ChatGPT解决这个技术问题 Extra ChatGPT

Django rest框架序列化多对多字段

如何将多对多字段序列化为列表,并通过 rest 框架返回它们?在下面的示例中,我尝试将帖子连同与之关联的标签列表一起返回。

模型.py

class post(models.Model):
    tag = models.ManyToManyField(Tag)
    text = models.CharField(max_length=100)

序列化程序.py

class PostSerializer(serializers.ModelSerializer):
    class Meta:
        model = Post
        fields = ("text", "tag"??)

视图.py

class PostViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = Post.objects.all()
    serializer_class = PostSerializer
使用@Brian 的帮助,我设法以这种形式列出项目:“tags”:[{“name”:“tag1”}]。我想将其简化为列表,是否可能:“tags”:[“tag1”,“tag2”,...]
在 PostSerializers 中使用 `tags = serializers.SlugRelatedField(many=True,read_only=True, slug_field='title', //tag's fireld you want to show allow_null=True)`

B
Brian

您将需要一个 TagSerializer,其 class Meta 具有 model = Tag。创建 TagSerializer 后,将 PostSerializermany=True 修改为 ManyToManyField 关系:

class PostSerializer(serializers.ModelSerializer):
    tag = TagSerializer(read_only=True, many=True)

    class Meta:
        model = Post
        fields = ('tag', 'text',)

Answer is for DRF 3


有用!!! :D 知道如何将这个序列化程序变成一个逗号分隔的列表吗?类 TagSerializer(serializers.ModelSerializer): 类 Meta: 模型 = 标签字段 = ('name')
现在,我得到:“tags”:[{“name”:“tag1”}] 我想将其简化为:“tags”:[“tag1”,“tag2”,...]
标签 = serializers.ListField(source='tag')。这将为您提供标签的每个对象的 str 表示形式的列表
如果您希望能够通过 Post 更新标签怎么办? (例如不是只读)当我拿走只读并尝试修补标签字段的更新时,我得到了奇怪的行为(我收到一个关于标签已经存在的错误)
read_only=True 部分在此处解释:django-rest-framework.org/api-guide/relations/…
J
Jesus Almaral - Hackaprende

这就是我所做的,假设一本书可以有多个作者,而作者可以有多个书: 在模型上:

class Author(models.Model):
    name = models.CharField(max_length=100, default="")
    last_name = models.IntegerField(default=0)

class Book(models.Model):
    authors = models.ManyToManyField(Author, related_name="book_list", blank=True)
    name = models.CharField(max_length=100, default="")
    published = models.BooleanField(default=True)

在序列化器上:

class BookSerializer(serializers.ModelSerializer):
    authors = serializers.PrimaryKeyRelatedField(queryset=Author.objects.all(), many=True)

    class Meta:
        model = Book
        fields = ('id', 'name', 'published', 'authors')


class AuthorSerializer(serializers.ModelSerializer):
    book_list = BookSerializer(many=True, read_only=True)

    class Meta:
        model = Author
        fields = ('id', 'name', 'last_name', 'book_list')

知道我们如何在创建 Book 实体时创建作者吗?
是的,必须在 Views 类上完成,如果您想要更详细的答案,请发布另一个问题
t
theTypan

添加到@Brian 的答案 "tags": [{"name": "tag1"}] 可以通过这种方式简化为 "tags": ["tag1", "tag2",...] :

class TagListingField(serializers.RelatedField):
 
     def to_representation(self, value):
         return value.name

class PostSerializer(serializers.ModelSerializer):
    tag = TagListingField(many=True, read_only=True)

    class Meta:
        ...

更多信息:https://www.django-rest-framework.org/api-guide/relations/#custom-relational-fields


I
Ismail Hachimi

默认的 ModelSerializer 使用关系的主键。但是,您可以使用 Meta depth 属性轻松生成嵌套表示:

class PostSerializer(serializers.ModelSerializer):
    class Meta:
        model = Post
        fields = ("text", "tag")
        depth = 1 

documentation 中所述:

depth 选项应设置为一个整数值,该值指示在恢复为平面表示之前应遍历的关系深度。


W
Windsooon

这对我有用。

tag = TagSerializer(source="tag", read_only=True, many=True)

u
user5299374

姜戈 2.0

对于多对多领域,如果您想要特定的领域:

class QuestionSerializer(serializers.ModelSerializer):

    topics_list = serializers.SerializerMethodField()

    def get_topics_list(self, instance):
        names = []
        a = instance.topics.get_queryset()
        for i in a:
            names.append(i.desc)
        return names
    class Meta:
        model = Question
        fields = ('topics_list',)

