Ali*_*ali 16 python django django-rest-framework
我是DRF的新手.我阅读了API文档,也许它没有注意到,但我找不到一个方便的方法来做到这一点.
我有一个Answer对象与问题有一对一的关系.
在前端我曾经使用POST方法创建一个发送到api/answers的答案,并将PUT方法更新发送到例如api/answers/24
但我想在服务器端处理它.我只会向api/answers发送POST方法,如果对象存在,DRF将根据answer_id或question_id(因为它是一对一)进行检查.如果是,它将更新现有的,如果不是,它将创建一个新的答案.
我应该在哪里实现它,我无法弄明白.在序列化程序或ViewSet或其他内容中覆盖create?
我的模型,序列化器和视图如下:
class Answer(models.Model):
question = models.OneToOneField(
Question, on_delete=models.CASCADE, related_name="answer"
)
answer = models.CharField(
max_length=1, choices=ANSWER_CHOICES, null=True, blank=True
)
class AnswerSerializer(serializers.ModelSerializer):
question = serializers.PrimaryKeyRelatedField(
many=False, queryset=Question.objects.all()
)
class Meta:
model = Answer
fields = ("id", "answer", "question")
class AnswerViewSet(ModelViewSet):
queryset = Answer.objects.all()
serializer_class = AnswerSerializer
filter_fields = ("question", "answer")
Run Code Online (Sandbox Code Playgroud)
小智 26
很遗憾,您提供和接受的答案无法回答您的原始问题,因为它不会更新模型.然而,这可以通过另一种便利方法轻松实现:update-or-create
def create(self, validated_data):
answer, created = Answer.objects.update_or_create(
question=validated_data.get('question', None),
defaults={'answer': validated_data.get('answer', None)})
return answer
Run Code Online (Sandbox Code Playgroud)
这应该Answer在数据库中创建一个对象,如果一个对象question=validated_data['question']不存在并且答案取自validated_data['answer'].如果它已经存在,django会将其answer属性设置为validated_data['answer'].
正如Nirri的回答所指出的,这个函数应该驻留在序列化器中.如果您使用通用ListCreateView,它将在发送发布请求后调用create函数并生成相应的响应.
Dam*_*nic 13
@Nirri发布的答案对我有帮助,但我发现使用Django QuerySet API快捷方式更优雅的解决方案:
def create(self, validated_data):
answer, created = Answer.objects.get_or_create(
question=validated_data.get('question', None),
defaults={'answer': validated_data.get('answer', None)})
return answer
Run Code Online (Sandbox Code Playgroud)
它不完全一样的东西-如果Answer到Question不存在的,它会被创建,否则-返回是question现场查询.
但是,此快捷方式不会更新对象.QuerySet API有另一种update操作方法,它被调用update_or_create并在线程中的其他答案中发布.
我会使用序列化程序的 create 方法。
在其中,您可以检查问题(使用您在“问题”主键相关字段中提供的 ID)是否已经有答案,如果有,则获取对象并更新它,否则创建一个新的。
因此,第一个选项将类似于:
class AnswerSerializer(serializers.ModelSerializer):
question = serializers.PrimaryKeyRelatedField(many=False, queryset=Question.objects.all())
class Meta:
model = Answer
fields = (
'id',
'answer',
'question',
)
def create(self, validated_data):
question_id = validated_data.get('question', None)
if question_id is not None:
question = Question.objects.filter(id=question_id).first()
if question is not None:
answer = question.answer
if answer is not None:
# update your answer
return answer
answer = Answer.objects.create(**validated_data)
return answer
Run Code Online (Sandbox Code Playgroud)
第二种选择是检查具有答案 ID 的答案是否存在。
除非您使用某种解决方法并将它们手动定义为 read_only = false 字段,否则应答 ID 不会显示在已验证的 post 请求数据中:
id = serializers.IntegerField(read_only=False)
Run Code Online (Sandbox Code Playgroud)
但是您应该重新考虑这一点, PUT 方法和 POST 方法作为单独的实体存在是有充分理由的,您应该将前端的请求分开。
一个更通用的答案,我认为这应该在视图集中而不是序列化器中,因为序列化器只需要序列化,仅此而已。
这模拟的条件update从传递IDrequest.data来kwargs,所以如果实例不存在,则UpdateModelMixin.update()提出了一个Http404由该抓except块,并呼吁例外create()。
from rest_framework.mixins import UpdateModelMixin
from django.http import Http404
class AnswerViewSet(UpdateModelMixin, ModelViewSet):
queryset = Answer.objects.all()
serializer_class = AnswerSerializer
filter_fields = ("question", "answer")
update_data_pk_field = 'id'
def create(self, request, *args, **kwargs):
kwarg_field: str = self.lookup_url_kwarg or self.lookup_field
self.kwargs[kwarg_field] = request.data[self.update_data_pk_field]
try:
return self.update(request, *args, **kwargs)
except Http404:
return super().create(request, *args, **kwargs)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
23528 次 |
| 最近记录: |