简体   繁体   English

如何在DRF中使用一个请求创建多个对象(相关)?

[英]How to create multiple objects (related) with one request in DRF?

I have one class representing a Job, one class representing a Tag, which describes a Job and then I have a class making a relationship (junction table) between them, so a Job can be described by multiple Tags: 我有一个代表一个Job的类,一个代表一个Tag的类,它描述一个Job,然后我有一个类在它们之间建立一个关系(联结表),所以一个Job可以用多个Tags来描述:

class JobTag(models.Model):
    job = models.ForeignKey(Job, unique=False, related_name='jobtags')
    tag = models.ForeignKey(Tag, unique=False, related_name='Tag_For_Job')

    created_time = models.DateTimeField(auto_now_add = True)
    modified_time = models.DateTimeField(auto_now = True)

    class Meta:
        unique_together = ('job', 'tag',)

    def __unicode__(self):
        return 'Tag '+self.tag.name +' for job '+ self.job.name

Then I have serializers: 然后我有序列化器:

class TagSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Tag
        fields = ('url','name','badge_pic')
        read_only_fields = ('name','badge_pic')

class JobTagSerializer(serializers.HyperlinkedModelSerializer):
    tag = TagSerializer()
    class Meta:
        model = JobTag
        fields = ('tag',)
        depth=1

class JobSerializer(serializers.HyperlinkedModelSerializer):
    jobtags=JobTagSerializer(many=True)
    class Meta:
        model = Job
        fields = ('url','name', 'employer','jobtags','description')
        read_only_fields = ('employer',)

So the http response on GET request is: 所以GET请求的http响应是:

{
        "url": "http://127.0.0.1:8000/api/jobs/2/",
        "name": "Odprac mi sneh",
        "employer": "http://127.0.0.1:8000/api/users/4/",
        "jobtags": [
            {
                "tag": {
                    "url": "http://127.0.0.1:8000/api/tags/2/",
                    "name": "Odhadzovanie snehu",
                    "badge_pic": "http://127.0.0.1:8000/media/pictures/tags/0005.jpg"
                }
            }
        ],
        "description": "blablabla"
    }

My question is pretty much obvious, how can I create a job instance and persist them with related JobTags with one POST http request? 我的问题非常明显,如何创建一个作业实例并使用一个POST http请求将它们与相关的JobTags保存在一起?

I tried to repeat this method http://www.django-rest-framework.org/api-guide/serializers/#writable-nested-representations . 我试图重复这个方法http://www.django-rest-framework.org/api-guide/serializers/#writable-nested-representations

class JobSerializer(serializers.HyperlinkedModelSerializer):
        jobtags=JobTagSerializer(many=True)
        class Meta:
            model = Job
            fields = ('url','name', 'employer','jobtags','description')
            read_only_fields = ('employer',)
        def create(self, validated_data):
            jobtag_data = validated_data.pop('jobtags')
            job = Job.objects.create(**validated_data)
            JobTag.objects.create(job=job, **jobtag_data)
            return job

But it returned "create() argument after ** must be a mapping, not list" error, so what should request.data json looks like? 但它返回“create()参数后**必须是映射,而不是列表”错误,那么request.data json应该是什么样的?

Or this approach cannot be used in my case and should I do something completly different? 或者这种方法不能在我的情况下使用,我应该做一些完全不同的事情吗?

I would appreciate any help. 我将不胜感激任何帮助。

Edit 编辑

if i try to access the list: 如果我尝试访问该列表:

def create(self, validated_data):
        jobtag_data = validated_data.pop('jobtags')
        job = Job.objects.create(**validated_data)
        JobTag.objects.create(job=job, **jobtag_data[0])
        return job

I gen another error:"Cannot assign "OrderedDict()": "JobTag.tag" must be a "Tag" instance." 我生成另一个错误:“无法分配”OrderedDict()“:”JobTag.tag“必须是”标签“实例。” So im guessing my posted json is in wrong format? 所以我猜我发布的json格式错误了吗? I tried topost data this way: 我尝试以这种方式发布数据:

{
        "name": "Odprac mi sneh",
        "jobtags": [
            {
                "tag": {
                    "url": "http://127.0.0.1:8000/api/tags/2/"
                }
            }
        ],
        "description": "veela sneu nemam ruky makam makam makamam",           
    }

If anyone else is facing this, the most suitable solution I figured out, so that the hyperlinked serialisation of jobtags was used when object is created and nested serialisation was used as an output is this: 如果其他人正面对这个,我想出了最合适的解决方案,以便在创建对象并使用嵌套序列化作为输出时使用了jobtags的超链接序列化:

I wrote serializers for each of these cases, for serialisation of data sent to client: 我为每种情况编写了序列化程序,用于序列化发送到客户端的数据:

class JobTagNestedSerializer(serializers.HyperlinkedModelSerializer):
    tag = TagSerializer()
    class Meta:
        model = JobTag
        fields = ('tag',)
        depth=1



class JobNestedSerializer(serializers.HyperlinkedModelSerializer):
    jobtags=JobTagNestedSerializer(many=True,read_only=True)
    class Meta:
        model = Job
        fields = ('url','name', 'employer','jobtags','description')
        read_only_fields = ('employer',)

and for creating new Job, so for data sent from client to DRF: 并且对于创建新Job,对于从客户端发送到DRF的数据:

class JobTagSerializer(serializers.HyperlinkedModelSerializer):
        class Meta:
            model = JobTag
            fields = ('tag',)

class JobCreateSerializer(serializers.HyperlinkedModelSerializer):
        jobtags=JobTagSerializer(many=True,required=False)
        class Meta:
            model = Job
            fields = ('url','name', 'employer','jobtags','description')
            read_only_fields = ('employer',)

        def create(self, validated_data):
            tag_data = validated_data.pop('jobtags')
            job = Job.objects.create(**validated_data)
            for tag in tag_data:
                d=dict(tag)
                JobTag.objects.create(job=job, tag_id=d['tag'].pk)
            return job

So DRF is expecting the POST json from client to looks like: 所以DRF期望客户端的POST json看起来像:

{
        "name": "Odprac mi sneh",
        "employer": "http://127.0.0.1:8000/api/users/4/",
        "jobtags": [
            {
                "tag": "http://127.0.0.1:8000/api/tags/2/"
            },
            {
                "tag": "http://127.0.0.1:8000/api/tags/5/"
            }
        ],
        "description": "veela sneu nemam ruky makam makam makamam"
    }

I believe you should provide the id and not the url of each tag in your POST data, like so: 我相信你应该在POST数据中提供id而不是每个标签的url ,如下所示:

{
    "name": "Odprac mi sneh",
    "tags": [
        {
            "id": 2
        },
        {
            "id": 3
        }
    ],
    "description": "veela sneu nemam ruky makam makam makamam"
}

Then, in your create method you should be able to iterate over the tags: 然后,在您的create方法中,您应该能够迭代标记:

def create(self, validated_data):
    tag_data = validated_data.pop('tags')
    job = Job.objects.create(**validated_data)

    for tag in tag_data:
        JobTag.objects.create(job=job, tag_id=tag["id"])

    return job

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

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