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
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)
I have a profile, and in this profile I want to display bookmarks for all messages (this is my IntegerField). In other words, how many people have bookmarked a particular author's posts.
models.py
class Post(models.Model):
slug = models.SlugField(unique=True)
title = models.CharField(max_length=255, db_index=True)
author = models.ForeignKey(
"users.CustomUser", on_delete=models.SET_NULL, null=True, db_index=True
)
bookmarkscount = models.IntegerField(null=True, blank=True, default=0)
class Profile(models.Model):
user = models.OneToOneField(get_user_model(), on_delete=models.CASCADE)
This is my try in template but it does not work
<p>Bookmark</p>
<p>{{posts.bookmarkscount}}</p>
But work only if I use "for"
{% for post in posts %}
<p>{{ post.bookmarkscount}}</p>
{% endfor %}
views.py
class ProfileDetailView(DetailView):
model = Profile
template_name = "users/profile/profile.html"
def get_context_data(self, **kwargs):
try:
context["posts"] = Post.objects.filter(
author=self.object.user.is_authenticated
)
except Post.DoesNotExist:
context["posts"] = None
posts is a QuerySet type, a representation of the query to be sent to the DB. More like a list on steroids rather than a single instance of Post. This is a crucial concept you need to understand before coding anything in Django. (Docs here)
In order to get a sum of all the bookmarkscount values from all posts of a user, you need to use aggregation. (Docs here)
from django.db.models import Sum
posts.aggregate(Sum('bookmarkscount'))
# returns i.e.: {'bookmarkscount': 234}
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):
...
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 not able to create the object review using the CreateView I am not sure what I am doing wrong. Below is a brief intro
Intro: My Order history page is where a user can see all the items that he/she has bought. In the Order history page I have a button that lets the buyer leave a review for the seller. Below is the button
<a href="{% url 'accounts:review' username=item.made_by pk=item.pk %}">
<button class="text-success">Leave Review</button>
</a>
from here I get the items item.id and the sellers username
{% for item in order.items_in_this_order.all %} <!--models below -->
url(r'^(?P<username>[-\w]+)/(?P<pk>\d+)/review/$', views.ReviewCreate.as_view(), name='review'),
{% endfor %}
The url expresses correctly in the address bar when I click on leave a review. It then displays a form. where I enter feedback, ratings, feedback_image, feedback_video the rest of the fields are supposed to be made in the views.py. After I fill the form and hit submit. The url is still correct. But I get the below error
IntegrityError at /accounts/nikhil/10/review/
NOT NULL constraint failed: accounts_review.item_id
Request Method: POST
Request URL: http://127.0.0.1:8000/accounts/nikhil/10/review/
Django Version: 1.11
Exception Type: IntegrityError
Exception Value:
NOT NULL constraint failed: accounts_review.item_id
Below are the views.py this is inside the accounts app
class ReviewCreate(LoginRequiredMixin, CreateView):
model = Review
form_class = ReviewCreateForm
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.review_from = self.request.user
print(self.object.review_from) #This prints
self.item = OrderItem.objects.get(pk=self.kwargs.get('pk'))
print(self.item) #This prints
self.object.review_for = User.objects.get(username=self.kwargs.get('username'))
print(self.object.review_for) #This prints
self.object.save()
return super().form_valid(form)
Below are the models.py for Review models
class Review (models.Model):
review_from = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, related_name='review_from')
review_for = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, related_name='review_for')
item = models.ForeignKey(OrderItem, related_name='items')
created = models.DateTimeField(auto_now_add=True)
feedback = models.TextField(blank=True, null=True)
feedback_image = models.ImageField(blank=True, null=True)
feedback_video = models.FileField(blank=True, null=True)
rating_choices = (
('1', 'One'), ('2', 'Two'), ('3', 'Three'), ('4', 'Four'), ('5', 'Five'),
('6', 'Six'), ('7', 'Seven'), ('8', 'Eight'), ('9', 'Nine'), ('10', 'Ten')
)
ratings = models.CharField(max_length=2, choices=rating_choices)
def __str__(self):
return 'Review from {} to {} for {}'.format(self.review_from, self.review_for, self.item.product)
Below are the models.py for OrderItem just in case
class OrderItem(models.Model):
product = models.CharField(max_length=350)
quantity = models.IntegerField()
price = models.DecimalField(max_digits=5, decimal_places=2, verbose_name='USD Price')
order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name='items_in_this_order')
date = models.DateField()
time_from = models.TimeField()
time_to = models.TimeField()
made_by = models.ForeignKey(User, on_delete=models.SET_NULL, blank=True, null=True, related_name='product_by')
image = models.ImageField()
order_date = models.DateField(auto_now_add=True)
picked = models.ManyToManyField(User, blank=True, related_name='item_picked')
Your form_valid method is quite strange. Among other things, you set the item to self.item, which isn't used anywhere and certainly isn't set on the created instance. Additionally, you create and save the object there directly, but then call the superclass method which will do it again without your additions.
Instead you should set all these attributes on form.instance, then let the super method do the saving:
def form_valid(self, form):
form.instance.review_from = self.request.user
form.instance.item = OrderItem.objects.get(pk=self.kwargs.get('pk'))
form.instance.review_for = User.objects.get(username=self.kwargs.get('username'))
return super().form_valid(form)