PCiah
PCiah

Reputation: 27

Django partially restricting contents according to different user group

Just started Django last week and I am facing this problem regarding two types of users (normal and VIP) and how to restrict normal users from viewing VIP contents.

I am using Django with MySQL. My site does not requires user to signup but instead, I will be giving them username/password. I manually creates user via Django admin and group them according to VIP or normal. I will be uploading contents (again via admin) and I have a Boolean check-box that determine whether it is a VIP content or not.

What I done so far:

  1. User must login to view the contents
  2. Upon logging in, VIPs can see VIP contents and normal users will not be able to see VIP contents.

FAQ.html

{% extends 'base.html' %}
...skipping...
{% for faqs in fq reversed %}
<a href="{% url 'faq_topics' faqs.pk %}">{{ faqs.name }}</a>
{{ endfor }}

faq_topics.html

<h2>{{ faqs.name }}</h2>
<h6 style="padding: 20px 20px 20px 20px">{{ faqs.description|linebreaksbr }}</h6>

urls.py

urlpatterns = [
path('faq/', views.faq, name='faq'),
url(r'^faq/(?P<pk>\d+)/$', views.faq_topics, name='faq_topics'),]

views.py

def is_user(user):
    return user.groups.filter(name='User').exists()

def is_vip(user):
    return user.groups.filter(name='VIP').exists()

@login_required
@user_passes_test(is_user)
def faq(request):
    fq = FAQ.objects.filter(vip_only=False)
    return render(request, 'faq.html', {'fq':fq})

models.py

class FAQ(models.Model):

    name = models.CharField(max_length=30, unique=True)
    description = models.CharField(max_length=300)
    vip_only = models.BooleanField(default=False)

Error Case

3 FAQ entries are made, the first one is classified as VIP only.

When a normal user log in into FAQ section, he/she will only see 2 contents

Welcome to FAQ section

  1. 127.0.0.1:8000/faq/3/

  2. 127.0.0.1:8000/faq/2/

However, the user can easily guess that faq/1/ exists and when they actually tries, they can have access to vip contents too.

I have been searching the web for the past 2 days, I learn how to user @user_passes_test to restrict users and objects.filter(vip_only=False) to restrict contents.

Additionally, I wish to have my views.py controlling the contents for both kind of user but I have yet to implement that yet. Will be very grateful if someone can teach me how to implement "2 views in one templates".

I have read from,

show different content based on logged in user django

django - 2 views in one template

My solution for splitting user

    @login_required
    def faq(request):
        '''user is separate using groups'''
        if request.user.is_superuser or request.user.groups.filter(name='VIP').exists():
            fq = FAQ.objects.all()
        else:
            fq = FAQ.objects.filter(vip_only=False)
        return render(request, 'faq.html', {'fq':fq})

Upvotes: 0

Views: 468

Answers (1)

ger.s.brett
ger.s.brett

Reputation: 3308

You should do something like this

def faq(request):
    if request.user.is_superuser:
        fq = FAQ.objects.all()
    else:
        fq = FAQ.objects.filter(vip_only=False)
    return render(request, 'faq.html', {'fq':fq})

You can also use similar approach for doing things in the template:

{% if user.is_superuser %}
  #...show what you only want to show the superuser
{% endif %}

And in your method for the single faq, do something like:

def faq_topics(request, pk):
    faq_item=FAQ.objects.get(id=pk)
    if not request.user.is_superuser and not request.user.groups.filter(name='VIP').exists(): 
        if fqa_item.vip_only:
            return render(request, 'path_to_access_error_template', {'fq':faq_nr})
    return render(request, 'faq_item.html', {'fq':faq_nr})

Upvotes: 1

Related Questions