How to restrict access to pages based on user type

2020-07-23 06:28发布

I have a basic question which can be useful for new Django developers.

I created my own UserProfile in Django. This UserProfile has a specific field called 'type'. This field can have two values (until now maybe more in the future) : Male - M / Female - F :

from django.contrib.auth.models import User

GENDER = (
    (M, 'Male'),
    (F, 'Female'),
)

class UserProfile(models.Model):
    user = models.OneToOneField(User)
    type = models.CharField( max_length=2,
                             choices=GENDER,
                             default='F')

Basically, I wanted to allow access to restrict access or to adapt page content depending on user Type. Until now, I used a really basic and beginner approach which is to test user type in a view and then process the page:

def OnePage(request):
    if request.user.type == 'M':
        ....
    else if request.user.type =='F':
        ....

Then I also need to adapt the template rendered depending on user type: a male user will not have the same profile page that a Female User.

I am sure there are better ways to do this but as a Django beginner I am quite lost with all of Django possibilities. So if you have any best practices to implement this please tell me (obviously I would like a DRY code I could use on every view!)

Thank you for your help.

4条回答
▲ chillily
2楼-- · 2020-07-23 07:00

To add extra data to User see

Storing additional information about users

Then add the profile to your context and you can use {{profile}} variable in your template

{% if profile.type == "F" %}
    blah, blah
{% else %}
    blah, blah
{% endif %}
查看更多
Emotional °昔
3楼-- · 2020-07-23 07:20

One solution could be to change the base template name depending on the user type:

@render_to('some_template.html')
def some_view(request):
    base_template = 'base_%s.html' % request.user.profile.type
    # …
    return {
        'base_template': base_template,
    }

And in your template :

{% extends base_template %}
{% block some-block %}
…
{% endblock %}

If you need to do this on every view, you could use a middleware to set this value.

查看更多
Ridiculous、
4楼-- · 2020-07-23 07:22

To restrict access, use the user passes test decorator:

from django.contrib.auth.decorators import user_passes_test

male_only = lamda u: u.type == 'M'
female_only = lamda u: u.type == 'F'


@user_passes_test(male_only)
def myfunc(request):
   pass

@user_passes_test(female_only)
def myotherfunc(request):
   pass
查看更多
来,给爷笑一个
5楼-- · 2020-07-23 07:25

Depending on what you want to do, if you need to use very different html for different genders, you can try this approach:

def gender_filter(func):
    def _view(request,*args,**kwargs):
        res=func(request,*args,**kwargs)
        if request.user.get_profile().type=='F':
            res.template_name='template_f.html'
            res.context_data['gender']='female'
        elif request.user.get_profile().type=='M':
            res.template_name='template_m.html'
            res.context_data['gender']='male'
        return res.render()
    return _view

@gender_filter
def my_view(request):
    t=TemplateResponse(request,'template_f.html',{...})
    return t

So instead of returning Http resonpse in views, you can make them return TemplateResponse objects and use decorators to change templates, add in general context, and them convert them to HttpResponse.

Or something like a permission check:

def gender_only(gender):
    def _dec(func):
        def _view(request,*args,**kwargs):
            if request.user.get_profile().type==gender
                return func.render(request,*args,**kwargs)
            else:
                raise Exception("You do not have the right gender")
        return _view
    return _dec

@gender_only('F')
def my_view(request):
    ...
    return render_to_response('template.html',{...},context_instance=RequestContext(request))
查看更多
登录 后发表回答