NOT NULL 约束失败:core_question.poll_id 错误

时间:2021-07-15 18:50:17

标签: python-3.x django api rest django-rest-framework

我在 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"),
]

1 个答案:

答案 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

我强烈建议您阅读所有官方教程