开发者

Find the most recent rating for a user in a django queryset

I'm looking for a method to get the most recent rating for a specific Person for all Resources. Currently I'm using a query like Rating.objects.filter(Person = person).order_by('-timestamp') then passing that through a unique_everseen with a key on the resource and user attributes and then re-looking up with a Rating.objects.filter(id__in = uniquelist). Is there a more elegant way to do this with the django queryset functions? These are the relevant models.

class Person(models.Model):
    pass

cla开发者_StackOverflowss Resource(models.Model):
    pass

class Rating(models.Model):
    rating = models.IntegerField()
    timestamp = models.DateField()
    resource = models.ForeignKey('Resource')
    user = models.ForeignKey('Person')

I need to keep all of the old Ratings around since other functions need to be able to keep a history of how things are 'changing'.


I am not 100% clear on what you are looking for here, do you want to find the most recent rating by a user for all the resources they have rated? If you can provide detail on what unique_everseen actually does it would help to clarify what you are looking for.

You could rather look from a resource perspective:

resources = Resource.objects.filter(rating__user=person).order_by('-rating__timestamp')
resource_rating = [(resource, resource.rating_set.filter(person=person).get_latest('timestamp')) for resource in resources]

You might be able to use Aggregate functions to get to the most recent record per resource, or some clever use of the Q object to limit the SQL requests (my example may save you some requests, and be more elegant but it is not as simple as what you could produce with a raw SQL request). In raw SQL you would be using an inner SELECT or a well executed GROUP BY to get the most recent rating, so mimicking that would be ideal.

You could also create a post_save signal hook and an 'active' or 'current' boolean field on your Rating model, which would iterate other ratings matching user/resource and set their 'active' field to False. i.e. the post_save hook would mark all other ratings as inactive for a user/resource using something like:

if instance.active:
    for rating in Rating.objects.filter(user=instance.user,resource=instance.resource).exclude(id=instance.id):
        rating.active=False
        rating.save()

You could then do a simple query for:

Rating.objects.filter(user=person,active=True).order_by('-timestamp')

This would be the most economical of queries (even if you make the complicated group by/inner select in raw SQL you are doing a more complicated query than necessary). Using the boolean field also means you can provide 'step forward/step backwards'/'undo/redo' behavior for a user's ratings if that is relevant.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