Django Rest Framework : Got AttributeError when attempting to get a value for field `data_params` on serializer `OrderCreateSerializer`

Question:

This is my models:

class Order(models.Model):
    """

    """
    order_num = models.CharField(max_length=128, unique=True)  
    order_status = models.CharField(max_length=12)    
    product_describe = models.TextField()  
    billing_type = models.CharField(max_length=16)   
    buytime = models.CharField(max_length=16)  
    count = models.IntegerField()   
    paytype = models.CharField(max_length=16)   
    cost = models.DecimalField(max_digits=8, decimal_places=2, default=0.00)   
    account = models.ForeignKey(to=Account)  

    ctime = models.DateTimeField(auto_now_add=True)   
    uptime = models.DateTimeField(auto_now=True)   

    def __str__(self):
        return self.product_describe
    def __unicode__(self):
        return self.product_describe

This is my serializer:

class OrderCreateSerializer(ModelSerializer):

    data_params = serializers.DictField()   

    class Meta:
        model = Order
        fields = (
            "product_describe",   
            "billing_type",  
            "data_params",  
        )
    def create(self, validated_data):

        request = self.context.get("request")
        if request and hasattr(request, "user"):
            user = request.user

        validated_data["order_num"] = generateOrderNum(userid=user.id)
        validated_data["order_status"] = "unpay"

        data_dic = validated_data.pop("data_params") #

        validated_data["buytime"] = data_dic["data"]["buytime"]
        validated_data["count"] = data_dic["data"]["count"]
        validated_data["paytype"] = ""   

        validated_data["cost"] = 0.00   
        validated_data["account"] = user.account   

        return Order.objects.create(**validated_data)

You see, in my serializer I have pop the data_params:

data_dic = validated_data.pop("data_params") 

But when I access this API, I get:

AttributeError at /api/financialmanage/order/add/
Got AttributeError when attempting to get a value for field data_params on serializer OrderCreateSerializer.
The serializer field might be named incorrectly and not match any attribute or key on the Order instance.
Original exception text was: ‘Order’ object has no attribute ‘data_params’.

If I don’t pop data_params, I will get bellow error:

TypeError at /api/financialmanage/order/add/
‘data_params’ is an invalid keyword argument for this function


EDIT

My views.py:

class OrderSerializerCreateAPIView(CreateAPIView):
    """
    create Order
    """
    serializer_class = OrderCreateSerializer
    permission_classes = []
    queryset = Order.objects.all()

EDIT-2

In my case the data_params dictionary is necessary for me.
Because when I buy a product(such as CloudServer), which has count, vcpus, ram, disk, and bandwidth, I through the data_params to get that.

You may want to know why I must use data_params to receive the data, because, the product may be different, if the product is Wine, it can not have the vcpus property now.

Asked By: maer

||

Answers:

class OrderCreateSerializer(ModelSerializer):
    data_params = DictField(child=serializers.CharField())
    .
    .
    .
    def create(self, validated_data):
        print(validated_data)

        data_dic = validated_data.pop("data_params")
        print(data_dic)
        return super(OrderCreateSerializer, self).create(validated_data)


class OrderSerializer(ModelSerializer):
    class Meta:
        model = Order
        fields = '__all__'

    # by @Vasil Shtiliyanov if you want return data_parms after create
    def to_representation(self, instance):
        serialized_data = super(OrderSerializer, self).to_representation(instance)
        serialized_data['data-params'] = #logic goes here
        return serialized_data

class OrderSerializerCreateAPIView(CreateAPIView):
    """
    create Order
    """
    serializer_class = OrderCreateSerializer
    permission_classes = []
    queryset = Order.objects.all()

   def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        instance = self.perform_create(serializer)
        data = OrderSerializer(instance).data
        headers = self.get_success_headers(data )
        return Response(data , status=status.HTTP_201_CREATED, headers=headers)

    def perform_create(self, serializer):
       return serializer.save()
Answered By: Ykh

If you want to add the data-params argument to the serializer when it is not a field in the model you should use the def to_representation function of DRF. Should look something like this:

def to_representation(self, instance):
serialized_data = super(SerializerClass, self).to_representation(instance)
serialized_data['data-params'] = #logic goes here
return serialized_data

And remove data-params from fields parameter of the Meta class.

Answered By: Vasil Shtiliyanov

I resolved it that same to yours:

data_params = serializers.DictField()   # yours

data_params = serializers.DictField(write_only=True)  # try it, pls. 

the source code:

# rest_framework/serializers.py => L504
def to_representation():.
    ..  
    fields = self._readable_fields  # this function rest_framework/serializers.py=>L371
    ...
Answered By: Zoe