如何在Django中获取外键关联的指定分类下全部产品?
优化获取指定分类下产品的方法
问题描述
目标:从自建模型中获取属于特定分类的所有条目,例如通过分类ID获取该分类下的所有产品。
模型代码
Product模型:
class Product(models.Model): name = models.CharField(max_length=200) category = models.ForeignKey('Category', null=True, on_delete=models.SET_NULL) id = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True, editable=False) def __str__(self): return self.name
Category模型:
class Category(models.Model): #product = models.ForeignKey('Product', null=True, on_delete=models.SET_NULL) name = models.CharField(max_length=200, blank=True, null=True) id = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True, editable=False) def __str__(self): return self.name
当前实现
视图代码:
def getCategory(request, pk): category = Category.objects.get(id=pk) products = Product.objects.all() context = {'category': category, 'products':products} return render(request, 'products/shop.html', context)
模板代码:
{% for product in products %} {% if product.category.id == category.id %} <!-- 产品内容渲染 --> {% endif %} {% endfor %}
疑问:尝试用Product.category_set.all()未成功,想了解更优实现方法。
更优实现方法
方法1:正确使用Django反向关联查询
你之前误用了反向查询的调用方式——反向关联是从Category实例触发,而非Product模型。因为外键定义在Product上,Django默认给Category生成的反向关联名为product_set(模型名小写+_set),正确写法如下:
def getCategory(request, pk): category = Category.objects.get(id=pk) # 直接获取该分类下的所有关联产品 products = category.product_set.all() context = {'category': category, 'products':products} return render(request, 'products/shop.html', context)
模板无需再做ID判断,直接遍历即可:
{% for product in products %} <!-- 产品内容渲染 --> {% endfor %}
如果觉得product_set不够直观,可以在Product的外键字段中指定related_name:
category = models.ForeignKey('Category', null=True, on_delete=models.SET_NULL, related_name='products')
之后就能用category.products.all()来获取关联产品,语义更清晰。
方法2:直接过滤Product模型
通过Product的category字段直接过滤,也是高效的实现方式:
def getCategory(request, pk): category = Category.objects.get(id=pk) # 两种过滤方式二选一 products = Product.objects.filter(category__id=pk) # 或用category实例过滤:products = Product.objects.filter(category=category) context = {'category': category, 'products':products} return render(request, 'products/shop.html', context)
方法3:优化查询避免N+1问题
如果后续需要访问产品关联的分类信息,或分类的其他字段,可以用select_related(正向外键查询)或prefetch_related(反向关联查询)减少数据库请求次数:
- 反向关联场景:
category = Category.objects.prefetch_related('product_set').get(id=pk) products = category.product_set.all()
- 过滤查询场景:
products = Product.objects.select_related('category').filter(category__id=pk)
这样能避免遍历产品时,每次都发起一次分类查询的低效问题。
内容的提问来源于stack exchange,提问作者Ayatoo
相关产品推荐
相关产品推荐

