Reputation: 1215
I'm new to Django and trying to get path details of one specific image from the ProductImage table using the place field in the table and display the image.Where place == 'Main Product Img'
Product and ProductImage has one to many relationship.
My database has two tables named
Product(id, name, price,..)
and ProductImage(id, productid, image, place)
which contains three images('Main Product IMG', 'Sub Img 1', 'Sub Img 2')
Here is my models.py
from django.db import models
from django.contrib.auth.models import User
class Product(models.Model):
name = models.CharField(max_length=200)
desc = models.TextField()
price = models.DecimalField(max_digits=10, decimal_places=2)
discount = models.DecimalField(max_digits=4, decimal_places=0)
def __str__(self):
return self.name
class ProductImage(models.Model):
PLACEHOLDER= (
('Main Product Image', 'Main Product Image'),
('Sub Img 1', 'Sub Img 1'),
('Sub Img 2', 'Sub Img 2'),
)
product = models.ForeignKey(Product, related_name='image_set', on_delete=models.CASCADE)
image = models.ImageField(upload_to='images/')
place = models.CharField(max_length=20, choices=PLACEHOLDER)
def __str__(self):
return str(self.id)
views.py
def menu(request):
products = Product.objects
images = ProductImage.objects
context = {'products': products, 'images': images}
return render(request, 'store/menu.html', context)
Template
{% for product in products.all %}
<a href="#">
<img src="{{ images.filter(product__id=product.id, place='Main Product Image')[0].image.url }}" class="img-fluid mt-3">
{% if product.discount != 0 %}
<span class="bonus">{{ product.discount }}% off</span>
{% endif %}
</a>
settings.py
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static'),
]
# Media files
MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR
urls.py
urlpatterns = [
path('admin/', admin.site.urls),
path('menu', views.menu, name='menu'),
]
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
I was able to write a query in the shell to do that
>>> images = ProductImage.objects
>>> images.filter(product__id='1', place='Main Product Image')[0].image
<ImageFieldFile: images/img3.jpg>
The rest of the operations are working correctly. I've been trying to solve this issue for many hours now but keep getting
TemplateSyntaxError at /menu
Could not parse the remainder: '(product__id=product.id, place='Main Product Image')[0].image.url'
from 'images.filter(product__id=product.id, place='Main Product Image')[0].image.url'
Any help that is appreciated.
Upvotes: 1
Views: 617
Reputation: 476594
You can not make method calls in a Django template, the parenthesis is deliberately not allowed to prevent people from writing business logic in the template.
You can define a method, for example in the Product
model:
class Product(models.Model):
name = models.CharField(max_length=200)
desc = models.TextField()
price = models.DecimalField(max_digits=10, decimal_places=2)
discount = models.DecimalField(max_digits=4, decimal_places=0)
@property
def main_product_image(self):
return self.image_set.filter(place='Main Product Image').first()
def __str__(self):
return self.name
and then render this with:
<img src="{{ product.main_product_image.image.url }}"; class="img-fluid mt-3">
but this will result in an N+1 problem, if method calls with parameters were allowed, this would also result in an N+1 problem.
You can make use of a Prefetch
object [Django-doc] to load the main images in bulk instead:
from django.db.models import Prefetch
def menu(request):
products = Product.objects.prefetch_related(
Prefetch(
'image_set',
ProductImage.objects.filter(place='Main Product Image'),
to_attr='main_images'
)
)
context = {'products': products}
return render(request, 'store/menu.html', context)
then you can render this with:
{% for product in products %}
<img src="{{ product.main_images.0.image.url }}" class="img-fluid mt-3">;
…
{% endfor %}
Upvotes: 1