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 %}
Related
I'm not sure how to ask this question but I'll give it a shot.
I am writing a Todo application and want to display each todo under its respective category in the template. For example
Display each category
{% for category in categories %}
<h2>{{ category.name }}</h2>
Now show each todo that falls under the above category
{% for todo in todos %}
<p>{{ todo.description }}</p>
{% endfor %}
{% endfor %}
How do I create a queryset that will give my this type of structure? Or is there are different way to achieve this?
If something is unclear or require more info let me know and I'll add it to the post
Any help is appreciated, thank you.
Models
class Category(models.Model):
name = models.CharField(max_length=20)
class Meta:
verbose_name_plural = "Categories"
def __str__(self):
return self.name
class Todo(models.Model):
# Priority choices
PRIORITY_CHOICES = (
("bg-danger", "High"),
("bg-info", "Normal"),
("bg-warning", "Low"),
)
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
description = models.CharField(max_length=255)
priority = models.CharField(max_length=200, choices=PRIORITY_CHOICES, null=True)
completed = models.BooleanField(default=False)
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
category = models.ManyToManyField(Category)
def __str__(self):
return self.description
View
def todo_listview(request):
template_name = "todos/listview.html"
context = {
"todos": get_users_todos(user=request.user),
"categories": Category.objects.all(),
}
return render(request, template_name, context)
You can prefetch the user's Todos, with:
from django.db.models import Prefetch
def todo_listview(request):
template_name = 'todos/listview.html'
context = {
'categories': Category.objects.prefetch_related(
Prefetch('todo_set', queryset=get_users_todos(user=request.user), to_attr='user_todos')
)
}
return render(request, template_name, context)
and then render this with:
Display each category
{% for category in categories %}
<h2>{{ category.name }}</h2>
{% for todo in category.user_todos %}
<p>{{ todo.description }}</p>
{% endfor %}
{% endfor %}
Since there is a many-to-many field between Category and Todo, it is possible that the same Todo will be printed multiple times: once per category.
Note: The documentation advises to
use the AUTH_USER_MODEL setting [Django-doc] over
get_user_model() [Django-doc].
This is safer, since if the authentication app is not yet loaded, the settings
can still specify the name of the model. Therefore it is better to write:
from django.conf import settings
class Todo(models.Model):
# …
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE
)
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:
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 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 %}
I am learning django. I have a simple model named customer. Here is my model:
class Year(models.Model):
year = models.CharField(max_length=255)
created_at = models.DateTimeField(auto_now=False, auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True, auto_now_add=False)
def __unicode__(self):
return self.year
def __str__(self):
return self.year
class Customer(models.Model):
name = models.CharField(max_length=255)
created_at = models.DateTimeField(auto_now=False, auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True, auto_now_add=False)
def __unicode__(self):
return self.name
def __str__(self):
return self.name
class Product(models.Model):
customer_name = models.ForeignKey(Customer, on_delete=models.CASCADE)
quantity = models.CharField(max_length=255)
year = models.ForeignKey(Year, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now=False, auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True, auto_now_add=False)
def __unicode__(self):
return self.score
def __str__(self):
return self.score
here is my view of customer:
from django.shortcuts import render, get_object_or_404, redirect
from .models import Customer, Product, Year
# Create your views here.
def home(request):
customer = Customer.objects.all
product = Product.objects.all
year = Year.objects.all().prefetch_related('product_set')
context = {'customers': customer,
'years': year,
'products': product
}
return render(request, 'customer.html', context)
Here is my customer.html
{% extends 'base.html' %}
{% block customer %}
<div class="container">
<h2>Players Table</h2>
<p>Customer with Product</p>
<table class="table">
<thead>
<tr>
<th>Year/Product</th>
{% for customer in cutomers %}
<th>{{ customer.name }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{# <tr>#}
{# <th>2011</th>#}
{# <th>633</th>#}
{# <th>424</th>#}
{# </tr>#}
{# <tr>#}
{# <th>2012</th>#}
{# <th>353</th>#}
{# <th>746</th>#}
{# </tr>#}
</tbody>
</table>
</div>
{% endblock customer %}
Now I have to generate table row which will contain year,customer and product througth customer per year.
So that How to fetch for every row that contains year, year based customer product data.
More simple,
Year has many customers and customer has one product thought year.
How to generate this. Please help me.
You don't need product or year in your context. You can use relation between your models to get this information:
views.py
from django.shortcuts import render, get_object_or_404, redirect
from .models import Customer, Product, Year
# Create your views here.
def home(request):
customer = Customer.objects.all
context = {'customers': customer}
return render(request, 'customer.html', context)
Now in your template you can get :
All product of a customer, with year by product
{% for customer in customers %}
Customer : {{ customer }}<br>
{% for product in customer.product_set.all %}
Product : {{ product }} / Year :{{ product.year }}<br>
{% endfor %}
{% endfor %}
But I don't like put too much logic in template.
I advise you to create the data of your table in your view, even better in your model. And then generate your html table with this data.
Summary of the function you will need:
You can replace all() by a filter()
products = customer.product_set.all() # give you all product of a customer
UPDATE AFTER COMMENTS:
Views.py
from django.shortcuts import render, get_object_or_404, redirect
from .models import Customer, Product, Year
# Create your views here.
def home(request):
customers = Customer.objects.all()
years = Year.objects.all().values_list('year', flat=True).asc() # List of year name
rows = []
for year in years:
row = [year] + [None] * len(customers) # Row with year in first column, and the rest init with same size of customers list
for idx, customer in enumerate(customers):
quantities = customer.product_set.filter(year__year=year).valu e_list('quantity', flat=True) # filter product by year. That can return multiple product !!!
row[idx + 1] = ' ,'.join(quantities) # create a string of quantities
rows.append(row) # Add new row in our rows list
context = {'customers': customer,
'rows': rows}
return render(request, 'customer.html', context)
template:
{% extends 'base.html' %}
{% block customer %}
<div class="container">
<h2>Players Table</h2>
<p>Customer with Product</p>
<table class="table">
<thead>
<tr>
<th>Year/Product</th>
{% for customer in customers %}
<th>{{ customer.name }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for row in rows %}
<tr>
{% for cell in row %}
<th>cell</th>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
I think that can help you to understand how to resolve your problem. I don't test this code, so maybe there is error. This is not perfect !