How to get data from Django Many-Many relationship? - django

How to get all product for every order on Templates. Please help me
Model.py
class Order(models.Model):
customer_id= models.ForeignKey(Customers )
delivery_add_id= models.ForeignKey(DeliveryAddresses)
class OrderItem(models.Model):
order_id = models.ForeignKey(Order, related_name='orderId')
product_id = models.ForeignKey('Products', related_name='productId')
class Products(models.Model):
cat_id = models.ForeignKey('Categories')
name = models.CharField(max_length=200)
price = models.FloatField()
Templates
<tr>
<th>Product ordered</th>
<td>
<ul>
{% for prod in order.orderId.productId.product_set.all%}
<li>{{pro}}</li>
{% endfor %}
</ul>
{{order.orderId.productId.product_set.all}}
</td>
</tr>
https://i.stack.imgur.com/XJ3zG.png
Views.py
class productList(ListView):
model= Products
context_object_name = 'product_list'
def get_queryset(self):
return Products.objects.all()
class productDetail(DetailView):
context_object_name = 'product'
model = Products
queryset = Products.objects.all()
class orderList(ListView):
model = Order
context_object_name= 'order_list'
def get_queryset(self):
return Order.objects.all()
class orderDetail(DetailView):
context_object_name ='order'
model = Order
queryset= Order.objects.all()
This is the general relationship I have set up.I'm trying to do is, in a templates, i want to show all product for every order. Order-product : many to many relationship. Please help me

It should be like this:
{% for orderItem in order.orderId.all %}
{% for pro in orderItem.productId.all %}
<li>{{pro}}</li>
{% endfor %}
{% endfor %}

Related

Cannot see foreign key values in the template

