简体   繁体   中英

Django custom decorator user_passes_test() can it obtain url parameters?

Can Django's user_passes_test() access view parameters?

For example I have view that receives an id to retrieve specific record:

def property(request, id):
    property = Property.objects.get(id=int(id))

The record has a field named user_id that contains the id for user that originally created record. I want users to be able to view only their own records otherwise be redirected.

I'd like to use a custom decorator which seems simple and clean.

For custom decorator is there some variation of something like this that will work?

@user_passes_test(request.user.id = Property.objects.get(id=int(id)).id, login_url='/index/')
def property(request, id):
    property = Property.objects.get(id=int(id))

I have tried creating separate test_func named user_is_property_owner to contain logic to compare current user to property record user_id

@user_passes_test(user_is_property_owner(id), login_url='/index/')
def property(request, id):
    property = Property.objects.get(id=int(id))


def user_is_property_owner(property_id):
    is_owner = False
    try:
        Property.objects.filter(id=property_id, user_id=user_id).exists()
        is_owner = True
    except Property.DoesNotExist:
        pass

But having trouble getting current user id and the property id from the request into the user_is_property_owner decorator function.


EDIT to add solution I was using. I did test inside each view test was required. It is simple. i thought using a decorator might be prettier and slightly more simple.

def property(request, id):

    # get object 
    property = Property.objects.get(id=int(id))

    # test if request user is not user id on property record    
    if request.user.id != property.user_id:
        # user is not same as property user id so redirect to index
        return redirect('index')

    # rest of the code if request user is user_id on property record 
    # eg it is ok to let user into view 

Typically, (using class based views), I'll handle this in the get_queryset method so it would be something like

class PropertyDetail(DetailView):
    def get_queryset(self):
        return self.request.user.property_set.all()

and that will give a 404 if the property isn't for the current user. You might prefer to use a project like django-guardian if you end up with more permission relationships than just Property .

If you take a look at UserPassesTestMixin you'll see that it processes the test_func before calling dispatch so you'll have to call self.get_object(request) yourself if you decide to go that route.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM