Django: ошибка при использовании get_or_create и unique_together - PullRequest
0 голосов
/ 19 декабря 2018

Я создаю API, который перечисляет и сохраняет транзакции.Моя Transaction s модель имеет модель от FK до Category.Моя цель при создании Transaction - также создать Category, если категория новая.

При первом создании транзакции она успешно создает новую категорию и транзакцию.В следующий раз, когда я пытаюсь создать транзакцию с существующей категорией, я получаю сообщение об ошибке, что категория уже существует.В моем сериализаторе Transaction я добавил метод создания, который должен использовать 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 голосов
/ 19 декабря 2018

Вы правы, что не достигли вашего 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_date, unique_for_month и unique_for_year, поступающие из модели

...