Поле 'id' ожидало число, но получило dict при загрузке базы данных django

Я ищу способ сохранить вопрос, полученный из внешнего API, в модели Question. Мой модуль views.py делает это, запрашивая данные, основанные на выборе пользователем сложности вопроса, а затем отображает полученное в форме. Это довольно простой метод, но по какой-то причине я получаю Field 'id' expected a number but got {'type': 'multiple'...}.

Я удалил код, который предназначался для создания синглтона другой модели, который мешал этой реализации из последнего ответа на этот вопрос. Затем я запустил ./manage.py makemigrations и ./manage.py migrate, чтобы отразить изменения, но исключение снова возникло. После этого я удалил migrations.py и их кэшированные файлы, чтобы запустить те же две команды, и ничего не изменилось.

Может ли кто-нибудь указать, что я упускаю или делаю неправильно?

models.py

from django.db import models


class Question(models.Model):
    type = models.TextField()
    difficulty = models.TextField()
    category = models.TextField()
    question = models.TextField()
    correct_answer = models.TextField()
    incorrect_answers = models.TextField()

views.py

from django.shortcuts import render, HttpResponse
from .forms import QuestionForm, QuestionLevelForm
from urllib.request import URLError
from .models import Question
import requests

def process_question(request):
    if "level" in request.POST:
        return fetch_question(request)
    elif "answer" in request.POST:
        return check_answer(request)
    else:
        form = QuestionLevelForm()
        return render(request, "log/question.html", {"form": form})


def fetch_question(request):
    match request.POST["difficulty"]:
        case "easy":
            url = "https://opentdb.com/api.php?amount=1&category=9&difficulty=easy&type=multiple"
        case "medium":
            url = "https://opentdb.com/api.php?amount=1&category=9&difficulty=medium&type=multiple"
        case "hard":
            url = "https://opentdb.com/api.php?amount=1&category=9&difficulty=hard&type=multiple"

    try:
        response = requests.get(url)
    except URLError as e:
        HttpResponse("Couldn't fetch data, try again")
    else:
        render_question(request, response.json())


def render_question(request, response):
    content = response["results"][0]
    question = {
        "type": content["type"],
        "difficulty": content["difficulty"],
        "category": content["category"],
        "question": content["question"],
        "correct_answer": content["correct_answer"],
        "incorrect_answers": content["incorrect_answers"],
    }
    form = QuestionForm(question)
    model = Question(question)
    model.save()
    context = {"question": question, "form": form}
    render(request, "./log/templates/log/question.html", context)

test_views.py

from django.http import HttpRequest
from django.test import TestCase, Client
from .. import views

client = Client()


class QuestionTest(TestCase):
    def test_page_load(self):
        response = self.client.get("/log/question")
        self.assertEqual(response["content-type"], "text/html; charset=utf-8")
        self.assertTemplateUsed(response, "log/question.html")
        self.assertContains(response, "Choose your question level", status_code=200)

    def test_fetch_question(self):
        request = HttpRequest()
        request.method = "POST"
        request.POST["level"] = "level"
        request.POST["difficulty"] = "hard"
        request.META["HTTP_HOST"] = "localhost"
        response = views.process_question(request)
        self.assertEqual(response.status_code, 200)

When using model constructor, use keyword arguments! [1]

С помощью аргументов-ключей можно указать, каким аргументам вы присваиваете значение. Например:

Question(
    type = content["type"],
    difficulty = content["difficulty"],
    category = content["category"],
    question = content["question"],
    correct_answer = content["correct_answer"],
    incorrect_answers = content["incorrect_answers"]
)

Вы также можете использовать dict распаковку для построения Question. При этом аргументы будут получены автоматически:

Question(**question)

[1] In your example, the constructor of the class Question takes question which is a dict and assigns this to its first argument id.

Вернуться на верх