How to show all foreign key attribute in Django template? - python

I want to fetch all the foreignkey table's attribute and show it in my HTML template. Here is my code in models, views and in the template:
models.py:
class OrderDashboard(models.Model):
title = models.CharField(max_length=100,default=None)
single_slug = models.SlugField(max_length=100, default=1)
description = models.TextField(max_length=1000)
thumb = models.ImageField()
date = models.DateField()
def __str__(self):
return self.title
class OrderScenario(models.Model):
webshop = models.CharField(max_length=100)
title = models.ForeignKey(OrderDashboard, default=None, on_delete=models.SET_DEFAULT)
order_qty = models.TextField(max_length=10)
order_date = models.DateField()
current_status = models.CharField(max_length=100)
ticket = models.CharField(max_length=200)
remark = models.TextField()
class Meta:
verbose_name_plural = "Scenario"
def __str__(self):
return self.webshop
Views.py:
def single_slug(request, single_slug):
report = OrderDashboard.objects.get(single_slug=single_slug)
return render(request, 'order_dashboard/report.html', {'report': report,
'OrderScenario': OrderScenario.objects.all})
I only want to view all the scenarios added in OrderScenario with respect to Title in OrderDashboard.

You should use backward relationship here; if you are passing the slug through the url, you can use:
views.py:
def single_slug(request, slug): # why you have self as the first argument?
report = OrderDashboard.objects.get(single_slug=slug)
return render(request, 'order_dashboard/report.html', {'report': report}
report.html:
{{ report.title }}
</p>Order Scenarios:</p>
{% for scenario in report.orderscenario_set.all %}
{{ scenario }}
{% endfor %}

Related

Compare object with string in django template

I have two models which I want to output on a template. But only if the parent class object matches to the child class object.
{% for market in markets %}
{% if object.market|slugify == market.market %}
>>> DO SOMETHING <<<
{% endif %}
{% endfor %}
The problem is when I use slugify on the Object it's giving me a string which starts with a small letter but market.market outputs a string with a capital letter.
Do someone know a solid solution for that?
UPDATE:
my Views:
class ItemDetailView(DetailView):
model = Item
template_name = "product.html"
def get_context_data(self, **kwargs):
context = super(ItemDetailView, self).get_context_data(**kwargs)
context['markets'] = Market.objects.all()
# And so on for more models
return context
def market_list(request):
context ={
'markets': Market.objects.all()
}
return render(request, "market-list.html", context)
My Models:
class Market(models.Model):
market = models.CharField(max_length=30)
branch = models.CharField(choices=BRANCH_CHOICES, max_length=1)
image = models.ImageField(blank=True)
slug = models.SlugField(blank=True)
def __str__(self):
return self.market
def get_absolute_url(self):
return reverse("core:market-product-list", kwargs={
'slug': self.slug
})
class Item(models.Model):
title = models.CharField(max_length=100)
market = models.ForeignKey(Market, related_name='children', on_delete=models.CASCADE, blank=True, null=True)
price = models.FloatField()
discount_price = models.FloatField(blank=True, null=True)
category = models.ForeignKey(ItemCategory, related_name='children', on_delete=models.CASCADE, blank=True, null=True)
label = models.CharField(choices=LABEL_CHOICES, max_length=1)
slug = models.SlugField()
description = models.TextField()
image = models.ImageField()
def __str__(self):
return self.title

filtering reviews according to product django

I want my reviews that are on that particular product to be shown only on that product not on any other . I do not know how to filter it. Recently it is showing all the reviews on every product.
My models.py file is:
class Review(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
product = models.ForeignKey(Product , on_delete=models.CASCADE, null=True)
date = models.DateTimeField(auto_now_add=True)
text = models.TextField(max_length=3000 , blank=True)
rate = models.PositiveSmallIntegerField(choices=RATE_CHOICES)
likes= models.PositiveIntegerField(default=0)
dislikes = models.PositiveIntegerField(default=0)
def __str__(self):
return self.user.full_name
my product models.py is:
class Product(models.Model):
title = models.CharField(max_length=110)
slug = models.SlugField(blank=True, unique=True)
status = models.CharField(choices=CATEGORY_CHOICES, max_length=10)
price = models.DecimalField(decimal_places=2, max_digits=6)
quantity=models.IntegerField(default=1)
discount_price=models.FloatField(blank=True, null=True)
size = models.CharField(choices=SIZE_CHOICES, max_length=20)
color = models.CharField(max_length=20, blank=True, null=True)
image = models.ImageField(upload_to=upload_image_path)
description = RichTextField(max_length=1000)
featured = models.BooleanField(default=False)
author = models.ForeignKey(User, on_delete=models.CASCADE)
time_stamp = models.DateTimeField(auto_now_add=True)
my product detail views.py is:
class ProductDetailSlugView(ObjectViewedMixin,DetailView):
queryset = Product.objects.all()
context_object_name = "object_list"
template_name = "product_detail.html"
def get_context_data(self, *args ,**kwargs):
context = super(ProductDetailSlugView , self).get_context_data(*args, **kwargs)
context['reviews'] = Review.objects.all()
# context['reviews'] = Review.objects.filter(product=self.request.product)
cart_obj, new_obj = Cart.objects.new_or_get(self.request)
context['cart'] = cart_obj
# context['comments'] = Comment.objects.all()
return context
my product_detail.html is:
<!-- {% for review in reviews %}-->when i do this with my code it show me all the product
<!-- <h1>{{review.text}}{{review.rate}}</h1>-->
<!-- {% endfor %}-->
{% for review in product.review_set.all %}
{{ review.text }}
{% endfor %}
You do not need to make a query separately for your reviews. You can simply loop over them using your instance of Product in the template. Also for some reason you have set context_object_name = "object_list" try this:
{% for review in object.review_set.all %}
{{ review.text }}
{% endfor %}
Here review_set is simply the default related_name set by Django which is the related models name in lowercase with _set appended to it. You can chose to set the related name yourself like so if you want:
product = models.ForeignKey(Product, related_name='reviews', on_delete=models.CASCADE, null=True)
Anyway if you insist on modifying the view you can simply do this:
class ProductDetailSlugView(ObjectViewedMixin,DetailView):
queryset = Product.objects.all()
context_object_name = "object_list"
template_name = "product_detail.html"
def get_context_data(self, *args ,**kwargs):
context = super(ProductDetailSlugView , self).get_context_data(*args, **kwargs)
context['reviews'] = Review.objects.filter(product=self.object)
cart_obj, new_obj = Cart.objects.new_or_get(self.request)
context['cart'] = cart_obj
# context['comments'] = Comment.objects.all()
return context
And then you can use this:
{% for review in reviews %}
{{ review.text }}
{% endfor %}

Django Foreign key relation views.py and template html

I have 3 tables related for listing a product with features, i want to list FeatureItem values with for loop in template html file. I ve tried to write a view class but i couldn't succeed. Any Suggestion which approach for views.py and template.html file would be best solution? Thanks.
class Item(models.Model):
title = models.CharField(max_length=100)
price = models.FloatField()
slug = models.SlugField()
category = models.ForeignKey(Category, on_delete=models.CASCADE)
feature = models.ForeignKey(Feature, on_delete=models.CASCADE)
class FeatureItem(models.Model):
feature_title = models.CharField(max_length=100)
feature_description = models.CharField(max_length=100)
feature_id = models.ForeignKey(Feature, on_delete=models.CASCADE)
class Feature(models.Model):
title = models.CharField(max_length=100)
description = models.TextField()
urls.py:
urlpatterns = [
...
path('some_url', views.some_view_function, name='some_url'),
...
]
views.py:
def some_view_function(request):
feature_items = models.FeatureItem.objects.all()
context = {
'feature_items' : feature_items,
...
}
return render(request, 'some_template.html', context=context)
some_template.html:
...
<div>
{% for feature_item in feature_items %}
Title: {{ feature_item.feature_title }}
{% endfor %}
...

How to render view from differents applications in the same template?

I have two applications (blog and category). On the post list template I would like to get the category blog name and description.
I have tried to put the import category model in the blog view, but nothing show up. So I have made two views rendering the same template, but it does not work.
Blog models:
from django.db import models
from django.utils import timezone
from autoslug import AutoSlugField
from category.models import Category
class Post(models.Model):
author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
category = models.ForeignKey(Category, on_delete=models.CASCADE,
default = '')
title = models.CharField(max_length=200)
...
class Meta:
verbose_name = "Post"
verbose_name_plural = "Posts"
ordering = ['created_date']
def publish(self):
self.published_date = timezone.now()
self.save()
def __str__(self):
return self.title
category models:
class Category(models.Model):
name = models.CharField(max_length=200)
slug = AutoSlugField(populate_from='name', default='')
parent = models.ForeignKey('self', blank=True, null=True, related_name='children', on_delete=models.CASCADE)
description = models.TextField(max_length=200)
class Meta:
unique_together = ('slug', 'parent',) # Enforcing that there can not be two
verbose_name_plural = "categories" # categories under a parent with same
# slug
def __str__(self): # __str__ method elaborated later in
full_path = [self.name] # post. use __unicode__ in place of
# __str__ if you are using python 2
k = self.parent
while k is not None:
full_path.append(k.name)
k = k.parent
return ' -> '.join(full_path[::-1])
Blog view:
def post_list(request):
posts = Post.objects.all()
cat_blog = Category.objects.get(pk=1)
context = {
'posts': posts,
'cat_blog': cat_blog
}
return render(request, 'blog/post_list.html', context)
Category view:
def cat_blog(request):
cat_blog = Category.objects.get(pk=1)
return render(request, 'blog/post_list.html', {'cat_blog': cat_blog})
post_list.html:
<div class="section-header text-center">
{% for category in cat_blog %}
<h1>{{ category.name }}</h1>
<p class="tag">{{ category.description }}</p>
{% endfor %}
</div>
<div class="row py-5">
{% for post in posts %}
// This part is fine
{% endfor%}
The post loop is fine. How can't I get the category name and description in my section header?
One URL gives one View gives one template.
You use the View to give context to the template to render.
def post_list(request):
posts = Post.objects.all()
cat_blog = Category.objects.get(pk=1)
context = {
'posts': posts,
'cat_blog': cat_blog
}
return render(request, 'blog/post_list.html', context)
Your url.py file should point to the post_list view.

Django objects.filter in template

I have django project with three below models:
models.py
from django.db import models
from django.contrib.auth.models import User
class Album(models.Model):
owner = models.ForeignKey(User)
title = models.CharField(max_length=127)
artist = models.CharField(max_length=63)
release_date = models.DateField()
logo = models.ImageField(blank=True, upload_to='album_logos', default='album_logos/no-image.jpeg')
t_added = models.DateTimeField(auto_now_add=True)
slug = models.SlugField(null=True, blank=True, max_length=63)
class Meta:
ordering = ['-release_date']
def __str__(self):
return self.title
class Song(models.Model):
album = models.ForeignKey(Album, on_delete=models.CASCADE)
name = models.CharField(max_length=255)
# is_favorite = models.BooleanField(default=False)
favorites = models.IntegerField(default=0)
song_file = models.FileField(blank=True, null=True, upload_to='song_files', default='song_files/mektub.mp3')
class Meta:
ordering = ['name']
def __str__(self):
return self.name
class Favorite(models.Model):
user = models.ForeignKey(User)
song = models.ForeignKey(Song)
created = models.DateTimeField(auto_now_add=True)
As you can see from these models many users can favorite many songs. In template, I want to add class to songs which are favorited by authenticated user:
template
<span {% if authenticated user favorited this song %}class="favorited" {% endif %}></span>
My problem is, I don't know how to write "if authenticated user favorited this song" in template. In terminal, I can get this information by this code:
user_favorited_this = song.favorite_set.filter(user=sample_user) and True or False
I couldn't do the same thing in template, since it doesn't support passing argument to filter method. How can I overcome this problem?
A tag filter can do what you want:
If the User.favorite_set.all has something in common with Song.favorite_set.all this means the current user has favorited that song
from django import template
register = template.Library()
# Method 1 for django queryset (Better)
#register.filter
def intersection(queryset1,queryset2):
return queryset1 & queryset2
# Method 2 for queryset or python List
#register.filter
def intersection(queryset1,queryset2):
return list(set.intersection(set(queryset1),set(queryset2)))
html:
{% if request.user.favorite_set.all|intersection:song.favorite_set.all %} class="favorited" {% endif %}
It may just be simpler to do this in the view, and then pass the result to the template as a boolean flag.
For example:
def song_view(request):
...
song = Song.objects.get(pk=request.GET['song_id'])
is_favorite = song.favorite_set.filter(user=request.user).exists()
return render(request, 'my_template.html', {'is_favorite': is_favorite})
or for a generic class based view:
class SongDetail(DetailView):
...
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
song = self.get_object()
is_favorite = song.favorite_set.filter(user=self.request.user).exists()
context['is_favorite'] = is_favorite
return context
and then the code in your template can be simplified to:
<span {% if is_favorite %}class="favorited" {% endif %}></span>

Categories