【问题标题】:Update method on Django Rest framework nested serializer for M2M fields用于 M2M 字段的 Django Rest 框架嵌套序列化程序的更新方法
【发布时间】:2019-05-11 05:44:11
【问题描述】:

我的 models.py 中有三个模型如下:

class Service(models.Model):
     name = models.CharField(max_length=50, unique=True)
     port = models.PositiveSmallIntegerField()
     protocol = models.CharField(max_length=50)

class ServiceGroup(models.Model):
     name = models.CharField(max_length=50, unique=True)
     services = models.ManyToManyField(Service, through=ServiceToServiceGroup)

class ServiceToServiceGroup(models.Model):
    service = models.ForeignKey(Service)
    service_group = models.ForeignKey(ServiceGroup)

我创建新服务组的 JSON 负载如下:

    {
    "name": "test_service_group1",
    "services":["service_1", "service_2"],
    }

由于我有一个 M2M through 表,我创建新 ServiceGroup 的策略是首先弹出服务列表,创建具有名称的 ServiceGroup,然后创建 M2M 关系。

我创建新ServiceGroup的序列化器如下:

class ServiceGroupCreateUpdateSerializer(serializers.ModelSerializer):
    services = serializers.SlugRelatedField(queryset=Service.objects.all(), 
                                            slug_field='name', many=True)
    class Meta:
        model = ServiceGroup
        fields = ['id', 'name', 'services']

    def create(self, validated_data):
        # Pop the services list out
        services = validated_data.pop('services', None)
        # Create the ServiceGroup with the name 
        service_group = ServiceGroup.objects.create(name=validated_data['name'])
        #Create M2M associations
        for service in services:
            service_id = Service.objects.get(name=service)
            ServiceToServiceGroup.objects.create(service_id=service_id,
                                                 service_group_id= service_group.id)

我的问题是我现在如何编写更新方法?我的 JSON 负载保持不变,唯一的区别是我在 URL 中传递了实例 id。伪代码如下:

  1. 弹出服务列表。
  2. 将名称保存到实例 ID。
  3. 找到与 ServiceGroup 关联的现有服务。
  4. 对于现有列表和 JSON 负载列表中常见的服务,什么也不做。
  5. 对于现有列表中而非负载中的服务,删除 M2M 关联。
  6. 对于不在现有列表和负载中的服务,创建 M2M 关联。

对于更新方法来说,这似乎需要做很多工作。有没有更简单的方法?

更新

In [145]: instance = ServiceGroup.objects.get(pk=1)                                                                                                                                                                                                                      

In [146]: instance.services.all()                                                                                                                                                                                                                                        
Out[146]: <QuerySet [<Service: test-create442>]>

In [147]: new_services_list = ['test-create398']                                                                                                                                                                                                                         

In [148]: service_objects = 
Service.objects.filter(name__in=new_services_list).all()                                                                                                                                                                                     

In [149]: service_objects                                                                                                                                                                                                                                                
Out[149]: <QuerySet [<Service: test-create398>]>

In [150]: instance.service_set = service_objects                                                                                                                                                                                                                         

In [151]: instance.save()                                                                                                                                                                                                                                                

In [152]: instance.services.all()                                                                                                                                                                                                                                        
Out[152]: <QuerySet [<Service: test-create442>]>

所以,我尝试了上述方法,但没有成功。

【问题讨论】:

    标签: python django django-rest-framework


    【解决方案1】:

    你可以覆盖更新方法

    def update(self, instance, validated_data):
        # Pop the services list out
        services = validated_data.pop('services', None)
        instance = super().update(instance, validated_data)
        service_objects = Service.objects.filter(name__in=services).all()
        ServiceToServiceGroup.objects.filter(service_group=instance).delete()
        service_group_obj = []
        for service in service_objects:
            service_group_obj(ServiceToServiceGroup(service=service, service_group=instance))
        ServiceToServiceGroup.objects.bulk_create(service_group_obj)
        return instance
    

    【讨论】:

    • 这看起来很不错...你能详细说明 instance.service_set 的工作原理吗?
    • django 为关系字段提供反向访问,使用related_name,如果不定义related_name 默认为modelname_set stackoverflow.com/questions/17328910/…
    • ..我试过这个..这似乎不起作用..M2M关系没有更新..
    • 没有错误..它只是不更新​​ M2m 表..还注意到有一个直通表..更新需要通过那个发生吗?
    • 更新的字段名称将是服务而不是 service_set
    猜你喜欢
    • 2015-02-17
    • 2020-07-07
    • 2019-12-23
    • 2016-05-04
    • 2014-07-19
    • 2018-06-18
    • 1970-01-01
    • 2021-06-23
    相关资源
    最近更新 更多