I have a simple Chat app. Here are my models.
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)
I use Django-Tastypie for my API. Here is an example of how my app currently works, if Steve wants to message Bill, a new "Message" object is created, where Steve is the sender. When a message object is created, it also creates a "Thread" object. In this thread, the participants are Steve & Bill.
I currently have a ThreadPreview resource.
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')
When I do a HTTP GET request on this resource, this is what I get back:
{
"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"
}],
}]
}
I would like to not include the user Steve when the data comes back since he is request.user. Anytime request.user accesses this data, I would like their user data to not be serialized since I already know who they are. For example, this is what I would like:
{
"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"
}],
}]
}
How can I about doing this so that request.user's data is always omitted?
You can use dehydrate_participants
hook (see docs on dehydration) on ThreadPreview
to filter participants:
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: I could be wrong about p['user']['id'] != bundle.request.user.pk
. p['user']['id']
is possibly string already.
Resource
has a hook method def get_object_list(self, request)
which could be used to filter list based on request.user
. Realisation is strateforward
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
...