views:

204

answers:

3

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.

+2  A: 

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
that's what I did ;)
Jiaaro
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
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
+4  A: 

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

Glader
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
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
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
this is far more elegant than what I had... maybe I ought to refactor :)
Jiaaro
A: 

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
Yes this is good example to.
aleksandar