I have a this models
class Project(models.Model):
name = models.CharField(max_length=20)
description = models.CharField(max_length=200, null=True, blank=True)
creation_date = models.DateTimeField(auto_now_add=True, auto_now=False)
group_owner = models.ForeignKey(User)
def __str__(self, y):
return smart_str(self.name)
class Note(models.Model):
title = models.CharField(max_length=50, null=True, blank=True)
content = models.CharField(max_length=1000)
creation_date = models.DateTimeField(auto_now_add=True, auto_now=False)
updated_date = models.DateTimeField(auto_now_add=False, auto_now=True)
projectId = models.ForeignKey(Project, on_delete=models.CASCADE)
userid = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return smart_str(self.title)
which i would like to join them in one view, which would be shown when someone enters to this url http://localhost.com:8000/project/ID.
obviously the ID will depend in Project.id and it will have to get all the Notes that are related to it.
Meanwhile my views.py looks like this
class ProjectDetail(generic.DetailView):
model = Project
template_name = 'scribere/project/detail.html'
def get_queryset(self):
return Project.objects.filter(group_owner__exact=self.request.user.id)
class ProjectNoteList(generic.ListView):
context_object_name = 'project_note_list'
template_name = 'scribere/note/index.html'
def get_queryset(self):
return Note.objects.filter(userid__exact=self.request.user.id, projectId__exact=self.kwargs['pk'])
and the template
{% extends "base/adminsNavBar.html" %}
{% load i18n %}
{% block head_title %}{% trans 'Projects Details' %}{% endblock %}
{% block breadcrumbs %}
<div class="breadcrumb"><p>{% trans 'Project Details' %}</p></div>
{% endblock %}
{% block content %}
<div class='row'>
{% trans 'Back' %}
{% trans 'Notes' %}
</div>
<div>
{{project.name}}
</div>
<div class = "note-list">
<ul>
{% for note in project_note_list %}
<li>
{{note}}
</li>
{% endfor %}
</ul>
</div>
{% endblock %}
which doesn't load any information about the note. What am i missing?
Unless you are populating project_note_list with some information, there will be nothing to iterate over.
By virtue of the ForeignKeys, and having a Many to one relation the project object will have a set of notes associated with it, without having to look them up.
You should be able to query them using project.note_set.all() or in your template by using:
{% for note in project.note_set %}
Related
I Have a table Product and a table Variation, Variation has ManyToOne relation i.e. ForeignKey with the table.
I want only first object of Variation, so that I can render it fields, which I want.
The way I am currently implementing to call the first object in html page:
{{item.variation.price_set.first}}
Note: {{item}} is my product object or instance.
Html file:
<div class="carousel-inner">
{% for item in TopItems %}
{% if item.image %}
<div class="carousel-item active">
<img class="d-block img-fluid mx-auto m-auto" src="{{item.image.url}}" alt="{{item.name}}">
<p>{{item.name}}</p>
<p>{{item.variation.price_set.first}}</p>
<p>{{item.variation_set.first}}</p>
{% if item.variation.promotion_price_set.first%}
<h2 class="text-primary">
{{item.variation.promotion_price}}
</h2>
<h2 class="text-primary">
{{item.variation.price}}
</h2>
{% else %}
<h2 class="text-primary">
{{item.variation.price}}
</h2>
{% endif %}
</div>
{% endif %}
{% endfor%}
</div>
Models.py
class Product(models.Model):
name = models.CharField(max_length=255)
short_description = models.TextField(max_length=255)
long_description = models.TextField(max_length=255, blank=True)
image = ResizedImageField(
size=[550, 300], quality=70, upload_to='product_images/%Y/%m/%d')
#image = models.ImageField(upload_to='product_images/%Y/%m/%d')
slug = AutoSlugField(unique=True, always_update=False,
populate_from="name")
top_item = models.BooleanField(default=False)
is_available = models.BooleanField(default=True)
category = models.ForeignKey(
Category, related_name="product", on_delete=models.CASCADE)
subcategory = models.ForeignKey(
SubCategory, related_name="sub", on_delete=models.CASCADE, null=True, blank=True)
objects = models.Manager()
available = AvailableManager()
class Meta:
ordering = ("name",) # vai ser ordenado pelo nome não o ID
def get_absolute_url(self):
return reverse("product:detail", kwargs={"slug": self.slug})
class Variation(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
name = models.CharField(
max_length=80, blank=True, null=True)
price = models.FloatField()
promotion_price = models.FloatField(blank=True, null=True)
stock = models.PositiveIntegerField(default=1)
is_available = models.BooleanField(default=True)
availableVariation = AvailableManagerVariation()
objects = models.Manager()
def __str__(self):
return self.name or self.product.name
Views.py, the below method is passing all records to the template.
def get_context_data(self, **kwargs):
context["TopItems"]= Product.objects.filter(top_item=True)
So, How can I get only first record of variaton, so that I can show respective prices?
You can use nested loops, for accessing only first promotion price as well as price in the following way:
This is a minimal reproducible example, as not able to understand your design.
{% for item in TopItems %}
<div>
<p> {{item.name}} </p>
<p>{{forloop.counter}}st variation</p>
{% for variation in item.variation_set.all %}
{% if forloop.counter0 < 1 %}
<p>First variation price of - {{variation.price}}</p>
{% comment %}It will give only first price {% endcomment %}
<p>First variation promotion price - {{variation.promotion_price}}</p>
{% comment %}It will give only first promotion price{% endcomment %}
{% endif %}
{% endfor %}
</div>
<br>
{%endfor%}
Note: There must be a space between template tags, as so write it as {% endif %} not {%endif%}, similarly for {% endfor %} not {%endfor%}.
Note: It will be better, if you pass your context keys in snake_case rather than PascalCase, so it can be passed as top_items rather than TopItems.
I'm trying to loop over my FeatureCatergories, FeatureSubcategories and Features. I'm able to loop over my feature categories just fine. Now I want to loop over my feature subcategories and finally features. I'm not sure what to call in my template for subcategories.. Should it be {{featuresubcategory.title}}? What about features?
views.py
def features_view(request):
context = {
"feature_categories": FeatureCategory.objects.prefetch_related('featuresubcategory_set').all(),
}
return render(request=request, template_name="main/features.html", context=context)
template.html
{% for category in feature_categories %}
{{category.title}}
{% for subcategory in featuresubcategory %}
{{ subcategory.title }}
{% endfor %}
{% endfor %}
models.py
class FeatureCategory(models.Model):
title = models.CharField(max_length=50)
featured_image = models.ImageField(blank=True, upload_to="features/")
category_slug = AutoSlugField(null=True, default=None,
unique=True, populate_from='title')
class Meta:
verbose_name_plural = "Feature Categories"
def __str__(self):
return self.title
class FeatureSubcategory(models.Model):
title = models.CharField(max_length=50)
category = models.ForeignKey('FeatureCategory', on_delete=models.CASCADE)
category_slug = AutoSlugField(null=True, default=None,
unique=True, populate_from='title')
class Meta:
verbose_name_plural = "Feature Subcategories"
def __str__(self):
return self.title
class Feature(models.Model):
title = models.CharField(max_length=150)
category = models.ManyToManyField(FeatureSubcategory)
description = models.TextField()
featured_image = models.ImageField(upload_to=image_dir)
class Meta:
verbose_name_plural = "Features"
def __str__(self):
return self.title
In your template, you must change
featuresubcategory with category.featuresubcategory_set.all()
also,
use prefetch_related('featuresubcategory') instead of prefetch_related('featuresubcategory_set')
{% for category in feature_categories %}
{{category.title}}
{% for subcategory in category.featuresubcategory_set.all %}
{{ subcategory.title }}
{% endfor %}
{% endfor %}
For features of subcategory, add related_name to your category field
category = models.ManyToManyField(FeatureSubcategory,related_name='subcategory_features')
and now, you can use it in your template, and don't forget to make migrate
{% for category in feature_categories %}
{{category.title}}
{% for subcategory in category.featuresubcategory_set.all %}
{{ subcategory.title }}
{% for feature in subcategory.subcategory_features.all %}
{{feature.title}}
{% endfor %}
{% endfor %}
{% endfor %}
You can see related objects reference here
I have a category model and list of posts related to those category also some post with same category name but when i wanted to make list of category section in template,
it showing duplicate name of category as it related to posts like:
food,
food,
desert,
style,
desert,
but I want like:
food,
desert,
style,
here is my code:
views.py
class ListCategory(ListView):
model = Post
paginate_by = 2
template_name = 'shit.html'
context_object_name = 'queryset'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
cate = Post.objects.all()
context['cate'] = cate
return context
models.py
class Category(models.Model):
title = models.CharField(max_length=20)
thumbnail = models.ImageField()
detail = models.TextField()
featured = models.BooleanField(default=True)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post-category', kwargs={
'pk': self.pk
})
class Post(models.Model):
title = models.CharField(max_length=100)
overview = models.TextField()
featured = models.BooleanField(default=True)
timestamp = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(Author,on_delete=models.CASCADE)
thumbnail = models.ImageField()
category = models.ForeignKey(Category, on_delete=models.CASCADE)
tags = TaggableManager()
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post-detail', kwargs={
'pk': self.pk
})
templates
{% extends "base.html" %}
{% load static %}
{% block content %}
<div class="sidebar-box ftco-animate">
<ul class="categories">
<h3 class="heading mb-4">Categories</h3>
{% for cat in cate %}
<li>{{cat.category}}<span>(12)</span></li>
{% endfor %}
</ul>
</div>
{% endblock content %}
Thank you so much!
Seems like you want to group your Posts, based on their category; so you can achieve that by iterating over the Category (instead of Post), and use the backward relationship to find out the related Post objects.
views.py
class ListCategory(ListView):
model = Category
paginate_by = 2
template_name = 'shit.html' # :)
context_object_name = 'queryset'
template:
{% extends "base.html" %}
{% load static %}
{% block content %}
<div class="sidebar-box ftco-animate">
<ul class="categories">
<h3 class="heading mb-4">Categories</h3>
{% for category in queryset %}
<li>{{category}}<span>{{ category.posts_set.count }}</span></li>
<ul>
{% for post in category.post_set.all %}
<li>{{ post }}</li>
{% endfor %}
</ul>
{% endfor %}
</ul>
</div>
{% endblock content %}
I also use {{ category.post_set.count }} instead of 12, since I think you are looking for the number of Post objects within each category.
You can use unique=True in desired field, to make every value unique. If you'll try to add new record with same value of unique field, a django.db.IntegrityError will be raised.
More about unique
More about model's fields options
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>
I'm building a commenting system, which is working fine but i'm now trying to integrate voting. So I made another model to handle that and I tried to pair it using ForeignKey. Not too familiar with ForeignKey but i've looked at some other answers here to see how to render it in the template. I tried that using the nested for loop in my template below but {{ j.user }} doesn't render anything. Can anyone tell me what I'm doing wrong?
models.py
class Comment(models.Model):
destination = models.CharField(default='1', max_length=12, blank=True)
author = models.CharField(max_length=120, blank=True)
comment_id = models.IntegerField(default=1)
parent_id = models.IntegerField(default=0)
comment_text = models.TextField(max_length=350, blank=True)
timestamp = models.DateTimeField(default=timezone.now, blank=True)
def __str__(self):
return self.comment_text
class CommentScore(models.Model):
user = models.ForeignKey(User)
comment = models.ForeignKey(Comment)
upvotes = models.IntegerField(default=0)
downvotes = models.IntegerField(default=0)
views.py
...
comment_list = Comment.objects.filter(destination=id)
score = CommentScore.objects.all()
context = {
'score': score,
'comment_list': comment_list,
}
return render(request, 'article.html', context)
template
{% for i in comment_list %}
<div class='comment_div'>
<h3>{{ i.author }}</h3>
{% for j in comment_list.score_set.all %}
{{ j.user }} #nothing comes up
{% endfor %}
<p>{{ i.comment_text }}</p>
</div>
{% endfor %}
when using _set, the reverse relationship lookup, you must provide the full model name, you must also specify which instance this list of related models this "set" is for so it should be
{% for j in i.commentscore_set.all %}
{% empty %}
No scores found
{% endfor %}
You may also wish to set a related_name for the foreign key
comment = models.ForeignKey(Comment, related_name='scores')
...
{% for j in i.scores.all %}