对于 get_topics_list,您可以简化为 return list(instance.topics.values_list('desc', flat=True))
r
rodrigomd

在 init 方法的序列化程序中,您可以将查询集传递给字段,rest_framework 验证该查询集上的 id

1)首先从 serializers.ModelSerializer 扩展您的序列化程序

class YourSerializer(serializers.ModelSerializer):

2)在元类中包含该字段

class YourSerializer(serializers.ModelSerializer):
  class Meta:
        fields = (..., 'your_field',)

3)在init方法中:

def __init__(self, *args, **kwargs):
    super(YourSerializer, self).__init__(*args, **kwargs)
    self.fields['your_field].queryset = <the queryset of your field>

您可以像往常一样使用过滤器或排除在任何参数下限制该字段的查询集。如果您想包含所有内容,只需使用 .objects.all()


i
iamdipta

模型.py

class Tag(models.Model):
    name = models.CharField(max_length=100)
    # ===============
    # ... rest of the fields ...

class Post(models.Model):
    tag = models.ManyToManyField(Tag)
    text = models.CharField(max_length=100)

序列化程序.py

class TagSerializer(serializers.ModelSerializer):
    class Meta:
        model = Tag
        fields = '__all__'


class PostSerializer(serializers.ModelSerializer):
    tags = TagSerializer(many=True, read_only=True)

    class Meta:
        model = Post
        fields = ("text", "tag")

视图.py

## FUNCTION BASED VIEW
def fbvPost_ListView(request):
    # list
    if request.method == "GET":
        posts = Post.objects.all()
        serializer = PostSerializer(instance=posts, many=True)
        return JsonResponse(serializer.data, safe=False)

    return JsonResponse({"success": False})

# ===========================================================

## CLASS BASED VIEW
class cbvPost_ListView(viewsets.ReadOnlyModelViewSet):
    queryset = Post.objects.all()
    serializer_class = PostSerializer

注意:Tag、Post 是两种模型,我们需要对它们进行序列化。这里,Post 模型依赖于 Tag 模型,所以这里我们明确提到它,[tags = TagSerializer(many=True, read_only=True)] 或其返回它的主要字段值。

DETAILS HERE


g
gerald heng

嗨,我将展示多对多的更新和创建。上下文是事件可以有很多舞蹈,舞蹈可以有很多事件。请求将如下所示。

 {
     "competition": 2,
     "title": "the title",
     "dances":[ {"id":1},{"id":2}],
     "description": "the desc"            
 }

def create(self, validated_data):
    try:
        dance_ids = []
        for dance in self.initial_data['dances']:
            if 'id' not in dance:
                raise serializers.ValidationError({'detail': 'key error'})
            dance_ids.append(dance['id'])

        new_event = models.Event.objects.create(**validated_data)
        
        if dance_ids:
            for dance_id in dance_ids:
                new_event.dances.add(dance_id)
        new_event.save()
        return new_event

    except Exception as e:
        raise serializers.ValidationError({'detail': e})

def update(self, instance, validated_data):
    # Delete all records of genres.
    try:
        for current_genre in instance.dances.all():
            instance.dances.remove(current_genre)

        # Repopulate genres into instance.
        for dance in self.initial_data['dances']:
            if 'id' not in dance:
                raise serializers.ValidationError({'detail': 'key error'})
            dance_obj = models.Dance.objects.get(pk=dance['id'])
            instance.dances.add(dance_obj)

            event_updated = super().update(instance, validated_data)

        return event_updated
    except Exception as e:
        raise serializers.ValidationError({'detail': e})

如果您只想做“舞蹈”:[1,2],只需对

for dance in self.initial_data['dances']:
        if 'id' not in dance:
            raise serializers.ValidationError({'detail': 'key error'})
        dance_ids.append(dance['id'])

部分。我希望这将能够帮助你们! :)


m
michaels234

首先,Tag 也需要自己的序列化器

class TagSerializer(serializers.ModelSerializer):
    class Meta:
    model = Tag
    fields = '__all__'

然后在您的 PostSerializer 中,添加一行

class PostSerializer(serializers.ModelSerializer):
tag = TagSerializer(read_only=True, many=True).data
class Meta:
    model = Post
    fields = ("text", "tag")

这将使您在 Post 中的 Tag 字段是一个标签 ID 数组。如果你不放“.data”部分,它会放标签的所有属性,这在大多数情况下可能太多了


关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