我在 Django 中遇到了 POST 方法的问题。 项目的核心理念是进行民意调查,在民意调查中添加问题,并为每个问题添加答案。
我确实做到了这一切。而且我的 API 很少:
获取:http://127.0.0.1:8000/poll/
显示数据库中所有创建的民意调查
获取:http://127.0.0.1:8000/poll/{poll_name}/
poll_name -> 天气(例如)显示所有问题、所有答案和正确答案
发布:http://127.0.0.1:8000/api/token/
如果管理员凭据正确,则提供授权令牌。 (用户名:admin,密码:admin)
但现在我需要 API 来添加、删除、更新投票、问题和答案。
我确实先尝试了问题:
class Questions(APIView):
def get(self, request, format=None, **kwargs):
question = Question.objects.filter(poll__title=kwargs['topic'])
serializer = QuestionSerializer(question, many=True)
return Response(serializer.data)
def post(self, request, format=None, **kwargs):
serializer = QuestionSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
但我收到错误:NOT NULL 约束失败:core_question.poll_id 错误
我确实尝试在 Internet 上搜索它,它说我没有请求正确的参数。 我确实尝试了 100 个变体,但仍然找不到问题所在。
这是项目的 Github 链接:https://github.com/NeoVic2006/Polls_with_questions_answers
请检查一下,让我知道问题出在哪里。 请具体说明,因为我对 Django 没有真正的经验。
谢谢,
附:
我的序列化:
from rest_framework import serializers
from .models import Answer, Polls, Question
class PollSerializer(serializers.ModelSerializer):
class Meta:
model = Polls
fields = [
'title',
]
class AnswerSerializer(serializers.ModelSerializer):
class Meta:
model = Answer
fields = [
'id',
'answer_text',
'is_right',
]
class QuestionSerializer(serializers.ModelSerializer):
answer = AnswerSerializer(many=True, read_only=True)
class Meta:
model = Question
fields = [
'title',
'answer'
]
我的模型:
from django.db import models
from django.db.models.deletion import DO_NOTHING
class Polls(models.Model):
class Meta:
verbose_name = 'Poll'
verbose_name_plural = 'Polls'
ordering = ['id']
name = models.CharField(max_length=255)
title = models.CharField(max_length=255, default="New Poll", verbose_name="Poll Title")
date_created = models.DateTimeField(auto_now_add=True)
date_over = models.DateTimeField(auto_now=True)
description = models.CharField(max_length=255)
def __str__(self):
return self.name
class Question(models.Model):
class Meta:
verbose_name = 'Question'
verbose_name_plural = 'Questions'
ordering = ['id']
TYPE = (
(0, 'Text'),
(1, 'Single Choise'),
(2, 'Multiple Choise')
)
poll = models.ForeignKey(Polls, related_name='question', on_delete=DO_NOTHING)
title = models.CharField(max_length=255, verbose_name="Title")
technique = models.IntegerField(choices=TYPE, default=0, verbose_name="Type of question")
def __str__(self):
return self.title
class Answer(models.Model):
class Meta:
verbose_name = 'Answer'
verbose_name_plural = 'Answers'
ordering = ['id']
question = models.ForeignKey(Question, related_name='answer', on_delete=DO_NOTHING)
answer_text = models.CharField(max_length=255, verbose_name="Answer text")
is_right = models.BooleanField(default=False)
def __str__(self):
return self.answer_text
核心网址:
from django.contrib import admin
from django.urls import path, include
from rest_framework.authtoken.views import obtain_auth_token
urlpatterns = [
path('api-auth/', include('rest_framework.urls')),
path('admin/', admin.site.urls),
path('api/token/', obtain_auth_token, name='obtain-token'),
path('poll/', include('core.urls', namespace='poll'))
]
应用中的网址:
from django.urls import path, include
from .views import Poll, Questions
app_name ="Poll"
urlpatterns = [
path('', Poll.as_view(), name="Poll"),
path('<str:topic>/', Questions.as_view(), name="question"),
]
答案 0 :(得分:0)
我已经克隆了您的存储库并进行了这些更改
在models.py中
class Question(models.Model):
# ... keep as is, just changed the poll
poll = models.ForeignKey(Polls, related_name='question', on_delete=DO_NOTHING, null=True, blank=True) #blank=True is there so you can make it work on the admin interface
在views.py中
class Questions(APIView):
# .. everything before this is as is
def post(self, request, format=None, **kwargs):
title = kwargs['topic'] # extract the title from the url
serializer = QuestionSerializer(data={**request.data, 'title':title}) # create a new serializer with the data you have + adding the title
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
这会起作用,但是这不是完成此任务的正确方法。
端点不应该那样使用,REST 端点通常是这样的
# this end point would list all the questions if called with `get` and would be used to create a new question if called with `post`
path('question/', Questions.as_view(), name="question"),
# this end point would display the question with the provided topic if called with `get` and would be used to update it called with `patch` or `put`
path('question/<str:topic>/', QuestionDetail.as_view(), name="questionDetail"),
在您的情况下,有一个列出所有问题的端点是没有意义的,但您应该使用该 url 来创建问题,或者您可以让 /poll/
端点负责创建一个包含所有问题的投票来自一个请求的问题和答案。
为了简化操作,您可以使用 generic APIViews provided by DRF
具体看一下:
这是来自官方教程展示和如何使用它的示例 https://www.django-rest-framework.org/tutorial/3-class-based-views/#using-generic-class-based-views
我强烈建议您阅读所有官方教程