Django queryset Product model and Product_images model, TemplateSyntaxError - django

I am developing an ecommerce website with Django. I had Product and Product_images models as below:
class Product(models.Model):
tags = models.ManyToManyField(Tag, related_name='products')
same_product = models.ManyToManyField('self', related_name='same_products', blank=True)
category = models.ForeignKey('Category', on_delete=models.CASCADE, related_name='product_categories')
who_like = models.ManyToManyField(User, related_name='liked_products', blank=True)
title = models.CharField('Title', max_length=100, db_index=True)
slug = models.SlugField('Slug', max_length=110, unique = True)
sku = models.CharField('SKU', max_length=50, db_index=True)
description = models.TextField('Description', null=True, blank=True)
sale_count = models.IntegerField('Sale Count', default=0)
is_new = models.BooleanField('is_new', default=True)
is_featured = models.BooleanField('is_featured', default=False)
is_discount = models.BooleanField('is_discount', default=False)
price = models.DecimalField('Price', max_digits=7, decimal_places=2)
discount_value = models.IntegerField('Discount Value', null=True, blank=True)
def __str__(self):
return self.title
class Product_images(models.Model):
# relations
product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='images')
# informations
image = models.ImageField('Image', upload_to='media/product_images')
is_main = models.BooleanField('Main Image', default=False)
is_second_main = models.BooleanField('Second Main Image', default=False)
# moderations
status = models.BooleanField('Status', default=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'image'
verbose_name = 'Image'
verbose_name_plural = 'Images'
ordering = ('created_at',)
def __str__(self):
return f'{self.image}'
In my Product_images model I store several images for one Product, in Product_images model I wrote
boolean fields with names is_main and is_second_main. In my template I want to get these images, in my terminal (interactive shell) when I write single_product.images.get(is_main=True).image.url can get image url, but in template I can't get image, but get an error as below:
TemplateSyntaxError at /
Could not parse the remainder: '(is_main=True).image.url' from 'product.images.get(is_main=True).image.url'
Below is my view and template:
def index(request):
products = Product.objects.all()
context = {
'products': products
}
return render(request, 'index/index.html', context)
{% for product in products %}
<div class="front">
<a href="product-page(no-sidebar).html">
<img src="{{ product.images.get(is_main=True).image.url }}" class="img-fluid blur-up lazyload bg-img" alt="">
</a>
</div>
<div class="back">
<a href="product-page(no-sidebar).html">
<img src="{{ product.images.get(is_main=True).image.url }}" class="img-fluid blur-up lazyload bg-img" alt="">
</a>
</div>
{% endfor %}
Please, help me with this problem and properly display these images, thanks in advance.

I already solve this problem, maybe it is not the best way, but work.
{% for product in products %}
<div class="product-box">
<div class="img-wrapper">
<div class="front">
<a href="{% url 'product-detail' product.slug %}">
{% for image in product.images.all %}
{% if image.is_main %}
<img src="{{ image.image.url }}" class="img-fluid blur-up lazyload bg-img" alt="">
{% endif %}
{% endfor %}
</a>
</div>
<div class="back">
<a href="{% url 'product-detail' product.slug %}">
{% for image in product.images.all %}
{% if image.is_second_main %}
<img src="{{ image.image.url }}" class="img-fluid blur-up lazyload bg-img" alt="">
{% endif %}
{% endfor %}
</a>
</div>
{% endfor %}

Related

Django imagefield don't shows on template

i've a model with an imageField and when i upload file works and in database adds file path to img field
but when i try call it in my template seem is always empity item.img instead other fields works well, to show it i use a listview model
def content_file_name(instance, filename):
ext = filename.split('.')[-1]
# filename = "%s_%s.%s" % (instance, instance.questid.id, ext)
return f"uploads/items/{instance.id}.{ext}"
class Item(models.Model):
type = models.IntegerField(choices=TYPE, blank=False, default=NO_CAT)
name = models.CharField(max_length=250 )
description = models.CharField(max_length=250, blank=True )
img = models.ImageField(upload_to=content_file_name, blank=True)
tags = models.ManyToManyField(Tag, through='Item_Tags')
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING)
active = models.BooleanField(default=False)
created = models.DateTimeField(default=timezone.now)
updated = models.DateTimeField(auto_now=True)
def __str__(self): #metodo righiesto
return self.name
my template
<div class="card-columns">
{% for item in page_obj %}
<div class="card">
{% if item.img %}
<img class="card-img-top" src="{{item.image.url}}" alt="Card image cap">
{% else %}
NO image
{% endif %}
<div class="card-body">
<h5 class="card-title">{{item.name}}</h5>
<p class="card-text">{{item.description}}</p>
<p class="card-text"><small class="text-muted"></small></p>
</div>
</div>
{% endfor %}
</div>

