Display Count of Foreign key in Other table - django

i want to display number of Users in that company for all companies. I am using User in-built Model.
UserProfile Model
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
user_company = models.ForeignKey(Company, on_delete=models.CASCADE)
Company Model
class Company(models.Model):
company_name = models.CharField(max_length=20, unique=True)
company_description = models.CharField(max_length=100)
View to display Companies
class CompanyListView(LoginRequiredMixin, generic.TemplateView):
template_name = 'company/company.html'
def get_context_data(self, **kwargs):
context = super(CompanyListView, self).get_context_data(**kwargs)
context['companies'] = Company.objects.exclude(company_name='Google')
# Count of Users
return context
Display Count of Users for each company in single template

First I'll add a related_name attribute to the user_company field:
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
user_company = models.ForeignKey(Company, on_delete=models.CASCADE, related_name='user_profiles')
Then in your get_context_data method you just need to annotate() your queryset in the following way:
def get_context_data(self, **kwargs):
context = super(CompanyListView, self).get_context_data(**kwargs)
context['companies'] = Company.objects.exclude(
company_name='Google'
).annotate(
total_users=Count('user_profiles')
)
# Count of Users
return context
Note that you will need to import Count function as follows:
from django.db.models import Count
Then in your template you can access the count of users like follows:
{% for company in objects %}
{{ company.total_users }}
{% endfor %}

Related

Cannot assign "id": "Product.category" must be a "CategoryProduct" instance

i'm working on a django project and i got this error (Cannot assign "'11'": "Product.category" must be a "CategoryProduct" instance.) anyone here can help me please.
Model:
class Product(models.Model):
name = models.CharField("Nombre", max_length=150)
category = models.ForeignKey(CategoryProduct, on_delete=models.SET_NULL, null=True, related_name='category')
def __str__(self):
return self.name
View:
class ProductCreateView(CreateView):
model = Product
form_class = ProductForm
success_url = '/adminpanel/products/'
def post(self, request, *args, **kwargs):
form = self.get_form()
category = CategoryProduct.objects.get(id=request.POST['category'])
if form.is_valid():
product = form.save(commit=False)
product.category = category
product.save()
Form:
class ProductForm(forms.ModelForm):
name = forms.CharField(max_length=150, label="Nombre")
category = forms.ChoiceField(choices=[(obj.id, obj.name) for obj in CategoryProduct.objects.all()], label="Categoría")
class Meta:
model = Product
fields = ['name', 'category']
You can let Django's ModelForm do its work, this will create a ModelChoiceField [Django-doc], which is where the system gets stuck: it tries to assign the primary key to category, but that should be a ProductCategory object, so you can let Django handle this with:
class ProductForm(forms.ModelForm):
class Meta:
model = Product
fields = ['name', 'category']
If you want to specify a different label, you can use the verbose_name=… [Django-doc] from the model field, or specify this in the labels options [Django-doc] of the Meta of the ProductForm. So you can specify Categoria with:
class Product(models.Model):
name = models.CharField('Nombre', max_length=150)
category = models.ForeignKey(
CategoryProduct,
on_delete=models.SET_NULL,
null=True,
related_name='products',
verbose_name='Categoria'
)
def __str__(self):
return self.name
then the CreateView can just use its boilerplate logic:
class ProductCreateView(CreateView):
model = Product
form_class = ProductForm
success_url = '/adminpanel/products/'
Note: The related_name=… parameter [Django-doc]
is the name of the relation in reverse, so from the Category model to the Product
model in this case. Therefore it (often) makes not much sense to name it the
same as the forward relation. You thus might want to consider renaming the category relation to products.

Rendering a custom tag with a foreign key into templates issues

