2

I am using django-voting as a voting application for two of my models. Those both models have fields "author".

How can I restrict a user from voting on a model that has this particular user set as it's author without modifying django-voting app?

Django middleware is the first thing that comes to my mind, but I don't understand it's "proces_view" function. If you think middleware is the right way could you please give an example of how to do it.

aleksandar
  • 31
  • 5

3 Answers3

4

Add this code anywhere in your settings.py:

from voting.managers import VoteManager

def check_user(func):
    def wrapper(self, obj, user, vote):
        if obj.user != user:
            return func(self, obj, user, vote)
        else:
            return None
            # or raise some exception
    return wrapper

VoteManager.record_vote = check_user(VoteManager.record_vote)

I didn't run this code, maybe it's incorrect, but I hope idea is clear

Carl Meyer
  • 122,012
  • 20
  • 106
  • 116
Mikhail Polykovskii
  • 2,333
  • 1
  • 16
  • 13
  • Yes, the idea is clear. And it is working. Just for future reference this code can't be put into settings.py. Put it in a file which is going to execute for certain, except settings.py. For example in models.py in your application. – aleksandar Jun 18 '09 at 10:51
  • I think this is the better way of doing it. This way the logic is also written for AJAX calls and it is in one place. – aleksandar Jun 18 '09 at 11:14
  • Be careful with this code if there are objects in your project which can be voted on that do not have a 'user' attribute. In that case you will need to either add a hasattr(obj, 'user') check or wrap everything in a try... except AttributeError. – Carl Meyer Jun 18 '09 at 23:38
  • this is far more elegant than what I had... maybe I ought to refactor :) – Jiaaro Jun 19 '09 at 14:36
2

Rather than a middleware hack, why not reroute requests to that particular URI through another view? Then you can performs whatever logic you like, and subsequently call the original view if appropriate.

ozan
  • 9,285
  • 4
  • 30
  • 27
  • This is so obvious I don't know why I didn't do it in a first place. Both answers are correct. Which to accept :)? – aleksandar Jun 18 '09 at 10:58
  • The disadvantage of this approach is that you'll be having to make extra database queries to fetch the object being voted on, which will then be repeated within django-voting's own view. So the other solution is more efficient and DRY, although this one doesn't require monkeypatching. – Carl Meyer Jun 18 '09 at 23:35
0

Another idea is to use the post_save signal

like so:

from django.db.models.signals import post_save
from voting.models import Vote

def check_user(sender, instance, **kwargs):
    if instance.user == instance.object.user:
        instance.delete()
        # do some other stuff to tell the user it didn't work

post_save.connect(check_user, sender=Vote)

The benefit of doing this vs overriding VoteManager.record_vote is that it's less tightly coupled to the voting module, and if they make changes it's less likely to break your code

edit: as in Glader's answer, you need to make sure that all the objects you're voting on have a 'user' attribute.

Jiaaro
  • 74,485
  • 42
  • 169
  • 190