Django创建Bot时discount_author无法写入数据库问题求助
问题原因
discount_author字段使用SerializerMethodField,这是只读字段,无法处理传入的请求参数,导致前端传入的discount_author不会被序列化器解析,自然无法存入数据库。- 创建
Bot实例时,没有处理discount_author参数来关联创建对应的BotDiscount实例,数据库中没有该Bot的BotDiscount记录,所以响应中返回默认值0。
修复步骤
1. 修改序列化器,让discount_author支持读写
在AbstractBotSerializer中,替换discount_author的定义,并保留原有输出逻辑:
class AbstractBotSerializer(serializers.ModelSerializer): """ Абстрактный класс, который определяет поведение сериализации и десериализации для данных, связанных с ботами. """ author = serializers.StringRelatedField(read_only=True) # 替换原来的SerializerMethodField为可读写的IntegerField,设置校验规则 discount_author = serializers.IntegerField( required=False, min_value=0, max_value=100, help_text='Введите скидку от автора в процентах (от 0 до 100).' ) discount_category = serializers.SerializerMethodField() amount_discounts_sum = serializers.SerializerMethodField() final_price = serializers.SerializerMethodField() categories = CategoryNameSerializer( required=False, queryset=Category.objects.all(), many=True, ) class Meta: abstract = True fields = '__all__' # 保留原来的折扣值获取逻辑,供其他计算方法调用 def get_discount_author_value(self, obj): try: discount = obj.discounts_author.discount except BotDiscount.DoesNotExist: discount = 0 return math.ceil(discount) # 重写序列化逻辑,确保输出的discount_author是从关联表获取的正确值 def to_representation(self, instance): representation = super().to_representation(instance) representation['discount_author'] = self.get_discount_author_value(instance) return representation def get_discount_category(self, obj): """Расчёт скидки по категории бота""" try: category_id = self.context['request'].query_params.get('categories') if category_id: banner_category = BannerCategory.objects.get(category_id=category_id) discount = banner_category.discount else: discount = BannerCategory.objects.aggregate(Max('discount'))['discount__max'] except BannerCategory.DoesNotExist: discount = 0 return math.ceil(discount) def get_amount_discounts_sum(self, obj): """Суммирование скидки от автора и по категории.""" discount_author = self.get_discount_author_value(obj) discount_category = self.get_discount_category(obj) return discount_author + discount_category def get_final_price(self, obj): """Вычисление итоговой цены бота с учётом всех скидок.""" try: discount_author = obj.discounts_author.discount except BotDiscount.DoesNotExist: discount_author = 0 discount_category = self.get_discount_category(obj) total_discount = discount_author + discount_category if total_discount >= 100: return 1 else: return math.ceil(obj.price - (obj.price * total_discount / 100))
2. 在序列化器的create方法中处理折扣参数,创建关联的BotDiscount实例
修改BotSerializer,重写create方法:
class BotSerializer(AbstractBotSerializer): """Сериализатор списка ботов""" main_photo = Base64ImageField() is_special_offer = serializers.BooleanField(read_only=True) class Meta(AbstractBotSerializer.Meta): model = Bot fields = '__all__' def create(self, validated_data): # 从校验后的数据中取出discount_author参数(如果存在) discount_author = validated_data.pop('discount_author', None) # 创建Bot实例 bot = super().create(validated_data) # 如果传入了折扣值,创建对应的BotDiscount记录 if discount_author is not None: BotDiscount.objects.create(bot=bot, discount=discount_author) return bot
验证修复效果
现在发送创建请求时,传入的discount_author会被序列化器解析,在创建Bot后自动创建关联的BotDiscount实例,响应中的discount_author会返回传入的数值(而非默认0)。
为什么之前改IntegerField会报错?
你之前直接把SerializerMethodField改成IntegerField,但原来的get_amount_discounts_sum等方法依赖get_discount_author方法,改成普通字段后这个方法被移除,导致调用报错。上面的方案保留了原有的折扣值获取逻辑,同时让字段支持读写,解决了这个问题。
内容的提问来源于stack exchange,提问作者Maxim K
相关产品推荐
相关产品推荐

