【问题标题】:Django-Tastypie: Omit one specific object to be serialized in ManyToManyDjango-Tastypie:在 ManyToMany 中省略一个要序列化的特定对象
【发布时间】:2013-11-07 22:34:46
【问题描述】:

我有一个简单的聊天应用程序。这是我的模型。

class Thread(models.Model):
    participants = models.ManyToManyField(User, related_name= 'threads_partof')
    last_message_time = models.DateTimeField(null=True, blank=True)

class Message(models.Model):
    message = models.CharField(max_length=500)
    sender = models.ForeignKey(User)
    thread = models.ForeignKey(Thread, related_name = 'thread_to_message')
    datetime = models.DateTimeField(auto_now_add=True)

def update_last_message_datetime(sender, instance, created, **kwargs):
    '''
    Update Thread's last_message field when
    a new message is sent.
    '''
    if not created:
        return

    Thread.objects.filter(id=instance.thread.id).update(last_message_time=instance.datetime)
post_save.connect(update_last_message_datetime, sender=Message)

我将 Django-Tastypie 用于我的 API。这是我的应用程序当前如何工作的示例,如果史蒂夫想向比尔发送消息,则会创建一个新的“消息”对象,其中史蒂夫是发件人。创建消息对象时,它还会创建一个“线程”对象。在这个线程中,参与者是 Steve 和 Bill。

我目前有一个 ThreadPreview 资源。

class ThreadPreview(ModelResource):
    participants = fields.ManyToManyField(BasicFoodieActivityResource, 'participants', full=True)
    class Meta:
        queryset = Thread.objects.all()
        resource_name = 'thread-preview'
        fields = ['id', 'participants', 'last_message_time']
        authorization = Authorization()
        authentication = BasicAuthentication()
        serializer = Serializer(formats=['json'])
        include_resource_uri = False
        always_return_data = True

    def dehydrate(self, bundle):
        bundle.data['last_message'] = bundle.obj.thread_to_message.latest('datetime').message
        return bundle

    def get_object_list(self, request):
        return super(ThreadPreview, self).get_object_list(request).filter(participants = request.user).order_by('-last_message_time')

当我对该资源执行 HTTP GET 请求时,我得到的返回如下:

{
    "meta": {
        "limit": 20,
        "next": null,
        "offset": 0,
        "previous": null,
        "total_count": 1
    },
    "objects": [{
        "id": "12",
        "last_message": "Hey, Bill, you're stealing from us!",
        "last_message_time": "2013-11-07T19:27:52",
        "participants": [{
            "user": {
                "first_name": "Steve",
                "id": "28",
                "last_name": "Jobs",
                "username": "steve"
            },
            "userPic": "http://apple.com/stevejobs.jpg"
        }, {
            "user": {
                "first_name": "Bill",
                "id": "6",
                "last_name": "Gates",
                "username": "bill"
            },
            "userPic": "http://microsoft.com/billgates.jpg"
        }],
    }]
}

我不想在数据返回时包含用户 Steve,因为他是 request.user。任何时候 request.user 访问这些数据,我都希望他们的用户数据不被序列化,因为我已经知道他们是谁。例如,这就是我想要的:

{
    "meta": {
        "limit": 20,
        "next": null,
        "offset": 0,
        "previous": null,
        "total_count": 1
    },
    "objects": [{
        "id": "12",
        "last_message": "Hey, Bill, you're stealing from us!",
        "last_message_time": "2013-11-07T19:27:52",
        "participants": [{
            "user": {
                "first_name": "Bill",
                "id": "6",
                "last_name": "Gates",
                "username": "bill"
            },
            "userPic": "http://microsoft.com/billgates.jpg"
        }],
    }]
}

我该如何做才能让 request.user 的数据始终被忽略?

【问题讨论】:

  • BasicFoodieActivityResource 长什么样子?

标签: python django json many-to-many tastypie


【解决方案1】:

本题案例(过滤相关资源)

您可以在ThreadPreview 上使用dehydrate_participants 挂钩(see docs on dehydration)来过滤参与者:

class ThreadPreview(ModelResource):

    ...

    def dehydrate_participants(self, bundle):
        if not hasattr(bundle.request, 'user'):
            return bundle.data['participants']

        new_participants = []
        for p in bundle.data['participants']:
            if p['user']['id'] != bundle.request.user.pk:
                new_participants.append(p)

        return new_participants

    ...

NB:我对p['user']['id'] != bundle.request.user.pk 的看法可能是错误的。 p['user']['id'] 可能已经是字符串了。

仅当此资源被序列化时(不相关时)

Resource 有一个钩子方法def get_object_list(self, request),可用于根据request.user 过滤列表。实现是战略性的

class BasicFoodieActivityResource(ModelResource):

    ...

    def get_object_list(self, request):
        qs = super(BasicFoodieActivityResource, self).get_object_list(request)

        if request and hasattr(request, 'user'):
            qs = qs.exclude(pk = request.user.pk)

        return qs

    ...

【讨论】:

  • 当我尝试这个时,它仍然返回相同的结果,我不认为来自 BasicFoodieActivityResource 的 get_object_list 是从 ThreadPreview 资源中调用的。就好像它没有看到get_object_list,它看到的只是来自BasicFoodieActivityResource 的类Meta
  • @RiegieGodwin,真的。尽管它可以(并且应该?)像列表一样处理相关对象,但它被完全忽略,相关对象被一一处理。我已经进一步调查并更新了我的答案。
猜你喜欢
  • 1970-01-01
  • 2011-11-23
  • 2016-01-04
  • 1970-01-01
  • 2014-02-05
  • 2010-09-14
  • 1970-01-01
  • 2011-01-24
相关资源
最近更新 更多