Получение плохого запроса от 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, так что, возможно, я делаю все совершенно неправильно.