You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django多对多关系下如何仅用筛选按类别和广告类型查询广告?

不用手动循环!Django实现按广告类型+类别检索广告的高效方案

当然可以做到!完全不用你手动写循环拼字典,Django的ORM和序列化工具就能帮你直接生成想要的结构化数据,而且广告对象也能完整包含进去,下面给你两种靠谱的实现方式:

方式一:用Django REST Framework序列化器(推荐,灵活且易维护)

这种方式最直观,能直接输出你想要的格式,还能自定义返回的字段:

第一步:定义序列化器

先在你的项目里创建一个serializers.py文件,写入以下代码:

from rest_framework import serializers
from .models import Advertisement_Type, Advertisement, Category

class AdvertisementSerializer(serializers.ModelSerializer):
    # 这里可以自定义广告对象返回的字段,比如只返回title和id就写fields = ['id', 'title']
    class Meta:
        model = Advertisement
        fields = '__all__'

class CategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = Category
        fields = ['name']

class AdvertisementTypeSerializer(serializers.ModelSerializer):
    # 把多对多的category转成名字列表
    category = serializers.SerializerMethodField()
    # 关联的广告集合,source指定关联的反向查询名
    advertisement = AdvertisementSerializer(many=True, source='advertisement_set')

    def get_category(self, obj):
        # 直接返回类别名称的列表,JSON不支持集合格式,用列表是前后端交互的标准方式
        return [cat.name for cat in obj.ad_category.all()]

    class Meta:
        model = Advertisement_Type
        fields = ['name', 'category', 'advertisement']

第二步:查询并序列化数据

在视图或者业务逻辑里,用ORM预取关联数据(避免N+1查询问题),然后序列化:

from django.db.models import Prefetch
from .models import Advertisement_Type
from .serializers import AdvertisementTypeSerializer

# 预取关联的类别和广告,大幅提升查询效率
ad_types = Advertisement_Type.objects.prefetch_related(
    'ad_category',
    Prefetch('advertisement_set', queryset=Advertisement.objects.all())
).all()

# 序列化得到目标格式的数据
result = AdvertisementTypeSerializer(ad_types, many=True).data

这样result就是你想要的结构化数据,每个广告类型下包含名称、类别列表和完整的广告对象集合。

方式二:用ORM聚合(适合简单场景,需PostgreSQL支持)

如果你的项目用的是PostgreSQL数据库,可以用ArrayAgg直接在数据库层面聚合数据,不需要序列化器:

from django.db.models import ArrayAgg
from .models import Advertisement_Type

ad_types = Advertisement_Type.objects.annotate(
    # 聚合得到类别名称的数组
    category=ArrayAgg('ad_category__name', distinct=True),
    # 如果只需要广告的标题等字段,可以这样聚合;要完整对象的话还是推荐序列化器
    advertisement_titles=ArrayAgg('advertisement_set__title', distinct=True)
).values('name', 'category', 'advertisement_titles')

这个方法直接从数据库拿到聚合后的结果,但缺点是没法直接返回完整的广告对象,适合只需要部分字段的场景。

小提示

  • 你示例里的集合格式({'Health', 'Engineering'})在JSON中不被支持,所以实际返回用数组(列表)是行业通用的标准做法。
  • 一定要用prefetch_related优化查询,否则会触发大量重复数据库请求,拖慢性能。

内容的提问来源于stack exchange,提问作者Paolo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 07:39:06