I want to display a Company header and the products below its related company. I am new to django i do not understand this fully.
My models.py
class Company(models.Model):
name = models.CharField(max_length=250)
def __str__(self):
return str(self.name)
class Products(models.Model):
company = models.ForeignKey(Company, on_delete=models.CASCADE, related_name="display")
engine = models.CharField(max_length=250, blank=True)
cyl = models.CharField(max_length=250, blank=True)
bore = models.CharField(max_length=250, blank=True)
def __str__(self):
return str(self.engine) + " (ref:" + str(self.ref) + ")"
My views.py:
def Companies(request):
context = {
'categories': Company.objects.all()
}
return render(request, 'product_list.html', context)
My html:
{% for category in categories %}
<h2>{{ category.name }}</h2>
{% for item in category.item_set.all %}
{{ item_engine }}
{% endfor %}
{% endfor %}
only make changes to your HTML file as below and make sure the class name is Product if you are using product_set.all:
{% for category in categories %}
<h2>{{ category.name }}</h2>
{% for item in category.product_set.all %}
{{ item.engine }}
{% endfor %}
{% endfor %}
If still not working then try to remove : + " (ref:" + str(self.ref) + ")"
and also, I think by mistake you have displayed your models.py wrongly. The str functions should be inside the classes like below:
class Company(models.Model):
name = models.CharField(max_length=250)
def __str__(self):
return str(self.name)
class Product(models.Model):
company = models.ForeignKey(Company, on_delete=models.CASCADE,
related_name="display")
engine = models.CharField(max_length=250, blank=True)
cyl = models.CharField(max_length=250, blank=True)
bore = models.CharField(max_length=250, blank=True)
def __str__(self):
return str(self.engine)
Related
I want to count how many Product variations available in each Market. For now I'm only able to count Product variations for each Distributor. I'm thinking about using 'add' built-in template tag to sum Product variation in each Distributor to solve this problem, but don't know how to implement this in template for loop. Or is there any better solution? I'm open for suggestions.
My 5 related models in Django:
class Market(models.Model, RecordStatus):
name = models.CharField(max_length=100)
class Country(models.Model):
market = models.ForeignKey(Market, on_delete=models.SET_NULL, null=True, blank=True)
name = models.CharField(max_length=100)
class Distributor(models.Model, RecordStatus):
headquarter = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True)
country = models.ForeignKey(Country, on_delete=models.SET_NULL, null=True, blank=True)
name = models.CharField(max_length=100, null=True, blank=True)
class Product(models.Model, RecordStatus):
video = models.URLField(verbose_name='Video URL', max_length=250, null=True, blank=True)
class ProductStock(models.Model):
distributor = models.ForeignKey(Distributor, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
stock = models.PositiveIntegerField(null=True, blank=True)
My views.py:
def market_list_view(request):
markets = Market.objects.all()
context = {
'market_list': markets,
}
return render(request, 'product_visualizers/market_list.html', context)
My current attempt on market_list.html template:
{% for market in market_list %}
<h3>{{market.name}}</h3>
<p>{% for country in market.country_set.all %}
{% for distributor in country.distributor_set.all %}
{{ distributor.productstock_set.all|length }} # should I write |add besides |length to sum the numbers?
{% endfor %}
{% endfor %}</p>
{% endfor %}
What should I code in the nested for inside the template?
You can use:
class Market(models.Model, RecordStatus):
name = models.CharField(max_length=100)
def get_product_variations(self):
return Product.objects.filter(productstock__distributor__country__market=self).count()
and for your template:
{% for market in market_list %}
<h3>{{market.name}}</h3>
<p>Product variations: {{ market.get_product_variations }}</p>
{% endfor %}
this is my models.py
class Category(models.Model):
name = models.CharField(max_length=50)
ordering_num = models.IntegerField(default=0)
class Meta:
ordering = ['ordering_num']
def __str__(self):
return self.name
class SubCategory(models.Model):
category = models.ForeignKey('Category', on_delete=models.CASCADE)
name = models.CharField(max_length=50)
ordering_num = models.IntegerField(default=0)
class Meta:
ordering = ['ordering_num']
def __str__(self):
return self.name
class ProductBasicModels(models.Model):
whose = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
category = models.ForeignKey(SubCategory, on_delete=models.CASCADE)
name = models.CharField(max_length=50)
standard = models.CharField(max_length=50)
maker = models.CharField(max_length=50, blank=True)
outbox = models.CharField(max_length=50, blank=True)
extra = models.CharField(max_length=100, blank=True)
orderto = models.ForeignKey(OrderCompany, null=True, blank=True, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['name']
def __str__(self):
return self.name
views.py
# login_required
def product_list(request):
categories = Category.objects.all()
context = {'categories': categories}
return render(request, 'medicalapp_1/products_h.html', context)
products_h.html
(simple structure...)
...
{% for category in categories %}
{{ category.name }}
{% for sub_category in category.subcategory_set.all %}
{{ sub_category.name }}
{% for list in sub_category.productbasicmodels_set.all %}
{% if list.whose.id is request.user.id %}
{{ list.name }}
{% endif %}
{% endfor %}
{% endfor %}
{% endfor %}
....
according to my code.. all of category and subcategory and products being displayed. But I want to make them display only products models has data.
like this..
category1
subcategory1
product1
product2
product3
category4
subcategory1
product4
product5
subcategory3
product6
(category2,3) and (subcategory2 of category4) are not displayed because they don't have product..
How can I make filter in the view to work like it?
Make use of regroup tag. No need to fetch all categories in the product_list() method. Instead fetch all products (as the name intents)
- with prefetch_related to its foreign key(s), to optimise the query. Then regroup the queryset. That's all!
def product_list(request):
products = ProductBasicModels.objects.all().prefetch_related('category','category__category')
context = {'products': products}
return render(request, 'medicalapp_1/products_h.html', context)
Then, in the template,
{% regroup products by category.category as cats %}
{% for cat in cats %}
<br>{{cat.grouper}}
{% regroup cat.list by category as subcats %}
{% for subcat in subcats %}
<br>{{subcat.grouper}}
{% for product in subcat.list %}
<br>{{product}}
{% endfor %}
{% endfor %}
{% endfor %}
PS :Two separate (& similar) models for category & sub-category is redundant and you shouldn't be using it. You may just use a single model with ForeignKey to 'self'
i currently try to display who many posts a category has.
Therefor i created the Post Model and the Category Model (See below):
models.py
# Categorys of Post Model
class Category(models.Model):
title = models.CharField(max_length=255, verbose_name="Title")
class Meta:
verbose_name = "Category"
verbose_name_plural = "Categories"
ordering = ['title']
def __str__(self):
return self.title
#Post Model
class Post(models.Model):
author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
title = models.CharField(max_length=200)
text = models.TextField(max_length=10000)
category = models.ForeignKey(Category, verbose_name="Category", on_delete=models.CASCADE, null=True)
tag = models.CharField(max_length=50, blank=True)
postattachment = fields.FileField(upload_to='postattachment/%Y/%m/%d/', blank=True, null=True)
postcover = fields.ImageField(upload_to='postcover/%Y/%m/%d/', blank=True, null=True, dependencies=[
FileDependency(processor=ImageProcessor(
format='JPEG', scale={'max_width': 300, 'max_height': 300}))
])
created_date = models.DateTimeField(default=timezone.now)
published_date = models.DateTimeField(blank=True, null=True)
def publish(self):
self.published_date = timezone.now()
self.save()
def __str__(self):
return self.title
category_list.html
{% extends 'quickblog/base.html' %}
{% block content %}
{% for categories in categories %}
<div>
<h1><u>{{ categories.title }} {{ $NumCountGetHere }}</u></h1>
</div>
{% endfor %}
{% endblock %}
Now i have no idea how to get the related objects counted...?
You can use something like this:
{% for cat in categories %}
<div>
<h1><u>{{ cat.title }} {{ cat.post_set.count }}</u></h1>
</div>
{% endfor %}
The model Post has a Foreignkey field to the model Category. You can access the related Post instances from a given Category instance using the manager category_instance.post_set. Read about it in the docs.
Finally, we use the method .count() on this manager to get the number of related posts for that given category. This way the code ends up looking like {{ cat.post_set.count }}.
This may be a simple answer but after days of searching I cannot seem to figure out the correct way to achieve this.
I have a template where I want to show all the questions that are related to an assessment that has been assigned to a user. I thought that I could use the results from:
ResponseDetails = AssessmentResponse.objects.prefetch_related('assessment').filter(id=response_id)
by looking into the object and grabbing the assessment_id which I could then pass into the next query-set as a filter but I couldn't get that to work.
Problem: Because the view doesn't filter based on the assessment_id found in the AssessmentResponse model, it gives me every question in the AssessmentQuestion model.
An answer would allow me to actually have a good nights sleep trying to figure it out.
Views
def UpdateAssessmentResponse(request, response_id):
ResponseDetails = AssessmentResponse.objects.prefetch_related('assessment').filter(id=response_id)
QuestionList = AssessmentQuestion.objects.all()
ChoiceList = AssessmentQuestionChoice.objects.all()
context = {
"ResponseDetails":ResponseDetails,
"QuestionList":QuestionList,
"ChoiceList": ChoiceList,
#"ID" : ID,
}
return render(request, "assessment/assessment_response_update.html", context)
Template
{% if QuestionList and ResponseDetails%}
{% csrf_token %}
{% for question in QuestionList %}
<p> {{ question.question_text }} </p>
{% for choice in ChoiceList %}
{% if choice.question_id == question.pk %}
<fieldset id="group1">
<div class="custom-control custom-radio custom-control-inline">
<input type="radio" class="custom-control-input" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" />
<label class="custom-control-label" for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label>
</div>
<fieldset id="group1">
{% endif %}
{% endfor %}
{% endfor %}
<div class="card-footer">
<input type="submit" value="Submit" class="btn btn-primary" />
</div>
{% else %}
<p>There are currently no questions for this assessment.</p>
{% endif %}
Models:
class AssessmentForm(models.Model):
name = models.CharField(max_length=400)
description = models.TextField()
created = models.DateTimeField(auto_now_add=True)
is_published = models.BooleanField()
due_date = models.DateField(default=datetime.now, blank=True, null=True)
def __str__(self):
return self.name
class AssessmentResponse(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT)
assessment = models.ForeignKey('AssessmentForm', on_delete=models.CASCADE)
created = models.DateTimeField(auto_now_add=True)
last_update = models.DateTimeField(auto_now=True)
def get_absolute_url(self):
return reverse('assessment_response_detail', args=[str(self.id)])
#def get_assessment_id(self):
# return self.assessment
def __str__(self):
return self.user
class AssessmentQuestionType(models.Model):
type = models.CharField(max_length=30)
def __str__(self):
return self.type
class AssessmentQuestionCategory(models.Model):
name = models.CharField(max_length=200)
assessment = models.ForeignKey('AssessmentForm', on_delete=models.CASCADE)
def __str__(self):
return self.name
class AssessmentQuestionSubCategory(models.Model):
name = models.CharField(max_length=200)
parent_category = models.ForeignKey('AssessmentQuestionCategory', on_delete=models.CASCADE)
def __str__(self):
return self.name
#CHOICES_HELP_TEXT = _(u"""The choices field is only used if the question type if the question type is 'radio', 'select', or 'select multiple' provide a comma-separated list of options for this question .""")
class AssessmentQuestion(models.Model):
question_type = models.ForeignKey('AssessmentQuestionType', on_delete=models.PROTECT)
question_text = models.TextField()
is_required = models.BooleanField()
category = models.ForeignKey('AssessmentQuestionCategory', on_delete=models.PROTECT, blank=True, null=True)
subcategory = models.ForeignKey('AssessmentQuestionSubCategory', on_delete=models.PROTECT, blank=True, null=True)
assessment = models.ForeignKey('AssessmentForm', on_delete=models.CASCADE)
def __str__(self):
return self.question_text
class AssessmentQuestionChoice(models.Model):
question = models.ForeignKey(AssessmentQuestion, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200, blank=True, null=True)
def __str__(self):
return self.choice_text
class AssessmentAnswer(models.Model):
text = models.CharField(max_length=1024)
question = models.ForeignKey('AssessmentQuestion', on_delete=models.CASCADE)
response = models.ForeignKey('AssessmentResponse', on_delete=models.PROTECT)
def __str__(self):
return self.text
Figured it out! Objects.filter is a lazy query so it wasn't actually available to my other query-set to use as a filter. Solved it by using objects.get instead.
I am creating a demo Django website where you browse Billy Joel's albums . You click on an album to view all songs.
(If it happens to be on: http://104.131.200.120/albums/all/--there's hardly any data at the moment. Only one song in Cold Spring Harbor, none in An Innocent Man)
I can't figure out how to display the song name in the album page. It can tell if there is a song, because Cold Spring Harbor prints out an empty "name/description" line, and An Innocent Man doesn't.
Here's the view
def album(request, album_id=1):
album = Album.objects.get(id=album_id)
album_songs = AlbumSong.objects.filter(id=album_id)
print(str(album_songs))
return render_to_response("album.html",
{"album": album, "album_songs" : album_songs})
(the print results in [<AlbumSong: Cold Spring Harbor: 10: Got To Begin Again>] being written to the console, when Cold Spring Harbor is selected.)
The model (note that the Song and Album models are not linked by foreign key. There's an intermediate table, AlbumSong):
from django.db import models
from django.contrib.auth.models import User
from time import time
def get_upload_file_name(instance, filename):
return "uploaded_files/%s_%s" % (str(time()).replace(".", "_"), filename)
class Album(models.Model):
title = models.CharField(max_length=70)
pub_date = models.DateField('release date')
is_official = models.BooleanField(default=False)
is_concert = models.BooleanField(default=False)
likes = models.IntegerField(default=0)
thumbnail = models.FileField(upload_to=get_upload_file_name, blank=True, null=True)
def __str__(self):
return self.title
class Song(models.Model):
name = models.CharField(max_length=100)
sub_name = models.CharField(max_length=200, null=True, blank=True)
length_seconds = models.IntegerField()
lyrics_url = models.TextField(default="", blank=True, null=True)
def __str__(self):
return self.name
class AlbumSong(models.Model):
song_id = models.ForeignKey(Song)
album_id = models.ForeignKey(Album)
sequence_num = models.IntegerField()
class Meta:
unique_together = ('album_id', 'sequence_num',)
unique_together = ('album_id', 'song_id',)
def __str__(self):
return str(self.album_id) + ": " + str(self.sequence_num) + ": " + str(self.song_id)
class FavoriteSongs(models.Model):
user_id = models.ForeignKey(User)
song_id = models.ForeignKey(Song)
sequence_num = models.IntegerField()
class Meta:
unique_together = ('user_id', 'song_id',)
unique_together = ('user_id', 'sequence_num',)
def __str__(self):
return "user=" + str(self.user_id) + ", song=" + str(self.song_id) + ", number=" + str(self.sequence_num)
class FavoriteAlbums(models.Model):
user_id = models.ForeignKey(User)
album_id = models.ForeignKey(Album)
sequence_num = models.IntegerField()
class Meta:
unique_together = ('user_id', 'album_id',)
unique_together = ('user_id', 'sequence_num',)
def __str__(self):
return "user=" + str(self.user_id) + ", album=" + str(self.album_id) + ", number=" + str(self.sequence_num)
and template:
{% extends "base.html" %}
{% block title %}Album detail{% endblock %}
<!-- <div id="sidebar"> -->
{% block sidebar %}
<UL>
<LI>Albums</LI>
</UL>
{% endblock %}
<!-- </div> -->
{% block content %}
<H1>{{ album.title }}</H1>
<P>{{ album.body }}</P>
{% if album.thumbnail %}
<P><img src="/static/{{ album.thumbnail }}" width="200"/></P>
{% endif %}
<P><UL>
<LI>Released: {{ album.pub_date }}</LI>
<LI>Official: {{ album.is_official }}</LI>
<LI>Concert: {{ album.is_concert }}</LI>
</UL></P>
<H2>Songs</H2>
{% for album_song in album_songs %} <!-- No colon after "album_songs" -->
<div>
<P><UL>
<LI>Name: {{ album_song.song.name }}<UL>
<LI>Description: {{ album_song.song.sub_name }}</LI>
</UL></LI>
</UL></P>
</div>
{% endfor %}
<P>Like this album -- {{ album.likes }} people liked this album.</P>
{% endblock %}
How do I display the song name in the template? What should album_song.song.name be changed to?
Thank you.
The problem is your field names. For some reason, you've called your foreign keys from AlbumSong "song_id" and "album_id". So you should use the same names in the template: {{ album_song.song_id.name }}.
However, it doesn't make sense to use this name. The Django field does not represent an ID, it represents the actual Song object. Django already creates an underlying database field with an "_id" suffix, so in this case it's created one called "song_id_id", which is silly. Rename your fields "song" and "album", and keep your template the way it is.