DRF新手,请耐心等待我:)
我正在尝试使用Serializer更新对象,由于某种原因,我无法将所有请求的有效负载都提供给Serializer,其中一个字段缺失。我必须说这个字段不是与Serializer链接的模型的一部分,但是查看文档,这似乎不是问题......我可以添加我想要的任何字段。
那就是说,这是我的模特:
class Product(AbstractProduct):
name = models.CharField(max_length=50, verbose_name=_(u'Name'))
school = models.ForeignKey('school.School')
level = models.ForeignKey(
'school.Level',
verbose_name=_(u'Level')
)
age = IntegerRangeField()
gender = models.CharField(choices=GENDER_CHOICES, max_length=1, null=True, blank=True, verbose_name=_(u'Gender'))
num_sessions = models.PositiveSmallIntegerField(verbose_name=_(u'Number of sessions'),
default=1,
help_text=_(u"Number of sessions that the product has."),
)
addons = models.ManyToManyField('self',
verbose_name=_(u'Administrators'),
through='AddonInService',
symmetrical=False,
related_name='addon_can_be_used_in'
)
class Meta(AbstractProduct.Meta):
verbose_name_plural = _(u'Products')
这是我的ProductViewSet,没什么特别的,你可以看到......
class ProductAPIViewSet(NestedViewSetMixin, viewsets.ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
@property
def pagination_class(self):
if 'offset' in self.request.query_params:
return CustomLimitOffsetPagination
else:
return CustomPageNumberPagination
最后,这是我的Serializer
class AddonSerializer(serializers.ModelSerializer):
price = serializers.SerializerMethodField()
class Meta:
model = Product
fields = (
'id',
'title',
'name',
'slug',
'description',
'price',
)
def get_price(self, obj):
Selector = get_class('partner.strategy', 'Selector')
selector = Selector()
strategy = selector.strategy()
stock_info = strategy.fetch_for_product(obj)
return stock_info.price.incl_tax
class ProductSerializer(serializers.ModelSerializer):
age = IntegerRangeField()
addons = AddonSerializer(many=True, read_only=True)
price = serializers.SerializerMethodField()
color = serializers.SerializerMethodField()
class Meta:
model = Product
fields = [
'id',
'structure',
'upc',
'title',
'slug',
'description',
'rating',
'date_created',
'date_updated',
'is_discountable',
'name',
'age',
'gender',
'num_sessions',
'parent',
'product_class',
'school',
'level',
'school_category',
'addons',
'color',
'price',
]
def get_price(self, obj):
Selector = get_class('partner.strategy', 'Selector')
selector = Selector()
strategy = selector.strategy()
stock_info = strategy.fetch_for_product(obj)
return stock_info.price.incl_tax
def validate(self, data):
school = data.get('school')
level = data.get('level')
view = self.context['view']
school_id = view.kwargs['parent_lookup_school']
school = School.objects.get(id=school_id)
if level and level.school != school:
raise serializers.ValidationError(
{'level': _(u'The level must be a level created by the school. ')
})
school_category = data.get('school_category')
if school_category is not None and school_category.school != school:
raise serializers.ValidationError({'school_category':
_(u'All the categories must be the categories created by the school.')}
)
return data
def get_color(self, obj):
try:
color = obj.school_category.color
except:
color = ''
return color
def create(self, validated_data):
product = Product.objects.create(**validated_data)
return product
def update(self, instance, validated_data):
for attr, value in validated_data.items():
if attr in 'price':
print('found price!!!')
else:
setattr(instance, attr, value)
instance.save()
return instance
好的,现在想象在我的前端我创建了一个修改现有产品的请求,请求有效负载是这样的:
{
"school": 1,
"school_category": 1,
"name": "Surfing board",
"slug": "object-object",
"level": 3,
"num_sessions": 1,
"age": {
"upper": 65,
"lower": 18,
"bounds": "[)"
},
"addons": [{
"id": 6,
"title": "Photography",
"name": "Photography",
"slug": "",
"description": "Nice pics",
"price": 206.87
}],
"gender": "F",
"description": "a nice board",
"price": 2111
}
因此,我期望在序列化程序更新方法中获得“2111”,但是没有,我什么都没得到。因此,我检查了验证方法,看看到底有什么:
(Pdb) l
85
86 def validate(self, data):
87 import pdb
88 pdb.set_trace()
89 school = data.get('school')
90 -> level = data.get('level')
91 view = self.context['view']
92 school_id = view.kwargs['parent_lookup_school']
93 school = School.objects.get(id=school_id)
94
95 if level and level.school != school:
(Pdb) print data
OrderedDict([(u'slug', u'object-object'), (u'description', u'a nice board'), (u'name', u'Surfing board'), (u'age', NumericRange(18, 65, u'[)')), (u'gender', 'F'), (u'num_sessions', 1), (u'school', <School: school_1>), (u'level', <Level: advanced>), (u'school_category', <Category: Surf <school_1>>)])
正如您所看到的,没有任何价格也没有将插件传递给Serializer ......
如果我创建了ProductSerializer的实例,我可以看到字段......
In [1]: from test.applications.catalogue.serializers import ProductSerializer
In [2]: ps = ProductSerializer()
In [3]: print repr(ps)
ProductSerializer():
id = IntegerField(label='ID', read_only=True)
structure = ChoiceField(choices=(('standalone', <django.utils.functional.__proxy__ object>), ('parent', <django.utils.functional.__proxy__ object>), ('child', <django.utils.functional.__proxy__ object>)), label='Product structure', required=False)
upc = CharField(allow_blank=True, allow_null=True, help_text='Universal Product Code (UPC) is an identifier for a product which is not specific to a particular supplier. Eg an ISBN for a book.', label='UPC', max_length=64, required=False, validators=[<UniqueValidator(queryset=Product.objects.all())>])
title = CharField(allow_blank=True, max_length=255, required=False)
slug = SlugField(max_length=255)
description = CharField(allow_blank=True, required=False, style={'base_template': 'textarea.html'})
rating = FloatField(read_only=True)
date_created = DateTimeField(read_only=True)
date_updated = DateTimeField(read_only=True)
is_discountable = BooleanField(help_text='This flag indicates if this product can be used in an offer or not', label='Is discountable?', required=False)
name = CharField(max_length=50)
age = IntegerRangeField()
gender = ChoiceField(allow_blank=True, allow_null=True, choices=(('M', <django.utils.functional.__proxy__ object>), ('F', <django.utils.functional.__proxy__ object>)), required=False)
num_sessions = IntegerField(help_text='Number of sessions that the product has.', label='Number of sessions', max_value=32767, min_value=0, required=False)
school = PrimaryKeyRelatedField(queryset=School.objects.all())
level = PrimaryKeyRelatedField(queryset=Level.objects.all())
school_category = PrimaryKeyRelatedField(allow_null=True, label='Category', queryset=Category.objects.all(), required=False)
addons = AddonSerializer(many=True, read_only=True):
id = IntegerField(label='ID', read_only=True)
title = CharField(allow_blank=True, max_length=255, required=False)
name = CharField(max_length=50)
slug = SlugField(max_length=255)
description = CharField(allow_blank=True, required=False, style={'base_template': 'textarea.html'})
price = SerializerMethodField()
color = SerializerMethodField()
price = SerializerMethodField()
任何想法为什么我没有得到价格 - 串行器中的插件?谢谢!
编辑:根据文档和上面的答案,我通过将字段更改为IntegerField来修复此问题
price = serializers.IntegerField()
然后移动在模型中添加了一个方法
@property
def get_price(self):
Selector = get_class('partner.strategy', 'Selector')
selector = Selector()
strategy = selector.strategy()
stock_info = strategy.fetch_for_product(self)
return stock_info.price.incl_tax
这实际上有效,看起来更干净......
答案 0 :(得分:1)
这是因为您使用SerializerMethodField
作为价格。根据{{3}}:
这是一个只读字段。它通过调用附加到它的序列化程序类的方法来获得它的价值。
如果您希望将整数传递给后端,则必须使用IntegerField
。为了实现检索数据的专用功能,您可以the documentation:
price = serializers.IntegerField(source='get_price')
可能必须将此get_price()
方法移至模型才能使其正常工作。