I am trying to show a button if the logged in user has the right permissions.
The code in the template:
{% if perms.django_apo_training.can_add %}
<a href="{% url 'training:trainee_add' %}">
<button type="button" class="btn btn-success">Add Trainee</button>
</a>
{% endif %}
I can print to the webpage to debug what the permissions the user has:
<p> {{ perms.django_apo_training }} </p>
It shows:
{'training.view_trainee', 'training.add_trainee', 'training.delete_trainee', 'training.change_trainee'}
but
perms.django_apo_training.can_add
always returns false, not sure what what I am missing?
Even double checked in the admin console:
(if I grant super user status to the the user in question, then the if statement works and returns true?)
Here is the model for the trainee stuff
# Create your models here.
class Trainee(models.Model):
objects = models.Manager()
first_name = models.CharField(max_length=200)
last_name = models.CharField(max_length = 200)
institution = models.CharField(max_length=200, blank=True)
contact_phone = models.CharField(max_length=50, blank=True)
contact_email = models.CharField(max_length=100, blank=True)
trained_date = models.DateField('date trained')
class Meta:
ordering = ['institution']
def __str__(self):
return "Trainee: " + str(self.first_name) + " " + str(self.last_name) + " " + str(self.institution)
Secondly... even once this works, how do I make sure that only those with that permission and logged in can get to (it is a lot more than an #login required decorator)
http://localhost:8000/training/add/
Lastly : I have also created model to extend the user model using the one-to-one model:
user = models.OneToOneField(User, on_delete=models.CASCADE)
Inside this APOUser model I call it, I have other fields that I would love to key off of for these permissions (specifically what is contained in the on_site_status), is there some set way or example/recipe of how one might do that?
(the full model is here)
class APOUser(models.Model):
objects = models.Manager()
user = models.OneToOneField(User, on_delete=models.CASCADE)
institution = models.ForeignKey("mainpage.Institution", on_delete=models.SET_NULL, null=True)
on_site_status = models.ForeignKey("mainpage.SiteStatus", on_delete=models.SET_NULL, null=True)
refer_to_as = models.TextField(max_length = 30, blank=True, null=True) #if the above is custom
room_preference = models.ForeignKey("housing.Room", on_delete=models.SET_NULL, null=True)
The standard permissions created follow the format <app_label>.view_<model_name>. So in the product app with the following models a total of 8 permissions will be automatically created.
class Category(models.Model):
...
class Product(models.Model):
...
# permissions for the Category model
'product.view_category'
'product.add_category'
'product.change_category'
'product.delete_category'
# permissions for the Product model
'product.view_product'
'product.add_product'
'product.change_product'
'product.delete_product'
In your example perms.django_apo_training.can_add will always return False because there is no permission can_add - unless you have a model called Add and have created a custom permission. The correct pattern should be perms.training.add_training.
It's also important to note that checking the permissions for a superuser will always return True even if the permission does not exist.
For protected views with permissions and custom user fields you can subclass UserPassesTestMixin.
from django.contrib.auth.mixins import UserPassesTestMixin
def permissions_check(user):
approved_profile_status = ['ADMIN', 'PURCHASER']
permission = 'training.add_trainee'
is_approved = user.profile.on_site_status in approved_profile_status
has_perm = user.has_perm(permission)
return is_approved or has_perm
class PermissionsMixin(UserPassesTestMixin):
def test_func(self):
return permissions_check(self.request.user)
class TraineeListView(PermissionsMixin, ListView):
...
Related
Hy,
I have a page that it can be accesed only if the user have a magiclink(made with django-sesame). After open that page using that maginlink i know witch user is, because when link is generated it incorporate the user information and include in that link.
So, the issue/question : in that page i want to show the name and departemnt for all users exept the users with the same department as the login user. I don't know how to make the query in view or forloop in template with that rule.
With another words: if the user logged in is from department "hr" i want to show in the template all the users for all department except those from "hr".
Please help me with a solution.
models.py
class Profil(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True)
username = models.CharField(max_length=200, blank=True, null=True)
nume = models.CharField(max_length=200, blank=True, null=True)
departament = models.CharField(max_length=200, blank=True, null=True)
view.py
#authenticate
def pagina_secreta(request):
utilizatori = User.objects.all()
context = {'utilizatori' : utilizatori}
return render(request, 'feedback/pagina_secreta.html', context)
template.html
{% for d in utilizatori %}
{{d.profil.nume}} {{d.profil.departament}} <br><br>
{% endfor %}
Thank you
You can filter out the department of that person with:
#authenticate
def pagina_secreta(request):
utilizatori = User.objects.exclude(
profil__departament=request.user.profil.departament
)
context = {'utilizatori' : utilizatori}
return render(request, 'feedback/pagina_secreta.html', context)
Sorry I am quite new to Django.
Ok in my project, every blogpost has their own group of members. You are only a member if your interest status is 'Accepted', and you get auto added to the member list. Every user can "submit interest" to any blogpost.
So now on the account page of the user, i want to query the blog posts that the user is a member to (aka interest status = "accepted")
I also want to query ALL the blog posts that the user has submitted interest to and that they are waiting to be accepted. to (aka interest status = "pending" and not a member yet)
In case you are confused, the members is a field of BlogPost model, and the status is a field in the InterestInvite model :).....
so in my template i want to have the title of ALL those blogpost that I am a member to and those blogpost where my interest is still pending status to be displayed. And when I click on the title, I will be directed to that particular blog post. Can anyone share how this querying can be done?
Problem i am facing is that i cannot use blog_post = get_object_or_404(BlogPost, slug=slug) in my views.py because they will say NameError because slug not defined. And I have no foreign key in my Account model to the BlogPost model. My foreign key is only in the BlogPost model.
Not sure if anyone has any solution to the querying and how I can display the info on the template. Thank you!
models.py
class Account(AbstractBaseUser):
email = models.EmailField(verbose_name="email", max_length=60, unique=True)
username = models.CharField(max_length=30, unique=True)
class BlogPost(models.Model):
title = models.CharField(max_length=50, null=False, blank=False, unique=True)
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
slug = models.SlugField(blank=True, unique=True)
members = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True, related_name="members")
class Interest(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
blog_post = models.ForeignKey(BlogPost, on_delete=models.CASCADE)
class InterestInvite(models.Model):
ACCEPT = "ACCEPT"
DECLINE = "DECLINE"
PENDING = "PENDING"
STATUS_CHOICES = [
(ACCEPT, "accept"),
(DECLINE, "decline"),
(PENDING, "pending"),
]
interest = models.OneToOneField(Interest, on_delete=models.CASCADE, related_name="interest_invite")
status = models.CharField(max_length=25, choices=STATUS_CHOICES, default=PENDING)
urls.py
path('<user_id>/', account_view, name="view"),
views.py
def account_view(request, *args, **kwargs):
context = {}
user_id = kwargs.get("user_id")
try:
account = Account.objects.get(pk=user_id)
context['account'] = account
except:
return HttpResponse("Something went wrong.")
if account:
context['id'] = account.id
context['username'] = account.username
context['email'] = account.email
context['profile_image'] = account.profile_image.url
context['hide_email'] = account.hide_email
context['biography'] = account.biography
blog_posts = BlogPost.objects.filter(author=account)
context['blog_posts'] = blog_posts
return render(request, "account/account.html", context)
account.html
{% if request.user in blog_post.members.all %}
{% endif %}
Django automatically sets an auto primary field in your BlogPost Model. So you can access it via:
blog_post = get_object_or_404(BlogPost, pk=pk)
And since you have a ForeignKey to the user you can query everything like:
user.blogpost_set.all() # get all blog posts of the user
user.interest_set.all() # get all interests of the user
user.interest_set.filter(
interest_invite__status="PENDING"
) # get all interest with status pending of the user
Or you can go through User Model like:
User.objects.filter(
blogpost__interest__interest_invite__status="PENDING"
).distinct() # get all users with interestinvite status PENDING
User.objects.filter(
blogpost=b, blogpost__interest__interest_invite__status="ACCEPTED"
).distinct() # get all users of a specific BlogPost with status ACCEPTED
I'm using Django 2.2 and PostgreSQL. I want to display the product information that the user has added to the detail page. I see the information in the 'StoreOtherInfo' model, but I don't see the information in the 'Product' model. How can I do that?
store/models.py
class StoreOtherInfo(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE,blank=True, null=True)
phone = models.CharField(max_length=11)
fax = models.CharField(max_length=11)
province = models.CharField(max_length=11)
district = models.CharField(max_length=11)
neighborhood = models.CharField(max_length=11)
def __str__(self):
return self.user.username
products/models.py
class Product(models.Model):
seller = models.ForeignKey(User, on_delete = models.CASCADE)
product_name = models.CharField(max_length = 50)
description = RichTextField()
added_date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.seller
store/views.py
from store.models import StoreOtherInfo
from products.models import Product
def neighbor_detail(request,username):
neighbor_detail = get_object_or_404(User,username = username)
neighbor_list = StoreOtherInfo.objects.all()
product_list = Product.objects.all()
return render(request, 'store/neighbor_detail.html', {'neighbor_detail':neighbor_detail, 'neighbor_list':neighbor_list, 'product_list':product_list})
templates/neighbor_detail.html
<strong><p>{{neighbor_detail.first_name}} {{neighbor_detail.last_name}}</p></strong>
<p>{{neighbor_detail.username}}</p>
<p>{{neighbor_detail.email}}</p>
<p>{{neighbor_detail.storeotherinfo.phone}}</p>
<p>{{neighbor_detail.storeotherinfo.fax}}</p>
<p>{{neighbor_detail.storeotherinfo.province}}</p>
<p>{{neighbor_detail.storeotherinfo.district}}</p>
<p>{{neighbor_detail.storeotherinfo.neighborhood}}</p>
<p>{{neighbor_detail.product.product_name}}</p>
<p>{{neighbor_detail.product.description}}</p>
<p>{{neighbor_detail.product.added_date}}</p>
according to your Product model:
seller = models.ForeignKey(User, on_delete = models.CASCADE)
the relation between User model and Product model is one-to-many. This means every User(in this case seller) can have multiple Products.
So when you try to access the Product objects of a User object as you did in you template: <p>{{neighbor_detail.product.product_name}}</p> you end up giving an attribution error because neighbor_detail.product is not a single object of Product class it's a collection.
replace your template code with this and i hope you realize whats happening.
<strong><p>{{neighbor_detail.first_name}} {{neighbor_detail.last_name}}</p></strong>
<p>{{neighbor_detail.username}}</p>
<p>{{neighbor_detail.email}}</p>
<p>{{neighbor_detail.storeotherinfo.phone}}</p>
<p>{{neighbor_detail.storeotherinfo.fax}}</p>
<p>{{neighbor_detail.storeotherinfo.province}}</p>
<p>{{neighbor_detail.storeotherinfo.district}}</p>
<p>{{neighbor_detail.storeotherinfo.neighborhood}}</p>
{% for product in neighbor_detail.product_set.all %}
{{product.product_name}}<br/>
{{product.description}}<br/>
{{product.added_date}}<br/>
{% endfor %}
note that product_set is the default name that django associate with products related to each user.
A User can have multiple Products, so you can't do neighbor_detail.product because product isn't defined on a User. You need to loop through the list of products with {% for product in neighbor_detail.product_set.all %} and then you can display the properties of each product.
Read [this] for more information about one-to-many relationships.
I am using Django-all auth for creating user accounts. I want to get First name, Last name, Email, and Password while signing up. But Sign up page Doesn't show First name and Last name. Sign up page showing only Email and Password. Could someone help me with that? Please let me know if you need any other information. Thanks!
Models.py
class CustomUser(AbstractUser):
# add additional fields in here
first_name = models.CharField(max_length=128, blank=True, null=True)
last_name = models.CharField(max_length=128, blank=True, null=True)
def __str__(self):
return self.email
Forms.py
class CustomUserCreationForm(UserCreationForm):
class Meta(UserCreationForm):
model = CustomUser
fields = ('email','first_name','last_name')
Signup.html
<h2>Sign Up</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Sign Up</button>
</form>
According to the Docs, you can override the the signup form. The default values are:
ACCOUNT_FORMS = {
'add_email': 'allauth.account.forms.AddEmailForm'
'change_password': 'allauth.account.forms.ChangePasswordForm'
'disconnect': 'allauth.socialaccount.forms.DisconnectForm'
'login': 'allauth.account.forms.LoginForm'
'reset_password': 'allauth.account.forms.ResetPasswordForm'
'reset_password_from_key': 'allauth.account.forms.ResetPasswordKeyForm'
'set_password': 'allauth.account.forms.SetPasswordForm'
'signup': 'allauth.account.forms.SignupForm'
'signup': 'allauth.socialaccount.forms.SignupForm'
}
It can be done by just adding ACCOUNT_FORMS = {'login': 'myapp.forms.CustomUserCreationForm'} to your settings.py.
Does this work for you?
There are some problems here. First of all, I'm not sure if you want to set blank=True [Django-doc], since that means that by default Django will hide these fields from editing. You might even not want to make these null=True [Django-doc] either, since that means the users are not required to fill these in. Your probably do not want that:
class CustomUser(AbstractUser):
first_name = models.CharField(max_length=128, null=True)
last_name = models.CharField(max_length=128, null=True)
def __str__(self):
return self.email
As for the form, you should not subclass Meta from the UserCreationForm itself. Perhaps you want to subclass it from the UserCreationForm.Meta:
class CustomUserCreationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = CustomUser
fields = ('email','first_name','last_name')
I would like to create a model method that will take the "user" (which is a CharField) for
a given review and then return the "quote" associated with that user that is defined as part
of UserProfile. I am trying to create both the method as well as the template. The things I've tried so far haven't seemed to work.
I know the best way to do this is probably make the "user" field within
Reviewbackup a ForeignKey to user, but I'd like to know how to be able to do it with a
method so I can learn.
models.py
class Reviewbackup(models.Model):
review = models.CharField('Review', max_length = 2000)
user = models.CharField('Username', max_length = 200)
rating = models.IntegerField(max_length=2, choices=RATING_OPTIONS)
product = models.ForeignKey(Productbackup)
def __unicode__(self):
return self.review
class UserProfile(models.Model):
user = models.OneToOneField(User)
quote = models.CharField('About', max_length = 200, null=True, blank=True)
website = models.URLField('Personal website/blog', null=True, blank=True)
facebook = models.URLField('Facebook profile page', max_length = 200, null=True, blank=True)
twitter = models.URLField('Twitter profile page', max_length = 200, null=True, blank=True)
youtube = models.URLField('YouTube channel page', max_length = 200, null=True, blank=True)
views.py
def view_reviews(request, product_name):
product = get_object_or_404(Productbackup, url_friendly=product_name)
product_id = product.id
#get reviews for the this product
reviews = Reviewbackup.objects.filter(product_id=product_id).order_by("-created_on")
return render_to_response('reserve/templates/view_reviews.html', {'reviews':reviews},
context_instance=RequestContext(request))
template
{% for review in reviews %}
{{review.user}}
<br>{{review.user.userprofile.quote}}
{% endfor %}
If condition of the problem says "not to use a ForeignKey for user, but use CharField for username" you may add the method to your Reviewbackup model like:
def get_user_quote(self):
return UserProfile.objects.get(user__username=self.user).quote
and use it in the template:
{{ review.get_user_quote }}
But you really should replace your user field to ForeignKey