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.
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()
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.
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
...
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 fielddata_params
on serializerOrderCreateSerializer
.
The serializer field might be named incorrectly and not match any attribute or key on theOrder
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.
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()
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.
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
...