2017-04-25 31 views
0

我有两个模型是这样的:Django的REST框架没有创造与FK对象具有独特=真领域的典范

class Sector(models.Model): 
    name = models.CharField(max_length=100, db_index=True, unique=True) # HERE IF I REMOVE unique=True, it works correctly 

class Address(models.Model): 
    ... 
    sector = models.ForeignKey(Sector, null=True, blank=True) 

并为地址机型串行:

在视图中,我有这个:

address_serialized = AddressSerializer(data=request.data) 
    if address_serialized.is_valid(): 
     address_serialized.save(client=client) 

它永远不会去create函数。我有一个序列化与创建功能,看起来像这样:

class AddressSerializer(serializers.ModelSerializer): 
    city_gps = CitySerializer(required=False) 
    sector = SectorSerializer(required=False) 

    class Meta: 
     model = Address 
     fields = (..., "sector") 

    def create(self, validated_data): 
     ... 
     sector_dict = validated_data.get("sector", None) 
     sector = None 

     if sector_dict and "name" in sector_dict and city_gps: 
      if Sector.objects.filter(name=sector_dict["name"], city=city_gps).exists(): 
       sector = Sector.objects.get(name=sector_dict["name"], city=city_gps) 

     # pdb.set_trace() 
     if "sector" in validated_data: 
      validated_data.pop("sector") 
     if "city_gps" in validated_data: 
      validated_data.pop("city_gps") 

     address = Address.objects.create(sector=sector, city_gps=city_gps, **validated_data) 

     return address 

的代码永远不会触及这个功能,is_valid()返回FALSE。该消息是

{“板块”:{“名”:“这个名字部门已存在”]}}

我需要能够创建一个新的地址与FK到现有的部门。我怎样才能做到这一点?任何建议都会有帮助。

编辑

的看法是这样的:

class ClientProfileAddressCreateView(APIView): 
    # throttle_scope = '1persecond' 
    renderer_classes = (JSONRenderer,) 
    permission_classes = (IsAuthenticated,) 

    def post(self, request): 

     try: 
      client = Client.objects.get(user=request.user) 
     except ObjectDoesNotExist: 
      return Response({"error": "A client profile for the logged user does not exit"}, 
          status=status.HTTP_404_NOT_FOUND) 

     address_serialized = AddressSerializer(data=request.data) 
     print("address_serialized.is_valid: %s" % address_serialized.is_valid()) # Returns False when unique=True in models 
     if address_serialized.is_valid(): 
      # print("address_serialized: %s" % address_serialized.data) 
      address_serialized.save(client=client) 
     else: 
      return Response(data=address_serialized.errors, status=status.HTTP_400_BAD_REQUEST) 

     return Response(data=address_serialized.data, status=status.HTTP_201_CREATED) 
+1

您可能想尝试'is_valid(raise_exception = True)'来诊断... http://www.django-rest-framework.org/api-guide/serializers/#raising-an-exception -on-invalid-data –

+0

您能否向我们提供您的意见?在'''serializer'''中更改'''required' = True''也会改变什么? –

+0

另外,你可以请检查你的数据库的无/空白的扇区条目吗? –

回答

2

这是一个已知的问题与嵌套的序列化和独特的约束。

真的很棒的事情总是做的是实际上打印串行器 - 它可以给你很多额外的信息。

当你有这样的JSON:

{ 
    "Sector": { 
     "name": "Sector XYZ" 
    }, 
    "address_line_one": “Some Random Address” 
} 

Django的REST框架不知道你是否正在制作或获取对象的部门,因此它迫使每个请求验证。

你需要做的是以下几点:

class SectorSerializer(serializers.ModelSerializer): 
    # Your fields. 
    class Meta: 
     model = Address 
     fields = ("Your Fields",) 

     extra_kwargs = { 
      'name': { 
       'validators': [], 
      } 
     } 

然后办理验证你需要重做创建/更新部分,以适应唯一性约束,提高异常/验证错误。

我希望这会有所帮助。

有用的链接:This SO AnswerDealing with unique constraints in nested serializers

编辑:

按切扎尔的要求:我会添加它如何可能看起来像覆盖串行的create方法。我没有试过这个代码,但逻辑是这样的。

class SectorSerializer(serializers.ModelSerializer): 
    # Your fields. 
    class Meta: 
     model = Address 
     fields = ("Your Fields",) 

     extra_kwargs = { 
      'name': { 
       'validators': [], 
      } 
     } 

    def create(self, validated_data): 
     raise_errors_on_nested_writes('create', self, validated_data) 

     ModelClass = self.Meta.model 

     info = model_meta.get_field_info(ModelClass) 
     many_to_many = {} 
     for field_name, relation_info in info.relations.items(): 
      if relation_info.to_many and (field_name in validated_data): 
       many_to_many[field_name] = validated_data.pop(field_name) 

     # FIELD CHECK 
     your_field = validated_data.get("your_field","") # or validated_data["your_field"] 
     try: 
      YourModel.objects.filter(your_check=your_field).get() 
      raise ValidationError("Your error") 
     except YourModel.DoesNotExist: 
      # if it doesn't exist it means that no model containing that field exists so pass it. You can use YourQuerySet.exists() but then the logic changes 
      pass 

     try: 
      instance = ModelClass.objects.create(**validated_data) 
     except TypeError: 
      tb = traceback.format_exc() 
      msg = (
       'Got a `TypeError` when calling `%s.objects.create()`. ' 
       'This may be because you have a writable field on the ' 
       'serializer class that is not a valid argument to ' 
       '`%s.objects.create()`. You may need to make the field ' 
       'read-only, or override the %s.create() method to handle ' 
       'this correctly.\nOriginal exception was:\n %s' % 
       (
        ModelClass.__name__, 
        ModelClass.__name__, 
        self.__class__.__name__, 
        tb 
       ) 
      ) 
      raise TypeError(msg) 

     # Save many-to-many relationships after the instance is created. 
     if many_to_many: 
      for field_name, value in many_to_many.items(): 
       field = getattr(instance, field_name) 
       field.set(value) 

     return instance 
+0

你能最终提供一个手动实现的独特验证的简单例子吗? Hvala;) – cezar

+0

有多种方法可以实现这一点 - 你可以在'view'本身覆盖'create' /'update''post' /'put'或'perform_create' /'perform_update'。或者你可以通过重写'create' /'update'来在序列化程序中完成。我将编辑我的答案,包括序列化器检查 - 和nema na cemu :) @cezar –

+0

现在检查@cezar –

相关问题