简体   繁体   English

使用 postman 发布请求 Manytomany 字段 DRF

[英]Post request Manytomany field DRF with postman

Objective: Creating a new entry in database from Postman using the "POST".目标:使用“POST”从 Postman 在数据库中创建一个新条目。

I am trying to send the data from Postman and I am using nested serializing.我正在尝试从 Postman 发送数据,并且我正在使用嵌套序列化。 I have changed the create method i have shared the snippet below.我已经更改了创建方法,我在下面共享了代码段。 Also, I tried this solution but it did not work.另外,我尝试了这个解决方案,但没有奏效。 Can someone please point out the mistake I am making?有人可以指出我犯的错误吗?

When I am trying to post as form-data the error is {"magazine":["This field is required."]} .当我尝试作为表单数据发布时,错误是{"magazine":["This field is required."]} When I am trying to post it as raw data the error is Direct assignment to the forward side of a many-to-many set is prohibited. Use magazine.set() instead.当我尝试将其作为原始数据发布时,错误Direct assignment to the forward side of a many-to-many set is prohibited. Use magazine.set() instead. Direct assignment to the forward side of a many-to-many set is prohibited. Use magazine.set() instead.

Here is my models:这是我的模型:

class Article(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()
    author = models.ForeignKey('authors.Author', on_delete=models.CASCADE)
    magazine = models.ManyToManyField('articles.Magazine')

    def __str__(self):
        return self.title


class Magazine(models.Model):
    name = models.CharField(max_length=30)
    title = models.CharField(max_length=100)

    def __str__(self):
        return self.name

This is my serializers:这是我的序列化程序:

class MagazineSerializer(serializers.ModelSerializer):
    class Meta:
        model = Magazine
        fields = '__all__'

class ArticleSerializer(serializers.ModelSerializer):
    author = AuthorSerializer(read_only=True, many=False)
    magazine = MagazineSerializer(many=True)
    class Meta:
        model = Article
        fields = [
            'title',
            'content',
            'author',
            'magazine',
        ]

    def create(self, validated_data):
        allmags = []
        magazine = validated_data.pop('magazine')
        for i in magazine:
            if Magazine.objects.get(id=magazine["id"]).exists():
                mags = Magazine.objects.get(id=magazine["id"])
                allmags.append(mags)
            else:
                return Response({"Error":  "No such magazine exists"}, status=status.HTTP_400_BAD_REQUEST)
            
        validated_data['author'] = self.context['request'].user
        validated_data['magazine'] = allmags
        return Article.objects.create(**validated_data)

Here is my view:这是我的看法:

class ArticleViewSet(viewsets.ModelViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer

class MagazineViewSet(viewsets.ModelViewSet):
    queryset = Magazine.objects.all()
    serializer_class = MagazineSerializer

    serializer_action_class = {
        'get_articles': MagazineSerializer,
    }

    @action(detail=True, url_path='articles', url_name='articles')
    def get_articles(self, request, pk=None):
        articles = Article.objects.filter(magazine=self.kwargs.get('pk'))
        serializer = ArticleSerializer(articles, many=True)
        return Response(serializer.data, status=200)

This is how I tried sending data as raw:这就是我尝试将数据作为原始数据发送的方式:

{
    "title": "New Post form Postman",
    "content": "Postman content new",
    "magazine": [
        {
            "id": 1,
            "name": "The Times",
            "title": "All News"
        }
    ]
}

This is how I posted as form-data:这就是我发布为表单数据的方式:

First, can you please clarify whether you wish to also create new Magazine objects from the nested serializer or do you want the user to only be able to create Article for existing magazines (it seems like the 2nd since you are calling .exists() )?首先,您能否澄清一下您是否还希望从嵌套序列化程序创建新的Magazine对象,或者您是否希望用户只能为现有杂志创建Article (这似乎是第二个,因为您正在调用.exists() ) ?

1st case:第一种情况:

If you were going for the 1st case, where you wish to also create new magazines within the same POST request, I'd recommend using the drf-writeable-nested package.如果您要进行第一种情况,您还希望在同一个POST请求中创建新杂志,我建议使用drf-writeable-nested package。

2nd case:第二种情况:

For this as well, you should use the drf-writeable-nested package.为此,您也应该使用drf-writeable-nested package。 Or, you can use this hack instead:或者,您可以改用此hack

from rest_framework.exceptions import ValidationError
from rest_framework import serializers
from .models import Article, Magazine

class ArticleSerializer(serializers.ModelSerializer):
    author = AuthorSerializer(read_only=True, many=False)
    magazines = MagazineSerializer(many=True, read_only=True)
    # accept list of PKs
    magazines_ids = serializers.PrimaryKeyRelatedField(
        many=True, write_only=True, queryset=Magazine.objects.all()
    )
    class Meta:
        model = Article
        fields = [
            'title',
            'content',
            'author',
            'magazines',
            'magazines_ids',
        ]

    def create(self, validated_data):
        magazines = validated_data.pop("magazines_ids", None)
        validated_data["author"] = self.context["request"].user
        article = Article.objects.create(**validated_data)
        if magazines:
            article.magazine.set(magazines)

        return article 


Now your POST request JSON body should look like:现在您的POST请求JSON正文应如下所示:

{
    "title": "New Post form Postman",
    "content": "Postman content new",
    "magazines_ids": [1]
}

Where magazines parameter takes list of primary keys. magazines参数获取主键列表的位置。


Bonus奖金

Also, just out of my curiosity, are you sure you want to use a ManytoManyField ?另外,出于我的好奇,您确定要使用ManytoManyField吗? I would assume that an Article can only belong to a single Magazine for which you should be using ForeignKey such as:我会假设一篇Article只能属于您应该使用ForeignKey单个Magazine ,例如:

magazine = models.ForeignKey("articles.Magazine", related_name="articles")

and then in your "action", you can make this change:然后在您的“动作”中,您可以进行以下更改:

@action(detail=True, url_path='articles', url_name='articles')
def get_articles(self, request, pk=None):
    articles = self.get_object().articles
    serializer = ArticleSerializer(articles, many=True)
    return Response(serializer.data, status=200)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM