如何使用 Django 查询从一对多关系中获取数据
How to fetch data from one to many relationship using Django queries
我是 Django 的新手,正在尝试使用 place[=47 从 ProductImage table 获取一张特定图像的路径详细信息=] 字段中的 table 并显示 image.Where place == 'Main Product Img'
Product 和 ProductImage 是一对多的关系。
我的数据库有两个 table 名为
Product(id, name, price,..)
和 ProductImage(id, productid, image, place)
其中包含三张图片('Main Product IMG', 'Sub Img 1', 'Sub Img 2')
这是我的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)
模板
{% 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)
我能够在 shell 中编写查询来做到这一点
>>> images = ProductImage.objects
>>> images.filter(product__id='1', place='Main Product Image')[0].image
<ImageFieldFile: images/img3.jpg>
其余操作正常。我已经尝试解决这个问题好几个小时了,但一直
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'
感谢任何帮助。
不能在Django模板中进行方法调用,括号是故意不允许的,以防止人们在其中编写业务逻辑模板。
你可以定义一个方法,比如在Product
模型中:
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
然后用以下方式渲染:
<img src="{{ product.main_product_image.image.url }}"; class="img-fluid mt-3">
但这会导致 N+1 问题,如果允许使用参数调用方法,这也会导致 N+1问题。
您可以使用 Prefetch
object [Django-doc] 来批量加载主要图像:
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)
然后你可以渲染它:
{% for product in products %}
<img src="{{ product.main_images.0.image.url }}" class="img-fluid mt-3">;
…
{% endfor %}
我是 Django 的新手,正在尝试使用 place[=47 从 ProductImage table 获取一张特定图像的路径详细信息=] 字段中的 table 并显示 image.Where place == 'Main Product Img'
Product 和 ProductImage 是一对多的关系。
我的数据库有两个 table 名为
Product(id, name, price,..)
和 ProductImage(id, productid, image, place)
其中包含三张图片('Main Product IMG', 'Sub Img 1', 'Sub Img 2')
这是我的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)
模板
{% 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)
我能够在 shell 中编写查询来做到这一点
>>> images = ProductImage.objects
>>> images.filter(product__id='1', place='Main Product Image')[0].image
<ImageFieldFile: images/img3.jpg>
其余操作正常。我已经尝试解决这个问题好几个小时了,但一直
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'
感谢任何帮助。
不能在Django模板中进行方法调用,括号是故意不允许的,以防止人们在其中编写业务逻辑模板。
你可以定义一个方法,比如在Product
模型中:
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
然后用以下方式渲染:
<img src="{{ product.main_product_image.image.url }}"; class="img-fluid mt-3">
但这会导致 N+1 问题,如果允许使用参数调用方法,这也会导致 N+1问题。
您可以使用 Prefetch
object [Django-doc] 来批量加载主要图像:
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)
然后你可以渲染它:
{% for product in products %}
<img src="{{ product.main_images.0.image.url }}" class="img-fluid mt-3">;
…
{% endfor %}