Django template - render object with specific attribute - python

I want my template to render object with specific attribute (products with specific category).
I am trying following code but it doesn't work.
May you please suggest how to write it correctly?
Template that I am trying make to work:
{% for instance in object_list %}
{% if instance.category == 'Statues' %}
{% endif %}
{% endfor %}
my models.py
class Category(models.Model):
categoryname = models.CharField(max_length=20)
description = models.CharField(max_length=200, blank=True, null=True)
#To make in name, not objXXX
def __str__(self):
return self.categoryname
class Product(models.Model):
name = models.CharField(max_length=20)
image = models.ImageField(upload_to='static/photos', default='http://placehold.it/700x400')
description = models.TextField(max_length=200, blank=True, null=True)
price = models.DecimalField(decimal_places=2, max_digits=10)
category = models.ForeignKey(Category, on_delete=models.PROTECT, blank=True, null=True)
#To make in name, not objXXX
def __str__(self):
return self.name

You need to use the field on the object;
{% for instance in object_list %}
{% if instance.category.categoryname == 'Statues' %}
{{ instance }}
{% endif %}
{% endfor %}
It won't work as a comparison against the string representation of the object.

Related

How can I get all objects of a model and it's fields?

I have a Product Model and I want to be able to count all it's objects in a method so I can render the total number in a template, same for each category but I can only do that with the number_of_likes method.
class Category(models.Model):
name = models.CharField(max_length=45)
...
class Product(models.Model):
author = models.ForeignKey(User, default=None, on_delete=models.CASCADE)
title = models.CharField(max_length=120, unique=True)
category = models.ForeignKey(Category, default=None, on_delete=models.PROTECT)
product_type = models.CharField(max_length=30, choices=TYPE, default='Physical')
likes = models.ManyToManyField(User, related_name='like')
...
def number_of_likes(self):
return self.likes.count()
def number_of_products(self):
return self.Products.objects.all.count()
def number_of_products_for_category(self):
return Product.objects.filter(category_id=self.category_id).count()
def __str__(self):
return str(self.title) + ' from ' + str(self.author)
<div>
<h3>All products ({{ number_of_products }})</h3>
{% for category in categories %}
<p>{{ category.name }} (q)</p>
{{ number_of_products_for_category }}
{% endfor %}
</div>
The number_of_products and number_of_products_for_category are the methods that aren't working.
You can work with:
def number_of_products_for_category(self):
return Product.objects.filter(category_id=self.category_id).count()
But if you use this for all categories, you can .annotate(..) [Django-doc] the queryset:
from django.db.models import Count
categories = Category.objects.annotate(num_products=Count('product'))
and render with:
{% for category in categories %}
<p>{{ category.name }} ({{ category.num_products }})</p>
{% endfor %}
Note: It is normally better to make use of the settings.AUTH_USER_MODELĀ [Django-doc] to refer to the user model, than to use the User modelĀ [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.

Django Template - filtering content

I have two models - "Products" and "Categories", and every product may be added to existing category.
I am trying to find a way to render page with products, filtered by category.
Currently I did it for every category by manualy filtering it in template:
{% for instance in object_list %}
{% if instance.category.categoryname == "Statues" %}
{{ instance.name }}
{{ instance.description }}
{{ instance.price }}
{% endif %}
{% endfor %}
I have same template for every category ("Paintings", "Jewelry" etc) and changed condition in each template. URL "../Statues" leads to prexisting template
Is there any way to do it easier?
I would like condtition {% if instance.category.categoryname == "Statues" %} to be imported from URL. So when you access "../Jewelry" - template would import "Jewelry" from URL and filter content accordingly.
models.py
class Category(models.Model):
categoryname = models.CharField(max_length=20)
description = models.CharField(max_length=200, blank=True, null=True)
#To make in name, not objXXX
def __str__(self):
return self.categoryname
class Product(models.Model):
name = models.CharField(max_length=20)
image = models.ImageField(upload_to='static/photos', default='http://placehold.it/700x400')
description = models.TextField(max_length=200, blank=True, null=True)
price = models.DecimalField(decimal_places=2, max_digits=10)
category = models.ForeignKey(Category, on_delete=models.PROTECT, blank=True, null=True)
#To make in name, not objXXX
def __str__(self):
return self.name
urls.py
urlpatterns = [
path('admin/', admin.site.urls),
path('<str:categoryname>', category_filter)
]
view.py
def category_filter(request, categoryname):
queryset = Product.objects.all()
context = {"object_list": queryset}
return render(request, "category_filter.html", context)
category choice template:
{% for instance in category_list %}
{{ instance.categoryname }}
{% endfor %}
It may be too simple answer ...you can apply filter in your views and send query set based on that:
def category_filter(request, categoryname):
category=Category.objects.get(categoryname=categoryname)
queryset = Product.objects.filter(category=category)
context = {"product_list": queryset}
return render(request, "category_filter.html", context)

Why Am I getting "None" when using ForeignKey on integer value from another model that I know that have integer number?

I wanted to ask you for your help. I have two models. In the first one I wanted to reference foriegn key from the second one to be able to print votescore that I store there.
My models.py :
class Question(models.Model):
question = models.CharField(max_length=300)
answered = models.BooleanField(default=False)
created = models.DateTimeField(auto_now_add=True)
datecompleted = models.DateTimeField(null=True, blank=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
votesscore = models.ForeignKey('VoteQuestion', on_delete=models.CASCADE, null=True, blank=True, related_name='question_votesscore')
def __str__(self):
return self.question
class VoteQuestion(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
question = models.ForeignKey(Question, on_delete=models.CASCADE, blank=False, null=True)
votesubmitted = models.DateTimeField(null=True, blank=True)
votesscore = models.IntegerField(default='0')
amountofvotes = models.IntegerField(default='0')
def __str__(self):
return self.votesscore
class Meta:
unique_together = ['user', 'question', 'votesscore']
Next in my views.py:
def home(request):
allquestionswithanswers = Question.objects.filter(datecompleted__isnull=False)
allquestionswithoutanswers = Question.objects.filter(datecompleted__isnull=True)
return render(request, 'main/home.html', {'allquestionswithanswers': allquestionswithanswers, 'allquestionswithoutanswers': allquestionswithoutanswers})
And in my home.html I am calling it like this:
{% for question in allquestionswithanswers %}
<li>
{{ question }} Score: {{ question.votesscore }} {{ question.user }}
<br><br>
<form class='my-ajax-form' method='POST' action='' data-url="{% url 'questionvoteup' question.id %}" >
{% csrf_token %}
<button type='submit'>UP</button>
</form>
{% for answer in question.answer_set.all %}
{{ answer }}<br>
{% endfor %}
</li>
{% endfor %}
And when I try to print {{ question.votesscore }} I get value "None". Yet I am sure that in database it is an integer value. Could you please point me in right direction with this ?
Thanks and Cheers

django iterate over a list that is an item of a queryset

I have a list that is generated by a method on one of my models. On the home page it works wonderfully, however when I go to a detail view of one project I can access all the parts of that project as they are direct fields of the Model, but I can't access the items in the list.
Model:
class Project(models.Model):
date_published = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
area = models.ForeignKey(Area, on_delete=models.PROTECT)
title = models.CharField(max_length=128, unique=True)
slug = models.SlugField(max_length=64)
summary = models.CharField(max_length=256)
others = models.CharField(max_length=128, blank=True)
deadline = models.DateField(null=True, blank=True)
priority = models.ForeignKey(Priority, on_delete=models.PROTECT)
closed = models.DateTimeField(null=True, blank=True)
def save(self, *args, **kwargs):
if not self.id:
self.slug = slugify(self.title)
super(Project, self).save(*args, **kwargs)
#property
def updates(self):
updates = []
sequence_id = 1
categories = set(self.update_set.all().values_list(
'category__id', flat=True))
for cat_id in categories:
a = Update.objects.filter(
project=self, category__id=cat_id).order_by('added').last()
if cat_id == sequence_id:
updates.append(a)
else:
for i in range(cat_id - sequence_id):
updates.append('null')
updates.append(a)
sequence_id = cat_id
sequence_id += 1
return updates
class Update(models.Model):
project = models.ForeignKey(Project, on_delete=models.CASCADE)
category = models.ForeignKey(UpdateCategory, on_delete=models.PROTECT)
update = models.TextField(max_length=240, blank=True)
added = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.update
The view is simple:
class ProjectDetailView(DetailView):
template_name = 'project_portal/project_detail.html'
queryset = Project.objects.all()
and here is the dynamic url that I am using:
path('project/<int:pk>/',
ProjectDetailView.as_view(), name='project_detail'),
As for the template, I'm lost, here is one of the things I have tried:
<!DOCTYPE html>
{% extends "project_portal/base.html" %}
{% block home %}
<div id="main">
<div id="content">
<div>
<h1>{{ object.title }}</h1>
<h1>hello</h1>
{% if object_list %}
{% for item in updates %}
<p>{{ item }}</p>
{% endfor %}
{% else %}
<h2>No records found for this project</h2>
{% endif %}
</div>
</div>
</div>
{% endblock %}
What do I need to do to access the "updates" list that gets generated?
update is a property of the model instance, you need to access it from there like any other attribute. Also note, there is no object_list in a detail view.
<div>
<h1>{{ object.title }}</h1>
<h1>hello</h1>
{% for item in object.updates %}
<p>{{ item }}</p>
{% endfor %}
</div>

Retrieve a filtered ForeignKey with Django

I have three main models, Picture, Place and PlaceRating:
class Picture(models.Model):
file = ImageField(max_length=500, upload_to="images")
user = models.ForeignKey(User, null=True, related_name="userpictures")
place = models.ForeignKey(Place, null=True, related_name='pictures')
class PlaceRating(models.Model):
place = models.ForeignKey(Place, null=True, related_name="placeratings")
user = models.ForeignKey(User, null=True, related_name="userratings")
rating = models.DecimalField(null=True, max_digits=4, decimal_places=1)
class Place(models.Model):
name = CharField(max_length=50)
I would like to display the place's rating given by the user, together with the place's image, but I cannot manage to do that as I would need to filter the ForeignKey and Django does not seem to allow that.
Example of what I would like to do:
View:
pictures = Picture.objects.filter(user=request.user)
Template:
{% for picture in pictures %}
<img src="{{ picture.file.url }}" class="bigpicture">
{{ picture.place.placeratings.0.rating|user:picture.user }}
{% endfor %}
For information, I managed to do it with templatetags, but this generates a lot of different queries to the database which I can't prefetch..:
{% for picture in pictures %}
<img src="{{ picture.file.url }}">
{% getplaceratingrelatedtopic picture.place.id picture.user.id %}
{% endfor %}
And:
#register.simple_tag
def getplaceratingrelatedtopic(placeid, userid):
print(placeid)
theplace = Place.objects.get(id=placeid)
user = User.objects.get(id=userid)
placerating = PlaceRating.objects.filter(author=user, place=place).last()
if rating:
return placerating.rating
else:
return ""
I work with Python 2.7/Django 1.9.
Any clue ? Thanks a lot!
You should move the logic to the model and use it in the template.
class Picture(models.Model):
file = ImageField(max_length=500, upload_to="images")
user = models.ForeignKey(User, null=True, related_name="userpictures")
place = models.ForeignKey(Place, null=True, related_name='pictures')
class PlaceRating(models.Model):
place = models.ForeignKey(Place, null=True, related_name="placeratings")
user = models.ForeignKey(User, null=True, related_name="userratings")
rating = models.DecimalField(null=True, max_digits=4, decimal_places=1)
class Place(models.Model):
name = CharField(max_length=50)
#property
def rating(self):
return self.placeratings.get().rating
{% for picture in picture_list %}
<img src="{{ picture.file.url }}" class="bigpicture">
{{ picture.place.rating }}: {{ picture.user.username }}
{% endfor %}

Categories