Получение плохого запроса от POST к модели DailyWc с внешним ключом к проектам

Я делаю приложение для написания текстов, используя Django backend и Vue 2 frontend. У меня есть две модели - DailyWc и Project. Каждый день, когда пользователь заходит на сайт, для него создается новый день для хранения текста (DailyWc обрабатывает это). Я хотел, чтобы пользователь также мог назначить текст проекту, при этом по умолчанию он должен быть "Не назначен". Таким образом, проект ассоциируется с несколькими dailywc.

На моем сайте есть кнопка, которую пользователь может нажать, чтобы сохранить свой прогресс за день. Вот здесь-то и возникает проблема - я не могу сделать вызов post или update, потому что получаю Bad Request. Я понимаю, что должен быть в состоянии просто передать связанный идентификатор проекта, чтобы заставить это работать, но я думаю, что модель DailyWc в ее нынешнем виде ожидает целый объект Project с соответствующими полями.

Мои модели:

# Create your models here.
class Project(models.Model):
    name = models.CharField(max_length=255, default="Unassigned")
    start_date = models.DateField("today's date", default=datetime.date.today)
    end_date = models.DateField("end date", default=datetime.date.today)
    word_count_goal = models.PositiveIntegerField(default=0)


    def __str__(self) -> str:
        return f'The Project {self.name} started on {self.start_date} and will end on {self.end_date} with a goal of {self.word_count_goal} and an id of {self.id}.'


class DailyWc(models.Model):
    # would reference the 'id' field in the Project model. db_index=True: foreign key index
    project = models.ForeignKey(Project, default=None, on_delete=models.CASCADE, db_index=True) # each DailyWc instance is associated with a single Project instance, and each Project instance can have multiple DailyWc instances associated with it.
    user = models.ForeignKey(User, on_delete=models.CASCADE) # A user can be associated with multiple daily wordcounts
    todays_wc = models.IntegerField(default=0)
    text_area = models.CharField(max_length=500000, blank=True, default='Text here.') # Save the text area each day so the user can access that page and see it.
    date = models.DateField("today's date", default=datetime.date.today)
    accessed_today = models.BooleanField(default=False)
    daily_goal = models.IntegerField(default=0)
    daily_goal_bool = models.BooleanField(default=False)
    
    
    def __str__(self) -> str:
        return f'{self.user} wrote {self.todays_wc} words on {self.date} for Project {self.project}.'

Функция в моем app.js, которая вызывается для обработки post и put: (Для этого примера я просто жестко закодировал id для 'project', но у меня есть способ получить доступ к фактическому номеру)

     createUpdate(wcId) {
            // If this is false AND it's today's date.
            // Means you didn't access it today yet and can create a new instance.
            if (!this.accessedToday && this.todaysDate == `${new Date().toLocaleDateString('en-CA')}`) 
            {axios.post('/apis/v1/new/', {
                'project': 17,
                'todays_wc': this.dailyWC,
                etc...
                // doesn't include date here because it is set to default datetime.date.today in models
            }, {
                headers: { 'X-CSRFToken': this.csrfToken }
            }).then(response => {
                this.getWc()
            })} else {
                axios.put(`/apis/v1/${wcId}/`, {
                    'project': 17,
                    'todays_wc': this.dailyWC,
                    etc...
            }, {
                headers: { 'X-CSRFToken': this.csrfToken }
            }).then(res => this.getWc())
            console.log("Was accessed today.")}
        }
    }

Мои сериализаторы:

class ProjectSerializer(serializers.ModelSerializer):
    class Meta:
        model = Project
        fields = (
            'name',
            'start_date',
            'end_date',
            'word_count_goal',
            'id',
        )


class DailyWcSerializer(serializers.ModelSerializer):
    project = ProjectSerializer(required=False)

    class Meta:
        model = DailyWc
        fields = (
            'project',
            'user',
            'daily_goal',
            'daily_goal_bool',
            'todays_wc',
            'text_area',
            'date',
            'accessed_today',
            'id',
        )

    # For the nested serializer to be writable, you'll need to create create() and/or update() methods
    # to explicitly specify how the child relationships should be saved.
    def update(self, instance, validated_data):
        print(validated_data)
        project_data = validated_data.pop('project', {})
        project = instance.project

        if project_data:
            project_serializer = ProjectSerializer(instance.project, data=project_data)
            if project_serializer.is_valid():
                project = project_serializer.save()
        instance.project = project
        instance.todays_wc = validated_data.get('todays_wc', instance.todays_wc)
        # assigning all my values manually using this same process...
        ...
        instance.save()
        return instance

    def create(self, validated_data):
        # have a project object on it. Get project off using id
        project_data = validated_data.pop('project', None)
        print(validated_data)
        if project_data is None:
            project, created = Project.objects.get_or_create(name='name')
        else:
            project = Project.objects.get(id=project_data['id'])
            project = Project.objects.create(**project_data)
        daily_wc = DailyWc.objects.create(project=project, **validated_data)
        return daily_wc

Является ли вложенный сериализатор причиной моих проблем? Я думаю, что дело может быть в сериализаторе. Я все еще новичок в Django REST framework, поэтому я не уверен, как еще это сделать, чтобы убедиться, что я получаю правильные данные проекта.

Также для развлечения, мой views.py

# path('new/', AddWc.as_view()),
class AddWc(generics.CreateAPIView):
    serializer_class = DailyWcSerializer

# path('<int:pk>/', WcView.as_view()),
class WcView(generics.RetrieveUpdateDestroyAPIView):
    queryset = DailyWc.objects.all()
    serializer_class = DailyWcSerializer

И мой urls.py

    # The option to add a new wordcount will be at apis/v1/new/
    path('new/', AddWc.as_view()),
    # get, put, and delete and accessing via primary key (e.g. apis/v1/200)
    path('<int:pk>/', WcView.as_view()),

Я попробовал ввести id проекта в вызове axios в post, и он возвращает Bad Request: apis/v1/new. Я попробовал жестко закодировать проект следующим образом:

 {axios.post('/apis/v1/new/', {
                'project': {
                     'id': 16,
                     'name': 'This is a post.',
                     'start_date': '2023-02-04',
                     'end_date': '2023-02-04',
                     'word_count_goal': 400,
                 },
                 ...

И это возвращает ошибку:

    project = Project.objects.get(id=project_data['id'])
KeyError: 'id'

Который, как я должен предположить, исходит от моего сериализатора.

Если я удалю функцию ручного создания, которую я сделал в своем сериализаторе, я получу эту ошибку:

AssertionError: The `.create()` method does not support writable nested fields by default.
Write an explicit `.create()` method for serializer `apis.serializers.DailyWcSerializer`, or set `read_only=True` on nested serializer fields.

До этого у меня все работало в некоторой степени, но все же не так, как я хотел. Извините, если это очень запутанно. Я все еще изучаю, как работает REST Framework, и это мой первый раз, когда я работаю с ForeignKey, так что, возможно, я делаю все совершенно неправильно.

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