Повторяющаяся запись для первичного ключа в Django - как мне сделать апсерт в Django? - PullRequest
0 голосов
/ 06 мая 2020

Я пытаюсь выполнить update_or_create на Django, при этом также задействованы некоторые logi c (мне нужно немного отклониться от лучших практик с PUT из-за уникального характера набора символов, который я использую) .

В моем представлении есть следующий код (показывающий только метод PUT):

class WordView(APIView):

    def put(self, request, user_id):
        character = request.data.get('character')
        correct = request.data.get('correct')
        mistakes = request.data.get('mistakes')
        score = request.data.get('score')

        if Word.objects.filter(user_id=user_id, character=character).exists():
            orig_word = Word.objects.get(user_id=user_id, character=character)
            correct = correct + orig_word.correct
            mistakes = mistakes + orig_word.mistakes
            trials = orig_word.trials + 1
            score = (score + (orig_word.score * orig_word.trials)) / trials
            pk = orig_word.pk
        else:
            trials = 1

        # Note - I know that pk won't exist on create - just testing update right now

        word_saves = {"user_id": user_id, "character": character,
                      "correct": correct, "mistakes": mistakes, "score": score, "trials": trials, "pk": pk}

        serializer = WordSerializer(data=word_saves)
        if serializer.is_valid(raise_exception=True):
            word_saved = serializer.save()

        return Response({"success": "Word character {} saved for user {}".format(word_saved.character, word_saved.user_id)})

В любом случае в моем WordSerializer у меня есть следующее:

class WordSerializer(serializers.Serializer):
    user_id = serializers.IntegerField()
    character = serializers.CharField()
    correct = serializers.IntegerField()
    mistakes = serializers.IntegerField()
    score = serializers.FloatField()
    trials = serializers.IntegerField()
    pk = serializers.IntegerField()

    def create(self, validated_data):
        return Word.objects.update_or_create(**validated_data)

Однако, когда я делаю запрос PUT, когда существует строка с данным user_id и символом, я получаю следующее:

django.db.utils.IntegrityError: (1062, "Duplicate entry '29' for key 'PRIMARY'")

Дело в том, что я хочу обновить значение, которое существует в базе данных с моим новым значением. Я предположил, что это именно то, что сделал update_or_create - upsert.

Как мне сделать upsert с текущим кодом?

1 Ответ

0 голосов
/ 06 мая 2020

Вы должны использовать аргумент ключевого слова defaults для передачи полей, которые вы хотите обновить при вызове update_or_create. Аргументы ключевого слова, которые вы передаете, кроме defaults, будут использоваться для сопоставления существующей записи, которую вы хотите обновить.

В вашем случае, если user_id и character являются уникальными идентификационными полями для модели, вы должны просто передать эти поля как ключевые слова

class WordSerializer(serializers.Serializer):

    def create(self, validated_data):
        return Word.objects.update_or_create(
            user_id=validated_data.pop('user_id'),
            character=validated_data.pop('character'),
            defaults=validated_data
        )
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...