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

Django Many-to-Many多对多关联GET/POST请求使用及set()方法疑问

核心结论

你需要使用set()或者add()这类Django ORM提供的多对多操作方法,且必须在两个关联模型的实例都已经保存到数据库之后才能调用,否则会触发操作报错。

现有代码的核心问题

  • 你调用了不存在的new_quote.set()方法,正确的调用方式是操作多对多字段本身:new_quote.tags.set()
  • 第三方API返回的tags是字符串列表,你直接把列表赋值给Tag模型的CharField类型tag字段属于类型错误,每个标签字符串需要对应独立的Tag实例
  • 多对多关联建立的前提是两端的实例都已经完成数据库保存,你创建Quote和Tag实例后没有调用save()就尝试关联,操作无效
  • 你的TagSerializer没有指定序列化字段,运行时会触发DRF报错

多对多常用操作说明

  • add(*objs):给当前实例追加关联对象,不会清空已有的关联关系
  • set(objs_list):用传入的对象列表覆盖当前所有关联关系,等价于先清空原有关联再批量添加新关联
  • remove(*objs):移除指定的关联对象
  • clear():清空当前实例的所有关联关系

代码修改示例

1. 修正serializers.py

from rest_framework import serializers
from .models import Quote, Tag

class TagSerializer(serializers.ModelSerializer):
    class Meta:
        model = Tag
        # 必须明确指定序列化字段
        fields = ['id', 'tag']

class QuoteSerializer(serializers.ModelSerializer):
    tags = TagSerializer(read_only = True, many=True)
    class Meta:
        model = Quote
        fields = ['id', 'frase', 'autor', 'tags']

2. 修正views.py的api_quotes函数

@api_view(['GET', 'POST'])
def api_quotes(request):
    if request.method == 'POST':
        new_quote_data = request.data
        # 先创建并保存Quote实例
        quote = Quote.objects.create(
            id=new_quote_data['id'],
            frase=new_quote_data['frase'],
            autor=new_quote_data['autor']
        )
        # 处理传入的标签列表,去重创建/查询Tag实例
        tag_objs = []
        for tag_name in new_quote_data['tags']:
            tag, _ = Tag.objects.get_or_create(tag=tag_name)
            tag_objs.append(tag)
        # 调用多对多字段的set方法完成关联
        quote.tags.set(tag_objs)

    # 第三方API请求逻辑保持不变
    url = "https://quotes15.p.rapidapi.com/quotes/random/"
    querystring = {"language_code":"pt"}
    headers = {
        'x-rapidapi-host': "quotes15.p.rapidapi.com",
        'x-rapidapi-key': "4a3bce6d8cmsh044349ed231bf95p15f17ajsn846aa4e94d98"
    }
    r = requests.get(url, querystring, headers=headers)
    quote_json = r.json()

    id = quote_json['id']
    frase = quote_json['content']
    autor = quote_json['originator']['name']
    tags = quote_json['tags']
    
    # 先创建并保存Quote实例
    new_quote = Quote.objects.create(
        id=id,
        frase=frase,
        autor=autor
    )
    # 处理标签列表
    tag_objs = []
    for tag_name in tags:
        tag, _ = Tag.objects.get_or_create(tag=tag_name)
        tag_objs.append(tag)
    # 此处调用set方法完成多对多关联
    new_quote.tags.set(tag_objs)

    serialized_quote = QuoteSerializer(new_quote)
    return Response(serialized_quote.data)

内容的提问来源于stack exchange,提问作者Henrique Martinelli Frezzatti

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 17:06:00