Django 2.2 + DetailView Multiple models with filtering

I'm trying to get my three models working correctly on one DetailView. I have all of them loaded, but the model that contains the images keeps showing the first image. I know I need to filter it somehow, but I don't really know how to do it. Since I need the product info to filter the images. Here is my code:
views:
class VendorDetailView(DetailView):
context_object_name = 'vendor_detail'
model = Vendor
queryset = Vendor.objects.all()
template_name = 'vendor_details.html'
def get_context_data(self, **kwargs):
context = super(VendorDetailView, self).get_context_data(**kwargs)
context['products'] = Product.objects.filter(vendor=self.get_object())
context['image'] = ProductImage.objects.all()
return context
models:
class Product(models.Model):
product_model = models.CharField(max_length=100)
vendor = models.ForeignKey(Vendor, on_delete=models.CASCADE)
slug = models.SlugField(max_length=200, unique=True, null=True)
length = models.CharField(max_length=50)
length_range = models.ForeignKey(LengthRange, on_delete=models.SET_NULL, null=True, blank=True)
hull_type = models.ForeignKey(Hull, on_delete=models.SET_NULL, null=True, blank=True)
max_beam = models.CharField(max_length=50, blank=True, default='0')
cockpit_length = models.CharField(max_length=50, blank=True, default='0')
cockpit_beam = models.CharField(max_length=50, blank=True, default='0')
price = models.DecimalField(decimal_places=2, max_digits=50)
power = models.ForeignKey(PowerConfiguration, on_delete=models.SET_NULL, null=True, blank=True)
average_bare_hull_weight = models.CharField(max_length=50, blank=True, default='0')
fuel_capacity = models.CharField(max_length=50, blank=True, default='0')
seating_capacity = models.ForeignKey(Seat, on_delete=models.SET_NULL, null=True, blank=True)
speed = models.ForeignKey(SpeedRange, on_delete=models.SET_NULL, null=True, blank=True)
warranty = models.CharField(max_length=256, default='None')
hull_only_available = models.BooleanField(blank=False, default=False)
description = models.TextField()
featured = models.BooleanField(blank=False, default=False)
class Meta:
ordering = ['product_model']
def __str__(self):
return '{} {}'.format(self.vendor, self.product_model)
def save(self, *args, **kwargs):
# just check if product_model or vendor.name has changed
self.slug = '-'.join((slugify(self.vendor.name), slugify(self.product_model)))
super(Product, self).save(*args, **kwargs)
class ProductImage(models.Model):
product = models.ForeignKey(Product, related_name='images', on_delete=models.CASCADE)
image = models.ImageField(upload_to='product_images', blank='img/92-thumb.jpg')
class Vendor(models.Model):
name = models.CharField(max_length=100)
slug = models.SlugField(max_length=200, unique=True, null=True)
website = models.CharField(max_length=256)
vendor_email = models.CharField(max_length=100)
images = models.ImageField(upload_to='vendor_images', blank='img/92-thumb.jpg')
description = models.TextField()
def __str__(self):
return self.name
def save(self, *args, **kwargs):
# just check if product_model or vendor.name has changed
self.slug = slugify(self.name)
super(Vendor, self).save(*args, **kwargs)
Template:
<div class="preview col-md-4">
<div class="vendor-pic">
{% if vendor_detail.images %}
<div class="tab-pane">
<img class="vendor-preview" src="{{ vendor_detail.images.url }}"/></div>
{% endif %}
</div>
**[snipped for brevity]**
</div>
<div class="details col-md-6">
<h3 class="vendor-title">{{ vendor_detail.name }} Boats</h3>
<p class="vendor-description">{{ vendor_detail.description | linebreaksbr }}</p>
<h5 class="website">website: <span>{{ vendor_detail.website }}</span></h5>
</div>
</div>
{% for product in products %}
<div class="product-card">
<div class="product">
<div class="top">{% for product_image in image.all %}
{% if product_image.image %}
<img class="product-img" src="{{ product_image.image.url }}">
{% endif %}
{% endfor %}
</div>
<div class="bottom">
<div class="left">
<div class="details">
<h3>{{ product.vendor }} {{ product.product_model }}</h3>
<p>Starting at ${{ product.price|intcomma }}</p>
</div>
<div class="buy"><a
href="{% url 'boatsales:product_detail' product.slug %}"><i
class="material-icons">pageview</i></a></div>
</div>
</div>
</div>
<div class="inside">
<div class="icon"><i class="material-icons">info_outline</i></div>
<div class="contents">
<p style="text-align: justify">{{ product.description|linebreaksbr }}</p>
</div>
</div>
</div>
{% endfor %}
I've tried multiple ways to filter the product images, but the only thing I can get working is the ProductImages.objects.all() which of course is incorrect. Any help you can provide would be greatly appreciated. Thanks in advance.
You don't need a queryset for the images, you can access them through the Product instances using the related_name like this:
{% for product in products %}
<div class="product-card">
<div class="product">
<div class="top">
{% for product_image in product.images.all %}
<img class="product-img" src="{{ product_image.image.url }}">
{% endfor %}
</div>
...
</div>
{% endfor %}

