如何使用 Django 查询从一对多关系中获取数据

Posted

技术标签:

【中文标题】如何使用 Django 查询从一对多关系中获取数据【英文标题】:How to fetch data from one to many relationship using Django queries 【发布时间】:2021-01-30 02:04:01 【问题描述】:

我是 Django 新手,并尝试使用表中的 place 字段从 ProductImage 表中获取一个特定图像的路径详细信息并显示图像。在哪里place == 'Main Product Img' Product 和 ProductImage 是一对多的关系。

我的数据库有两个名为 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模板中进行方法调用,括号是故意不允许的,以防止人们在模板中编写业务逻辑。 @WillemVanOnsem 所以我必须为查询创建一个单独的文件? 不,那会使软件质量变差一个数量级。 @WillemVanOnsem,好的,现在我明白了...非常感谢...您能否推荐一些参考资料供我进一步研究:) 【参考方案1】:

你不能在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 查询从一对多关系中获取数据的主要内容,如果未能解决你的问题,请参考以下文章

如何在 django 中从一对多关系中检索数据?

Android ListView:如何避免bindView()中的数据库查询?需要获取一对多的关系数据

Django Postgres ArrayField 与一对多关系

Django 无法确定使用一对一关系链接一对多的查询集

从关系数据库映射

从 2 个表中获取记录数 - 一对多关系