Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django generic listview filter utilizing current user id

Tags:

jquery

django

I'm creating a rather simple web-app that'll allow me to rate various items (hopefully for use in generating some machine learning recommendations).

I've gotten the 5-star rating working by using Django-ratings, I'm having difficulties creating new views for my 'rated items', however. More specifically: I'm getting stuck on attempting to create an 'unrated item'-view and 'previously rated items' view.

The djangoratings works by creating the using the following model to administer votes:

class Vote(models.Model):
    content_type    = models.ForeignKey(ContentType, related_name="votes")
    object_id       = models.PositiveIntegerField()
    key             = models.CharField(max_length=32)
    score           = models.IntegerField()
    user            = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, related_name="votes")
    ip_address      = models.IPAddressField()
    cookie          = models.CharField(max_length=32, blank=True, null=True)
    date_added      = models.DateTimeField(default=now, editable=False)
    date_changed    = models.DateTimeField(default=now, editable=False)

class ContentType(models.Model):
    name = models.CharField(max_length=100)
    app_label = models.CharField(max_length=100)
    model = models.CharField(_('python model class name'), max_length=100)
    objects = ContentTypeManager()

The items I'm rating (models.py):

class Media(models.Model):
    id = models.AutoField(primary_key=True)
    url = models.CharField(unique=True, max_length=100)
    last_updated = models.DateTimeField(blank=True, null=True)
    ...
    rating = RatingField(range=5, can_change_vote=True, allow_delete=True)  # 5 possible rating values, 1-5
    class Meta:
        verbose_name_plural = "Media"

The following view works lovely by paginating and allowing me to rate each item:

class MediaListView(LoginRequiredMixin, ListView):
    queryset = Media.objects.all()
    template_name = 'myMedia/media_list.html'
    paginate_by = 10

However, I'm looking for a way to filter these items in two ways:

  • Retrieve only rated views, ordered by rating date (DESC)
  • Retrieve only unrated views, not (yet, maybe later!) ordered.

I figured I need to query the Vote table (filtering on the current user) to do so. As I don't have anything other than 'media' rated I can ignore the 'content_type' aspect of the generic-ratings table (which takes care of different types of models being rated).

I see request.user mentioned quite often in questions related to identifying the current user. I am, however, getting a 'NameError: name 'request' is not defined' error when trying to do so:

#views.py
class MediaListView(LoginRequiredMixin, ListView):
    queryset = Media.objects.all()
    template_name = 'myMedia/media_list.html'
    paginate_by = 10

class MediaListView_VotesByUser(LoginRequiredMixin, ListView):
    User = request.user
    voted_ids = Vote.objects.filter(user=User).values('object_id', flat=True) # Obtain the IDs for voted items.
    queryset = Media.objects.filter(id__in=voted_ids])
    paginate_by = 10

class MediaListView_Unrated(LoginRequiredMixin, ListView):
    User = request.user
    voted_ids = Vote.objects.filter(user=User).values('object_id', flat=True) # Obtain the IDs for voted items.
    queryset = Media.objects.exclude(id__in=voted_ids])
    paginate_by = 10


# urls.py
urlpatterns = patterns('',
    url(
        regex=r'^$',
        view=views.MediaListView.as_view(),
        name='media'),
    url(r'^rate/(?P<object_id>\d+)/(?P<score>\d+)/', AddRatingFromModel(), {
        'app_label': 'myMedia',
        'model': 'media',
        'field_name': 'rating',
    }),
    url(
        regex=r'^myVotes',
        view=views.MediaListView_VotesByUser.as_view(),
        name='UserVotedOn'),
    url(
        regex=r'^unrated',
        view=views.MediaListView_Unrated.as_view(),
        name='UnratedMedia')

)

Furthermore, I'm not quite sure I'm heading into the right direction. Do I need separate views for this or extend the existing view? Any help or tips on how I'd create these views would be greatly appreciated. I'm working with Django 1.7 (with MySQL), if that matters.

like image 634
MattV Avatar asked Jul 31 '26 04:07

MattV


1 Answers

Okay, so while Googling my question title I actually stumbled(!) upon an answer to the question, note that I did google this for quite a while! I guess it's time to go back through all of the documentation once more!

Django documentation: As you can see, it’s quite easy to add more logic to the queryset selection; if we wanted, we could use self.request.user to filter using the current user, or other more complex logic.

The following view returns all of my votes:

class MediaListView_VotesByUser(LoginRequiredMixin, ListView):
    def get_queryset(self):
        voted_ids = Vote.objects.filter(user=self.request.user).values_list('object_id', flat=True)
        return Media.objects.filter(id__in=voted_ids)
    paginate_by = 10

And the following returns the unrated ones.

class MediaListView_Unrated(LoginRequiredMixin, ListView):
    def get_queryset(self):
        voted_ids = Vote.objects.filter(user=self.request.user).values_list('object_id', flat=True)
        return Media.objects.exclude(id__in=voted_ids)
    paginate_by = 10

Performance and/or design tips on better implementing such a feature would still be appreciated!

like image 142
MattV Avatar answered Aug 01 '26 18:08

MattV



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!