3

I am trying to restrict instances of an object to be viewable only to users referenced by that object via a OneToOneField. I’m using the “user_passes_test” mixin on a DetailView to compare request.user to the user in the OnetoOne relationship. I got some help on django irc which led me to unsuccessfully try and implement get_object, but I’m still stuck (I'm new to Django & Python).

the Model:

class Event(models.Model):     
    client = models.OneToOneField(settings.AUTH_USER_MODEL)

the View:

class EventDetail(UserPassesTestMixin, DetailView):
    model = Event

    def test_func(self):
        if self.request.user == self.model.client:
            return True
        else:
            return False

User is being referenced in its own app, as User(AbstractUser)

brandondavid
  • 201
  • 1
  • 8

2 Answers2

2

If you are using DetailView then you can implement the get_queryset method in the view:

class EventDetail(DetailView):
    model = Event

    def get_queryset(self):
        queryset = super(DetalView, self).get_queryset()
        return queryset.filter(client=self.request.user)

This would make sure that the Event objects are restricted to the user as a client only.

I am not sure what URL are you using to access the Event and why there is just OneToOne relation between Event and User. But if it is a OneToOne relation then the queryset after this implementation will contain only one object. (which might or might not be the primary key using which you are accessing this event).

AKS
  • 18,983
  • 3
  • 43
  • 54
  • I'm using a OneToOne over a ForeignKey because there will always only ever be 1 event affiliated with 1 user. – brandondavid Jan 13 '17 at 14:52
  • (i didn't realize hitting enter saved the comment!) - url is calling Event object with pk, for example: http://localhost:8000/events/3/ - So I'm still unsure how to use the output of get_queryset in the test function. – brandondavid Jan 13 '17 at 14:58
  • I see now that your solution replaces the test function and it works perfectly! But I was using the test function so I could also provide an if / else condition that allows a user marked as "staff" to view the object as well. Using your solution how would one have the function check and allow if the user is staff? – brandondavid Jan 13 '17 at 15:12
  • Do you mean that either the user which is logged in and related to the event or any user who is a staff can see this object? – AKS Jan 13 '17 at 15:32
  • 1
    Yes exactly - your solution with the added if /else check for is_staff seems to be working fine (unless there is some reason why it's no good!) – brandondavid Jan 13 '17 at 15:52
  • It looks good. Just that it is not mentioned in the original post above. So there was no way for me to know that is also a requirement. – AKS Jan 13 '17 at 15:55
  • So for future reference, if we were to use "user_passes_test" function, how would we compare request.user to the user that is referenced via the "client" field on the Event model, (the way I was originally trying) ? – brandondavid Jan 13 '17 at 17:59
1

I finally got it, I think it took me writing it out to realize I could just put an if / else condition on the queryset like this:

def get_queryset(self):
    queryset = super(DetailView, self).get_queryset()
    if self.request.user.is_staff:
        return queryset
    else:
        return queryset.filter(client=self.request.user)

Thank you AKS!

brandondavid
  • 201
  • 1
  • 8