Hi this is the model I am working with
from django.db import models
from users.models import CustomUser
class Project(models.Model):
id = models.AutoField(primary_key=True)
user = models.ForeignKey(CustomUser, on_delete=models.PROTECT, editable=False)
name = models.CharField(max_length=20, editable=False)
total = models.DecimalField(max_digits=6, decimal_places=2, editable=False)
created = models.DateTimeField(auto_now_add=True, editable=False, null=False, blank=False)
def __str__(self):
return self.name
The class is populated by an HTML form using this view:
def homepage(request):
if request.method == "POST":
project = Project()
name = request.POST.get('name')
total = request.POST.get('total')
created = datetime.datetime.now()
user = request.user
project.user = user
project.name = name
project.total = total
project.created = created
project.save()
#return HttpResponse(reverse("homepage.views.homepage"))
return render(request, 'homepage.html')
else:
return render(request, 'homepage.html')
and so I have added a custom tag into my app which is a function
#register.filter
def monthlyTotal(user):
this_month = now().month
return Project.objects.filter(
created__month=this_month,
user=user
).aggregate(
sum_total=Sum('total')
)['sum_total']
I call the tag like this in template
<p>Total monthly sales = {{ user.username|monthlyTotal }}</p>
however I get an error saying Field ID expected a number but got 'grandmaster' which is the name of my test user who has multiple Project objects.. if I switch to user.id I get no error but it displays None which makes sense because when I look at my project section in admin the field user is populated by the username not the id so there would be no project where user=id
You need to use the user, not the username, so:
<p>Total monthly sales = {{ user|monthlyTotal }}</p>

How to properly use filter method with foreign key in django details view with multiple models

I have two model one model is being used for storing the blog posts and another model is being used for taking the ratings and comments. Below are two my models
# Models Code
class Products(models.Model):
name = models.CharField(max_length=50)
img = models.ImageField(upload_to='productImage')
CATEGORY = (
('Snacks','Snacks'),
('Juice','Juice'),
)
category = models.CharField(max_length=50, choices=CATEGORY)
description = models.TextField()
price = models.FloatField()
review = models.TextField()
# Rating Model
class Rating(models.Model):
product = models.ForeignKey(Products, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
stars = models.IntegerField(validators=[MinValueValidator(1),MaxValueValidator(5)])
comment = models.TextField()
#Views Code
class ProductListView(ListView):
model = Products
template_name = 'products.html'
context_object_name ='Products'
class ProductDetailView(DetailView):
model = Products
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super().get_context_data(**kwargs)
context['Rating'] = Rating.objects.filter(self.product_id) # How can i get the comments only for that specific product?
return context
In details-view how should I filter to fetch the comments for that specific product only ?
no need to write separate context for that in ProductDetailView, you can do it as follows in templates
{% for rate in object.rating_set.all %}
{{ rate.comment }}
{% endfor %}

Why can't I see user-added information with Django?

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.

Django: How to create a simple view to display current object of a model?

models.py:
class User(models.Model):
sex_choices=(('M', 'Male'), ('F', 'Female'))
category_choices=(('S', 'Student'),('T', 'Teacher'),('G', 'Guardian'))
qual_choices = (('a', 'Secondary'),('b', 'Senior Secondary'),('c', 'Undergraduate'),('d', 'Postgraduate'))
area_choices = (('CS', 'Computer Science'),('Maths', 'Mathematics'),('Phy', 'Physics'),('Chem','Chemistry'),('Bio', 'Biology'))
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
age = models.PositiveSmallIntegerField()
sex = models.CharField(max_length=1, choices=sex_choices)
contact = models.CharField(max_length=10)
email = models.EmailField(unique=True)
category = models.CharField(max_length=1, choices=category_choices)
qualification = models.CharField(max_length=1, choices=qual_choices)
area = models.CharField(max_length=5, choices=area_choices, null=True)
current_institution = models.CharField(max_length=30)
about = models.TextField(null=True)
password = models.CharField(max_length=20)
views.py:
class UserDetailView(DetailView):
model = User
def get_context_data(self, **kwargs):
context = super(UserDetailView, self).get_context_data(**kwargs)
return context
urls.py:
urlpatterns = [
url(r'^profile/(?P<slug>[-\w]+)/$', views.UserDetailView.as_view(), name='profile')]
templates/profile.html:
<font size="6" color="white">Name: {{object.first_name}} {{object.last_name}}</font>
I simply want to display the details of the current user i.e. display the fields of an object of class User. I can't figure out how to create a view for the same. Please help.
In your UserDetailView you need to call get_object() to get the particular object:
class UserDetailView(DetailView):
model = User
def get_context_data(self, **kwargs):
context = super(UserDetailView, self).get_context_data(**kwargs)
user = super(UserDetailView, self).get_object()
context['user'] = user
return context
Note
In your url you've used slug as the user/profile identifier. Unless I'm mistaken that's not a PK field in your model. Django's DetailView requires a value that is a representation of the PK of the model. E.g. If your model has field UUID as PK then the url should have a valid uuid in it so that Django can get the object. If slug has been used as a named group, (DetailView uses pk as the default), then you need to set the pk_url_kwarg in your view to slug i.e. pk_url_kwarg = 'slug'.
References:
Class-Based Generic Views