Django template loop through items with parent ID or PK

I'm trying to set up magnific popup on django.
My goal is to have one main picture in the homepage overview gallery view, which when clicked, would open a popup with the related images from the same photoshoot i.e. images with the same ID or PK.
I tried to apply the following approach
but i just cannot get it to work, maybe someone could help me out in this
My models.py
class Item(models.Model):
name = models.CharField(blank=False, max_length=200)
category = models.ForeignKey(Category, blank=True, null=True, on_delete=models.SET_NULL)
order = models.IntegerField(blank=True, null=True)
active = models.BooleanField(blank=True, default=False)
objects = models.Manager()
class Meta:
verbose_name_plural = 'items'
def __str__(self):
return self.name
class ItemImage(models.Model):
image = ProcessedImageField(
blank=True,
null=True,
processors=[ResizeToFit(width=1680, upscale=False)],
format='JPEG',
options={'quality':90})
order = models.IntegerField(blank=True, null=True)
main = models.BooleanField(blank=True, default=False)
cover = models.BooleanField(blank=True, default=False)
item = models.ForeignKey(Item, related_name='items', blank=True, null=True, on_delete=models.SET_NULL)
objects = models.Manager()
class Meta:
verbose_name_plural = 'item images'
Views.py
def portraits(request):
port = ItemImage.objects.filter(item__category__slug='portraits', item__active=True, main=True,).order_by('item__order')
portall = ItemImage.objects.filter(item__category__slug='portraits', item__active=True).order_by('item__order')
context = {
'main_portraits': port,
'all_portraits': portall
}
return render(request, 'gallery/portraits.html', context)
and Template:
{% block content %}
<div class="grid">
{% for pic in main_portraits %}
<div class="item">
<div class="item">
<div class="outer-text">
<div class="text">
{{ pic.item.name }}
<p>Click to view gallery</p>
</div>
</div>
<a><img class="lazy" alt=""
sizes="(min-width:1400px) 1220px
(min-width:1000px) 1000px,
(min-width:500px) 700px,
(min-width:320px) 420px,
280px"
srcset="{{ pic.image_xs.url }} 280w,
{{ pic.image_s.url }} 420w,
{{ pic.image_m.url }} 700w,
{{ pic.image_l.url }} 1000w,
{{ pic.image_xl.url }} 1220w" />
</a> {{ pic.item.pk }}
</div>
<div class="lazy">
{% for p in all_portraits %}
{% endfor %}
</div>
</div>
{% endfor %}
</div>
{% endblock %}
I have set
z.item.pk
just as a test, to see if any of my manipulations result in the pk's to bunch up. For example the first for-loop returns a picture with PK "24", I need for the second for-lop to return only images with the same PK; and so for every image. I think the answer might be connected with _set.all function, just like in the related question above, but I cant seem to get it to work in my case. Feels like I'm missing something here.
current output:
<div class="grid">
<div class="item">
<div class="item">
<div class="outer-text">
<div class="text">
Palagā tītā
<p>Click to view gallery</p>
</div>
</div>
<a><img class="lazy" alt=""
sizes="(min-width:1400px) 1220px
(min-width:1000px) 1000px,
(min-width:500px) 700px,
(min-width:320px) 420px,
280px"
srcset="/media/CACHE/images/IMG_8329_3Vi8mYO_GD621ql/958ba5dbee5efe28fd2f5054b8f819e1.jpg 280w,
/media/CACHE/images/IMG_8329_3Vi8mYO_GD621ql/02d12ca7f0633fee2fc762cf96f7889e.jpg 420w,
/media/CACHE/images/IMG_8329_3Vi8mYO_GD621ql/ba5fa6633e92a288e3b2f47a713d64c2.jpg 700w,
/media/CACHE/images/IMG_8329_3Vi8mYO_GD621ql/fe0d559fef5b02434c43f841005d4961.jpg 1000w,
/media/CACHE/images/IMG_8329_3Vi8mYO_GD621ql/96d0e52dff14d1bc4b60bbec674565db.jpg 1220w" />
</a> 24
</div>
<div class="lazy">
</div>
</div>
You need prefiltered querysets containing the related images for every main image before handing over to the template.
def portraits(request):
ports = ItemImage.objects.filter(item__category__slug='portraits', item__active=True, main=True,).order_by('item__order')
for p in ports:
# You may not need the item__category__slug filter
# if there are only images of the same category
# associated with an item.
# Also, if you want to exclude the main image
# from the set of related images, you need to add the filter
# main=False
p.related_images = ItemImage.objects.filter(item__category__slug='portraits', item__id=p.item.id)
context = {
'main_portraits': ports,
}
return render(request, 'gallery/portraits.html', context)
Then you can loop over main_portraits in the template, and get the related images for each main image in a nested loop:
{% for mainp in main_portraits %}
{% for im in mainp.related_images %}
{# do something with the related images #}
{% endfor %}
{% endfor %}
You can break down the models like this it will make the querying easier.
# models.py
class Item(mdoels.Model):
name = models.CharField(blank=False, max_length=200)
category = models.ForeignKey(Category, blank=True, null=True, on_delete=models.SET_NULL)
...
display_image = models.ProcessedImageField(...)
class ItemImage(models.Model):
item = models.ForeignKey(Item, related_name='images', blank=True, null=True, on_delete=models.SET_NULL)
image = models.ProcessedImageField(...)
...
#views.py
def portraits(request):
items = Item.objects.filter(category__slug='portraits', active=True)
return render(request, 'gallery/portraits.html', context={items: items})
#template
{% for item in items %}
<h1> {{item.name}} </h1>
<img src={{item.display_image}} />
{% for item_image in item.images.all %}
<img src={{item_image.image}} />
{% endfor %}
{% endfor %}

After using prefetch_related still facing n+1

I am facing multiple duplicate db call even after I am using prefetch_related.
Here is my views:
def index(request):
product_qs = Product.objects.filter(shop_type='Grocery', featured=True, hide=False)
product_list = product_qs.prefetch_related('image', 'size_list').order_by('ranking')
products = terminator(request, product_list, 25) // reusable paginator!
context = {'categories': categories, 'products': products}
return render(request, 'grocery/index.html', context)
Here is my models:
class ProductImage(models.Model):
image = models.ImageField(upload_to='shop/product')
color = models.BooleanField(default=False)
image_thumbnail_index = ImageSpecField(source='image',
processors=[ResizeToFill(308, 412)],
format='JPEG',
options={'quality': 100})
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Product(models.Model):
shop_type = models.CharField(choices=shop_options, max_length=40)
name = models.CharField(max_length=200, unique=True)
image = models.ManyToManyField(ProductImage)
category = TreeForeignKey('Category', null=True, blank=True, on_delete=models.PROTECT)
slug = models.SlugField(max_length=200, db_index=True)
featured = models.BooleanField(default=False)
size = models.BooleanField(default=False)
size_list = models.ManyToManyField(SizeList)
available = models.BooleanField(default=True) # out of stock ?
hide = models.BooleanField(default=False) # archive a product
ranking = models.PositiveIntegerField()
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
and the template:
<figure class="product-image-container">
<a href="#" class="product-image">
<img src="{{ product.image.first.image_thumbnail_index.url }}" alt="{{ products.name }}">
</a>
{% trans 'Quickview' %}
</figure>
<div class="product-details">
<h2 class="product-title">
<a href="/grocery/product/{{ product.slug }}">
{% if LANGUAGE_CODE == 'en' %}
{{ product.name }}
{% else %}
{{ product.name_bn }}
{% endif %}
</a>
</h2>
<div class="price-box">
<span class="product-price">
{% if LANGUAGE_CODE == 'en' %}
৳ {{ product.price }}
{% else %}
৳ {{ product.price_bn }}
{% endif %}
</span>
</div><!-- End .price-box -->
Screenshot of sql calls:
Since you are already prefetching the ProductImage objects you may use the of the prefetched objects: {% with product.image.all|first as image %}{{ image.image_thumbnail_index.url }}(% endwith %}. (While calling first() does an extra query using LIMIT 1 at the end.)

Displaying images "not featured" with featured images in Django template language

I am trying to display small thumbnail under featured images using django template language but for some reason main image displays fine but not small image. Idea is to display one featured image and rest as "not featured" images.
My single-page code to display "Featured Images" with "Not Featured" images is given below.
{% extends 'base.html' %}
{% block content %}
<h1>{{ product.title }}</h1>
{% for img in images %}
{% if img.featured %}
<h1>Featured</h1>
<img class='img-responsive' src="{{ MEDIA_URL }}{{ img.image }}"/>
{% else %}
<div class="col-xs-6 col-md-3">
<a href="#" class="thumbnail">
<img class='img-responsive' src="{{ MEDIA_URL }}{{ img.image }}"/>
</a>
</div>
{% endif %}
{% endfor %}
{% endblock %}
Please advise.
My models.py is....
from django.core.urlresolvers import reverse
from django.db import models
class Product(models.Model):
title = models.CharField(max_length=120)
description = models.TextField(null=True, blank=True)
price = models.DecimalField(decimal_places=2, max_digits=100, default=29.99)
sale_price = models.DecimalField(decimal_places=2, max_digits=100, null=True, blank=True)
slug = models.SlugField(unique=True)
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
updated = models.DateTimeField(auto_now_add=False, auto_now=True)
active = models.BooleanField(default=True)
def __unicode__(self):
return str(self.title)
class Meta:
unique_together = ('title', 'slug')
def get_price(self):
return self.price
def get_absolute_url(self):
return reverse('single_product', kwargs={'slug': self.slug})
class ProductImage(models.Model):
product = models.ForeignKey(Product)
image = models.ImageField(upload_to='products/images/')
featured = models.BooleanField(default=False)
thumbnail = models.BooleanField(default=False)
active = models.BooleanField(default=True)
updated = models.DateTimeField(auto_now_add=False, auto_now=True)
def __unicode__(self):
return self.product.title
All the images were set as featured and that was causing issue. Thanks for help #f43d65. Also consulted project on Github at: https://github.com/codingforentrepreneurs/ecommerce/blob/master/ecommerce/templates/products/single.html.
Try to replace
{{ MEDIA_URL }}{{ img.image }}
to
{{ img.image.url }}