Django:使用get_or_create和unique_together错误

时间:2018-12-19 18:02:10

标签: django django-rest-framework

我正在创建一个API,该API列出并保存交易。我的Transaction模型具有FK到Category模型。创建Transaction时,我的目标是如果类别是新的,也要创建Category

我第一次创建交易时,它成功创建了新类别和交易。下次我尝试使用现有类别创建事务时,收到错误消息,指出该类别已存在。在我的Transaction序列化程序中,添加了一个create方法,该方法应使用get_or_create作为类别。但是,我在我的唯一字段上仍然遇到错误。我的期望是它将返回现有的Category

在有机会使用create之前,似乎在Transaction序列化程序中使用get_or_create方法之前就抛出了错误。

型号:

class Category(models.Model):
    name = models.CharField(max_length=128, null=False)
    owner = models.ForeignKey(settings.AUTH_USER_MODEL,
                          on_delete=models.CASCADE)
    created_time = models.DateTimeField(auto_now_add=True)
    modified_time = models.DateTimeField(auto_now=True)

    class Meta:
        unique_together = ('name', 'owner')


class Transaction(models.Model):
    date = models.DateField()
    payee = models.CharField(max_length=256)
    category = models.ForeignKey(Category,
                                related_name='category',
                                on_delete=models.CASCADE)
    amount = MoneyField(max_digits=19,
                        decimal_places=2,
                        default_currency='USD')
    created_time = models.DateTimeField(db_index=True,
                                        auto_now_add=True)
    modified_time = models.DateTimeField(auto_now=True)

序列化器:

class CategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = Category
        fields = ('id', 'name', 'owner', 'created_time', 'modified_time')


class TransactionSerializer(serializers.ModelSerializer):
    balance = serializers.DecimalField(
        decimal_places=2, max_digits=19, read_only=True)

    category = CategorySerializer(many=False, read_only=False)

    class Meta:
        model = Transaction
        fields = ('id', 'date', 'payee', 'category',
                  'amount', 'balance', 'created_time', 'modified_time',
                  'is_cleared', 'paid_or_deposited')

    def create(self, validated_data):
        category_data = validated_data.pop('category')

        category, created = Category.objects.get_or_create(**category_data)

        transaction = Transaction.objects.create(category=category,
                                                 **validated_data)


        return transaction

POST:

{
"date": "2018-12-19",
"payee": "Test",
"category": {"owner": 1, "name": "TEST"},
"amount": "-134"
}

错误:

{
    "category": {
        "non_field_errors": [
            "The fields name, owner must make a unique set."
        ]
    }
}

1 个答案:

答案 0 :(得分:1)

您正确地认识到您无法使用create()方法。

之所以会这样,是因为默认情况下,ModelSerializer根据您的模型Meta.unique_together的值https://www.django-rest-framework.org/api-guide/serializers/#modelserializer创建验证器

禁用这种类型的验证器的最简单方法是为序列化程序覆盖get_unique_together_validators

class CategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = Category
        fields = ('id', 'name', 'owner', 'created_time', 'modified_time')

    def get_unique_together_validators(self):
        return []

另一种更干净的解决方案是覆盖Meta.validations中的CategorySerializer *

class CategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = Category
        fields = ('id', 'name', 'owner', 'created_time', 'modified_time')
        validators = []

* 请注意,这将禁用来自模型的串行化器验证器unique_for_dateunique_for_monthunique_for_year