我正在尝试在Django上进行update_or_create,同时也涉及一些逻辑(由于我使用的字符集的独特性,我不得不稍微偏离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)
然而,当存在具有给定user_id和字符的行时,当我发出PUT请求时,我得到以下结果:
django.db.utils.IntegrityError: (1062, "Duplicate entry '29' for key 'PRIMARY'")
问题是,我希望用我的新值更新数据库中存在的值。我以为update_or_create
就是这么做的——一次追加销售。
如何使用我当前拥有的代码进行追加销售?
您应该使用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
)