To determine the user's role in the project - python

In my django website I have pages like 'project_list' and 'project_detail'. Every project has members with different roles (developer, manager, e.t.c.). I want to show different buttons depending on the current user's role in the project in template. I need ideas how to realise it. Lets say something like that in template:
{% if request.user.role_in_the_current_project = 'manager' %}
SOW SOMETHING
{% endif %}
models.py
class Project(models.Model):
name = models.CharField(max_length=250,)
slug = models.SlugField(max_length=250, unique_for_date='publication_date',)
*Other fields*
def get_absolute_url(self):
return reverse('project:project_detail', args=[self.slug])
class Membership (models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
project = models.ForeignKey(Project, on_delete=models.CASCADE)
ROLE_CHOICES = (
('manager', 'Manager'),
('developer', 'Developer'),
('business_analyst', 'Business analyst'),
('system_analysts', 'System analysts'),
)
role = models.CharField(max_length=20, choices=ROLE_CHOICES,)
view.py
def project_detail(request, slug):
project = get_object_or_404(Project, slug=slug, status='public')
return render(request, 'project/project_detail.html', {'project': project,})
project_detail.html
{% block content %}
<h1>{{ project.name }}</h1>
<p>{{ project.description|linebreaks }}</p>
{%endblock %}
urls.py
urlpatterns = [
url(r'^project/(?P<slug>[-\w]+)/$', project_detail, name='project_detail'),
]

You can use the concept of choices inside a model field and then by using these you can make decisions inside your templates (or to your views) to show appropriate content.
Let me know if you need more info on this.
[EDIT]: So, what you want is to check each time the value of role. Right?
In your views.py write:
project = get_object_or_404(Project, slug=slug, status='public')
memberships = project.membership_set.all()
Then because one project can have many Membership records you should iterate over the memberships to get each time the role.
So, in your template:
{% for membership in memberships %}
{% if membership.role == 'Manager' %} Do stuff here {% endif %}
{% endfor %}
Note that .role will give you back the second value of the ROLE_CHOICES sub-tuple which is capitalized, while the first one is that will be shown in the user if you use the function get_role_display()

Well, after all I found solusion. In view I add:
is_manager = project.membership_set.filter(user=request.user, role='Manager').exists()
Then in template I add:
{% if is_manager %}
<button>Create</button>
{% endif %}

Related

How to restrict admin link/button in Django?

This is what I expect: if a user has position "1" (Admin) the nav menu in home.html must show "Admin" link to an admin page. If a user has position "2" (User) it won't show the link.
But when I run server this code generate as many Admin links as there are registered users. I want only one link for currently logged-in user to be shown. How can I do that? I know that there's something wrong with "for user in position", but how to fix it for currently logged-in user?
models.py
class Profile(models.Model):
positions = (
('1', 'Admin'),
('2', 'User'),
)
user = models.OneToOneField(User, on_delete=models.CASCADE, unique=True)
image = models.ImageField(default='default.jpg', upload_to='profile_pics')
position = models.CharField(max_length=50, default='Position', choices=positions)
views.py
def home(request):
user_position = Profile.objects.all()
return render(request, 'home.html', {
'position': user_position,
})
home.html
{% for user in position %}
{% if user.position == '1' %}
<a class="nav-link" aria-current="page" href="/admin">Admin</a>
{% endif %}
{% endfor %}
You can also use the is_superuser attribute in your template to achieve this:
{% if user.is_superuser %}
admin
{% endif %}
if you want to check it based on the username only you can use:
{% if user.username == "Admin" %}
admin
{% endif %}
Another thing you can do is to create 2 groups inside your admin panel; admins & users.
Then you have to create a custom template tag(has_group for example) to show the nav items based on these groups which is a better solution i think. Then you can use something like this in your template:
{% if user|has_group:"admin" %}
<p>User belongs to the admin group
{% else %}
<p>belongs to users group</p>
{% endif %}

Check if a record from one model exists in a list with records from another model in Django

I have two simple models defined in Django... one contains album names, and another one that links albums and users.
class Album(models.Model):
name = models.CharField(max_length=255)
class UserAlbum
category = models.ForeignKey(Album, on_delete=models.CASCADE)
author = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
In my view I get the list of all albums, and I check which albums the user owns:
albums = Album.objects.order_by('name')
my_albums = UserAlbum.objects.filter(user_id=request.user.id)
This all works well. However, I now need to display the list with albums online, and a little icon should appear if a user owns an album. I'm not sure how to do this. This is what I have:
<ul>
{% for info in albums %}
<li>{{ info.name %} {% if SOME_CONDITION %} <span class="owner"></span>{% endif %}</li>
{% endif %}
I am not sure how to formulate SOME_CONDITION. It should basically say: if this album id is also in the my_albums list. But how can I do this?
You don't really need the UserAlbum model, unless you want to attach extra fields to the m2m relation. Instead just use a ManyToManyField.
from django.contrib.auth import get_user_model
User = get_user_model()
class Album(models.Model):
name = models.CharField(max_length=255)
users = models.ManyToManyField(User)
Then you can test for membership in Album().users.all() in your template.
{% for album in albums %}
<li>{{ album.name }}
{% if request.user in album.users.all %}
<span class="owner"></span>
{% endif %}
</li>
{% endfor %}
If you have some plan with the UserAlbum model, you can use it as a intermediate model.
class Album(models.Model):
name = models.CharField(max_length=255)
users = models.ManyToManyField(User, through='UserAlbum')

Python - Check if user is in team or not

I have a model that stores teams and members. I want to check if a requested user is in this team or not. How do i do that?
Model
class TeamPlayer(models.Model):
team = models.ForeignKey(Team, related_name='players', on_delete=models.CASCADE)
player = models.OneToOneField(User, related_name='player', on_delete=models.CASCADE)
approved = models.BooleanField(default=False)
Template
{% if request.user in object.players.all %}
Leave
{% else %}
Join
{% endif %}
View is just simple DetailView.
If you want to do that in the template, just use the teamplayer_set like this:
{% if request.user in object.teamplayer_set.all %}
You have it 1-on-1, so it should be
players = TeamPlayer.object.all()
if request.user.player in players
# Do what you need to
or in template
{% if request.user.player in players %}
provided players is sent to the template
When it's one-on-one, it's always user.player to get related player and player.user for the related user.

How to show in template current users role in project?

Can someone say where I did mistake?
I have Project model. Every project has members. I have project_detail page where I want to show current user's username and his role in project. Right know in template it shows me only current user's username but not his role in project.
models.py:
class Project(models.Model):
members = models.ManyToManyField(User, through='Member', help_text=_('Members'))
ROLE_CHOICES = (
('manager', _('Manager')),
('developer', _('Developer')),
('business_analyst', _('Business Analyst')),
('system_analyst', _('System Analyst')),
)
class Member(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
project = models.ForeignKey(Project, on_delete=models.CASCADE)
role = models.CharField(max_length=20, choices=ROLE_CHOICES)
views.py:
def project_detail(request, project_code):
project = get_object_or_404(Project, pk=project_code, status='open')
context = {'project': project,}
return render(request, 'project/project_detail.html', context)
project_detail.html:
<span class="nav-link active navbar-text">
{{ user.get_username }}:
{% for member in project.member_set.all %}
{% if member.user == user.get_username %}
{{ member.get_role_display }}
{% endif %}
{% endfor %}
</span>
Why are you comparing the user against the result of get_username? That presumably returns a username string, but the user is, well, a user. This would work:
{% if member.user == user %}
{{ member.get_role_display }}
{% endif %}
But don't do this. It's very inefficient to loop over all project members and get the user for each one. Instead, do a single query in the view:
member = project.member_set.get(user=request.user)
context = {'project': project, 'role': member.get_role_display()}

Filter on many-to-one model

I want to be able assign users vehicle registrations, and when the user logs into the website their home page should have a list of vehicle regs they own.
However I cannot get the model class to filter on the foreign key.
views.py
#login_required
def home(request):
# This is the basic user landing Page
veh_list = Vehicle.objects.filter(UserProfile.user)
return render(request, 'portal/home.html', {"veh_list": veh_list})
model.py
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class UserProfile(models.Model):
# This line is required. Links UserProfile to a User model instance.
user = models.OneToOneField(User)
# The additional attributes we wish to include.
compName = models.CharField(max_length = 20)
milkco = models.IntegerField()
# Override the __unicode__() method to return out something meaningful!
def __unicode__(self):
return self.user.username
class Vehicle(models.Model):
vehid = models.CharField(max_length = 10)
company = models.ForeignKey(UserProfile, default = 1)
class Meta:
db_table = "vehicle"
def __unicode__(self):
return self.vehid
home.html
<!DOCTYPE html>
{% extends 'portal/base.html' %}
{% block title %}{{user.first_name }} {{ user.last_name }} Portal{% endblock %}
{% block content %}
<p>This is the home Page</p>
{% if user.is_authenticated %}
<h4>Optiload says... hello {{ user.first_name }} {{ user.last_name }}!</h4>
{% endif %}
{% for veh in veh_list %}
{{ veh}}
{% endfor %}
{% if user.is_authenticated %}
Logout<br/>
{% endif %}
{% endblock %}
Could someone help me with where I'm going wrong?
Thanks
Django offers a powerful and intuitive way to “follow” relationships in lookups, taking care of the SQL JOINs for you automatically, behind the scenes. To span a relationship, just use the field name of related fields across models, separated by double underscores, until you get to the field you want.
So your query should look like
veh_list = Vehicle.objects.filter(company__user=request.user)
Reference
You cannot make queries with unnamed arguments:
Vehicle.objects.filter(UserProfile.user)
In this case you want:
Vehicle.objects.filter(company=[your user])

Categories

Resources