You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django创建Bot时discount_author无法写入数据库问题求助

问题原因

  1. discount_author字段使用SerializerMethodField,这是只读字段,无法处理传入的请求参数,导致前端传入的discount_author不会被序列化器解析,自然无法存入数据库。
  2. 创建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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 00:24:58