Python M2M字段Django Rest框架嵌套序列化程序上的更新方法

Python M2M字段Django Rest框架嵌套序列化程序上的更新方法,python,django,django-rest-framework,Python,Django,Django Rest Framework,我的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.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)
    {
    "name": "test_service_group1",
    "services":["service_1", "service_2"],
    }
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有效负载如下所示:

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)
    {
    "name": "test_service_group1",
    "services":["service_1", "service_2"],
    }
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)
因为我有一个M2M直通表,所以我创建新服务组的策略是首先弹出服务列表,用名称创建服务组,然后创建M2M Realationships

创建新服务组的序列化程序如下所示:

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)
    {
    "name": "test_service_group1",
    "services":["service_1", "service_2"],
    }
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。伪代码如下:

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)
    {
    "name": "test_service_group1",
    "services":["service_1", "service_2"],
    }
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)
  • 弹出服务列表
  • 将名称保存到实例id
  • 查找链接到服务组的现有服务
  • 对于现有列表和JSON有效负载列表中常见的服务,不执行任何操作
  • 对于现有列表中而非有效负载中的服务,请删除M2M关联
  • 对于不在现有列表和有效负载中的服务,创建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>]>
    
    [145]中的
    :instance=ServiceGroup.objects.get(pk=1)
    在[146]中:instance.services.all()
    出[146]:
    在[147]中:新的\u服务\u列表=['test-create398']
    在[148]中:服务对象=
    Service.objects.filter(name\u in=new\u services\u list).all()
    In[149]:服务对象
    出[149]:
    在[150]中:instance.service\u set=service\u对象
    在[151]:instance.save()中
    在[152]中:instance.services.all()
    出[152]:
    

    因此,我尝试了上述方法,但没有成功

    您可以覆盖更新方法

    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使用相关的_名称为关系字段提供反向访问,如果不定义相关的\u名称,默认值为modelname\u set..我尝试了这个..这似乎不起作用..M2M关系没有更新..没有错误..它只是不更新M2M表..还请注意,有一个直通表..更新是否需要通过它进行?更新的字段名称将是服务而不是服务\u set