2016-04-18 104 views
0

假設我有兩個型號:多對多關係自定義序列

{ 
"name":"Foo", 
"ips":["192.168.1.40", "4.4.4.4", "8.8.8.8"] 
} 

此外,我要構建的IP在每個請求:

class IPAddress(models.Model): 
    address = models.CharField() 

class Rule(models.Model): 
    name = models.CharField() 
    ips = models.ManyToMany(IPAddress) 

我希望能夠通過如下請求添加規則(沒有url直接構建ip)用於新規則,所以我寫了一個類似於這樣的管理器:

class RuleManager(models.Manager): 
    def create(self, validated_data): 
     rule = Rule(name=validate_data['name']) 
     rule.save() 

     rule.ips = [IPAddress.objects.get_or_create(item.lower()) for item in validated_data['ips']] 

B UT在串行我無法找到一個合適的方式來顯示這一點,我已經寫了一個串行這樣的:

class RuleSerializer(serializers.Serializer): 
    name = serializers.CharField() 
    ips = serializers.SlugRelatedField(many=True, slug_field='address', validators=[], queryset=models.IPAddress.objects.all()) 

但問題是,它驗證IP的請求,如果沒有這樣的IP它返回一個錯誤,儘管我將驗證器設置爲空列表。

我有兩個問題,我該如何禁用此驗證?而且是我寫的串行器與模型的方法是適合我的情況(我不能改變我得到的請求和響應,我必須送)

+0

你需要嵌套的序列化用於創建'ips'通過API,或者您只需要在已經創建ips的地方使用它。 – AKS

回答

2

如果您需要在下面的格式返回Rule一個實例:

{ 
"name":"Foo", 
"ips":["192.168.1.40", "4.4.4.4", "8.8.8.8"] 
} 

您可以創建一個RuleSerializer並使用SlugRelatedField

SlugRelatedField只適用於已存在的對象。因爲你會被創建了對象,你可以修改to_internal_value實施創造一個不存在的對象(referenced from here):

class CreatableSlugRelatedField(serializers.SlugRelatedField): 

    def to_internal_value(self, data): 
     try: 
      return self.get_queryset().get_or_create(**{self.slug_field: data})[0] 
     except ObjectDoesNotExist: 
      self.fail('does_not_exist', slug_name=self.slug_field, value=smart_text(data)) 
     except (TypeError, ValueError): 
      self.fail('invalid') 

class RuleSerializer(serializers.ModelSerializer): 

    ips = serializers.CreatableSlugRelatedField(
     many=True, 
     slug_field='address' # this is the ip address 
     queryset=IPAddress.objects.all() 
    ) 

    class Meta: 
     model = Rule 
     fields: ('name', 'ips') 

UPDATE:基於對這個問題的意見:

我無法改變我得到的請求和響應,我必須送

但是如果你可以再使用嵌套的串行儘管你表示需要略微改變:

{ 
    "name": "Foo", 
    "ips": [ 
     {"address": "192.168.1.40"}, 
     {"address": "4.4.4.4"}, 
     {"address": "8.8.8.8"} 
    ] 
} 

和,然後嵌套序列化(more documentation here):

class IPAddressSerializer(serializers.ModelSerializer): 

    class Meta: 
     model = IPAddress 
     fields: ('address',) 

class RuleSerializer(serializers.ModelSerializer): 

    ips = IPAddressSerializer(many=True) 

    class Meta: 
     model = Rule 
     fields: ('name', 'ips') 
+0

它看起來像一個黑客,因爲我們設置了'ips' read_only字段,但我們使用它來寫入,如果我們將它設置爲'read_only',它將從validated_data中刪除,您可以通過在print中添加'print(validated_data)'來檢查「創造」功能的乞求。我也有許多嵌套關係,每個人都必須構建它的低層數據,所以我認爲使用'ModelManager'來構造低層數據而不是使用'create'的序列化類會更愉快。 – MohsenTamiz

+0

好吧,這不是破解,而是[DRF推薦](http://www.django-rest-framework.org/api-guide/relations/#writable-nested-serializers)。儘管你正在使用'read_only'。這不是必需的,所以你可以在你的實現中刪除它。就經理而言,寫'創造'完全取決於你的要求。 – AKS

+0

如果你刪除'read_only'字段,那麼驗證問題就像我在我的問題中提到的那樣,因爲默認情況下它會檢查'ip'是否存在。 – MohsenTamiz