This is my 2nd week learning Django. I'm trying to get comfortable with Django Template Language. I'm trying to make an Inventory app with 4 models. The views for them are class-based.
The templates for Ingredient and Menu work as expected. However, I'm struggling with trying to loop through values from the Purchase model which has a foreign key field 'menu_item'. The template is not showing anything from the for loop. I've referred numerous articles here to find most of them use function-based views. I've tried using {% for purchase in purchase_set %}, {% for purchase in purchase_set.all %}. I know the object to iterate over is a query-set. I cannot figure out what to do?
MODELS.PY
from django.db import models
# Create your models here.
class Ingredient(models.Model):
Pounds = 'lbs'
Ounces = 'oz'
Grams = 'gms'
Eggs = 'eggs'
Piece = 'piece'
Litre = 'litre'
unit_choices = [(Pounds, 'lbs'),
(Ounces, 'ounces'),
(Grams, 'grams'),
(Eggs, 'eggs'),
(Piece, 'piece'),
(Litre, 'litre')]
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=50)
unit_price = models.FloatField(default=0.0)
quantity = models.FloatField(default=0.0)
unit = models.CharField(max_length=10, choices=unit_choices)
class Meta:
ordering = ['id']
def __str__(self):
return self.name
class MenuItem(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=50)
price = models.FloatField(default=0.0)
class Meta:
ordering = ['id']
def __str__(self):
return self.title
class RecipeRequirement(models.Model):
menu_item = models.ForeignKey(MenuItem, on_delete=models.CASCADE)
ingredient = models.ForeignKey(Ingredient, on_delete=models.CASCADE)
quantity = models.FloatField(default=0.0)
def __str__(self):
return self.menu_item.title
class Purchase(models.Model):
menu_item = models.ForeignKey(MenuItem, on_delete=models.CASCADE)
timestamp = models.DateTimeField()
id = models.AutoField(primary_key=True)
class Meta:
ordering = ['id']
def __str__(self):
return self.menu_item.title
VIEWS.PY:
from django.shortcuts import render
from .models import Ingredient, MenuItem, RecipeRequirement, Purchase
from django.views.generic import ListView
def home(request):
return render(request, 'inventory/home.html')
class IngredientView(ListView):
model = Ingredient
template_name = 'inventory/ingredients.html'
class PurchaseView(ListView):
model = Purchase
template_name = 'inventory/purchases.html'
class MenuView(ListView):
model = MenuItem
template_name = 'inventory/menu.html'
PURCHASES.HTML
<h3>This is purchases page.</h3>
{% block content %}
<table>
{% for purchase in purchase_set.all %}
<tr>
<td>{{ purchase.title }}</td>
</tr>
{% endfor %}
</table>
{% endblock %}
The title field you are trying to show is in MenuItem model that is used as foreignkey in Purchase model with menu_item field. ListView class returns to context yours purchases in object_list key. So in Your purchases.html template:
<h3>This is purchases page.</h3>
{% block content %}
<table>
{% for purchase in object_list %}
<tr>
<td>{{ purchase.menu_item.title }}</td>
</tr>
{% endfor %}
</table>
{% endblock %}
PS. This `purchase_set' is referring to reverse relationship. So if you would want to show all purchases of MenuItem you would do:
{% for item in menuitems %}
<h1>{{ item }}</h1>
{% for purchase in item.purchase_set.all %}
<p>{{ purchase.timestamp }}</p>
{% endfor %}
{% endfor %}

Django listview filter related field lookup by date

I want to fetch only the elements of my VM model related to my Hypervisor model based on the current date, but when it finds them I fetch all the elements related to the parent model
My Models
class Hypervisor(models.Model):
name = models.CharField(max_length=200)
class VM(models.Model):
hypervisor = models.ForeignKey(Hypervisor, on_delete=models.CASCADE)
name = models.CharField(max_length=200)
cpu = models.CharField(max_length=200)
ram = models.CharField(max_length=200)
disk = models.CharField(max_length=200)
date = models.DateField(null=True)
My view
class vm(LoginRequiredMixin, ListView):
model = Hypervisor
template_name = 'vm_list_original.html'
ordering = ['name']
def get_queryset(self, *args, **kwargs):
return Hypervisor.objects.filter(vm__date=datetime.today().strftime('%Y-%m-%d')).distinct()
DDBB
sqlite> select * from budget_vm;
280|TC-CLINDE1-HARD001|4|8192|80|2022-09-01|254
281|TC-CLINDE1-HARD001|4|8192|80|2022-09-02|251
My Template
<tbody>
{% for hyper in object_list %}
<tr>
<td>{{ hyper.name }}</td>
<td>
{% for vm in hyper.vm_set.all %}
{{ vm.name }}
{% endfor %}
</td>
</tr>
{% endfor %}
</tbody>
The Result
You need to filter the related items as well with a Prefetch object [Django-doc], so:
from django.utils.timezone import now
class vm(LoginRequiredMixin, ListView):
model = Hypervisor
template_name = 'vm_list_original.html'
ordering = ['name']
def get_queryset(self, *args, **kwargs):
today = now().date()
return (
super()
.get_queryset(*args, **kwargs)
.filter(vm__date=today)
.prefetch_related(
Prefetch('vm_set', queryset=VM.objects.filter(date=today))
)
.distinct()
)

How to display sum of disctinct items in django?

I would like to display sum all the distinct categories of the products that belongs to the user. I searched on the web, but all the things that I tried doensn't work. You may find the models,view and template below. It doesn't give me anything at the html.
Model:
class Product(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE,related_name='products')
category = models.CharField(max_length=120)
brand = models.CharField(max_length=120)
product = models.CharField(max_length=120)
price = models.DecimalField(decimal_places=2,max_digits=100)
class Comp_Product(models.Model):
product = models.ForeignKey(Product,on_delete=models.CASCADE, related_name="comp_products")
competitor = models.URLField()
price = models.DecimalField(decimal_places=2,max_digits=100)
change = models.FloatField()
stock = models.BooleanField()
last_update = models.DateField(auto_now_add=True)
View:
class DashboardList(ListView):
template_name='dashboard_by_user.html'
def get_queryset(self):
return Product.objects.filter(user=self.request.user).annotate(count_category=Count('category',distinct=True)).aggregate(sum_category=Sum('count_category'))
template:
{% for product in product_list %}
{{product.sum_category}}
{%endfor%}
welcome to stackoverflow,
I'm assuming that you want to count the number of distinct categories for the given user. This can be done like this:
views.py:
from django.views.generic.list import ListView
from .models import Product
class DashboardList(ListView):
template_name = 'dashboard_by_user.html'
def get_queryset(self):
return Product.objects.filter(user=self.request.user)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
Products = context['object_list']
context['distinct_category_count'] = Products.values(
'category').distinct().count()
return context
dashboard_by_user.html:
<h1>Products</h1>
<ul>
{% for product in object_list %}
<li>{{ product.brand }} - {{ product.product }} - {{ product.category }}</li>
{% empty %}
<li>No Producs yet.</li>
{% endfor %}
</ul>
<p> Number of distinct categories: {{ distinct_category_count }} </p>
This should give you an output similar to this one:

Unable to display parent table with child table in a for loop with template tagging in Django

I want to display an unordered list of NBA teams from my teams table database. Within each team, I want an ordered list of players on that team. So basically I want to produce a list of all objects from my parent table and for each object from the parent table I want a list of all objects from the child table related the parent table. I understand that the problem is methods are not allowed in template tagging, so 'team.players_set.all()' would not be allowed. How else can I get the results that I want?
class Teams(models.Model):
name = models.CharField(max_length=20, unique=True)
num_of_plyrs = models.IntegerField()
def __str__(self):
return f"{self.name} have {self.num_of_plyrs} players."
class Meta:
verbose_name_plural = "Teams"
class Players(models.Model):
name = models.CharField(max_length=20)
team = models.ForeignKey(Teams, on_delete=models.CASCADE)
def __str__(self):
return f"{self.name} plays for {self.team}"
class Meta:
verbose_name_plural = 'Players'
__________________________________________________________________________________
def teams(request):
teams = Teams.objects.all()
context = {'teams': teams}
return render(request, 'one_app/teams.html', context)
__________________________________________________________________________________
<h3>NBA Teams</h3>
<ul>
{% for team in teams %}
<li>
<p>Team: {{ team.name }}</p>
<p>Number of players: {{ team.num_of_plyrs }}</p>
<ol>
{% for plyr in team.players_set.all() %}
<li>{{ plyr.name }}</li>
{% endfor %}
</ol>
</li>
{% empty %}
<li>There are no teams listed.</li>
{% endfor %}
</ul>
{% for player in team.players_set.all %}
table name should be singular
you can set related_name and use players instead players_set
team = models.ForeignKey(Teams, related_name='players',on_delete=models.CASCADE)
make use of select_related
One way to achieve this is:
class PlayersView(ListView):
model = Team
...
def get_queryset(self, **kwargs):
teams = []
queryset = super().get_queryset()
for team in queryset:
players = team.player_set.all()
for player in players:
teams.append([team, (player.name, ...)]
return teams
And in your template:
{% for team, players in teams %}
...
{% for player in players %}
...
{% endfor %}
{% endfor %}
ALTERNATIVE
If you know this is something you might be using a lot and to simplify your view, you can also create a manager:
from your_app.managers import TeamManager
class Team(models.Model):
...
objects = Manager()
team_manager = managers.TeamManager.as_manager()
...
In a file manager.py or anything you want:
from django.db.models import QuerySet
class TeamManager(QuerySet):
def table_queryset(self):
queryset = self.all()
teams = []
for team in queryset:
players = team.player_set.all()
for player in players:
teams.append([team, (player.name, ...)]
return teams
And then in your view:
class PlayersView(ListView):
model = Team
queryset = Team.player_manager.table_queryset()

How to create a dynamic filter based on the primary key of ForeignKey in ListView?

I am relatively new to Django but the main problem I am facing right now is to create a ListView that will display uploaded documents based on the primary key of my ForeignKey.
I have tried several methods of trying to create the filter and read the online documentation on class-based view but it does not seem to have relevant information on how to use the primary key of my ForeignKey in my filter.
These are my models:
class Post(models.Model):
title = models.CharField(max_length=100)
image = models.ImageField(default = 'default0.jpg',
upload_to='course_image/')
description = models.TextField()
price = models.DecimalField(decimal_places=2, max_digits=6)
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
rating = models.IntegerField(default = 0)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post-detail', kwargs={'pk' : self.pk})
class Lesson(models.Model):
title = models.CharField(max_length=100)
file = models.FileField(upload_to="lesson/pdf")
date_posted = models.DateTimeField(default=timezone.now)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('lesson_upload', kwargs={'pk': self.pk})
Here is my ListView with the filter that is not working:
class LessonListView(ListView):
model = Lesson
template_name = 'store/uploaded_lesson.html'
context_object_name = 'lesson'
# def get_queryset(self):
# return Lesson.objects.filter(Post__pk=self.Post.pk)
def get_queryset(self):
self.post__pk = get_object_or_404(post__pk,
name=self.kwargs['post__pk'])
return Lesson.objects.filter(post__pk=self.post__pk)
Here is my urls.py:
path('post/<int:pk>/lesson_uploaded/', LessonListView.as_view(), name='lesson_uploaded'),
Here is my html:
{% extends "store/base.html" %}
{% block content %}
<div id="main">
<table class="table mb-0">
<thead>
<tr>
<th>Title</th>
<th>Author</th>
<th>Download</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
{% for lesson in lesson %}
<tr>
<td>
{% if lesson.file %}
<img src="{{ lesson.file.url }}" style="width:100px;">
{% else %}
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}
You can try like this:
In urls, add post_id :
path('lessons/<int:post_id>/', LessonListView.as_view()),
Then update the View to get the post_id in get_queryset method:
class LessonListView(ListView):
model = Lesson
template_name = 'store/uploaded_lesson.html'
context_object_name = 'lesson'
def get_queryset(self):
return Lesson.objects.filter(post_id=self.kwargs.get('post_id'))
Also, please don't name list and item of that list in a for loop same, so update it to:
{% for l in lesson %}. // or anything other than lesson
<tr>
<td>
{% if l.file %}