Ошибка отказа ограничения NOT NULL при попытке сохранения с помощью createview
Это мое первое сообщение в SO, поэтому, пожалуйста, дайте мне знать, если я упустил какие-либо важные детали. Я работаю над обновлениями домашней системы продажи билетов на базе dJango.
У меня есть две "родительские" модели (ParentProjects и Projects), которые фиксируют детали о работе, которую мы хотим отслеживать. Обе модели имеют ряд столбцов, которые хранят информацию в связанных таблицах, а также некоторые отношения FK.
Для просмотра объектов в таблице Project используется общее детальное представление на основе классов, а для доступа к таблице ParentProject используется представление на основе функций. Представление на основе функций выполняет ту же задачу по загрузке значений объектов родительского проекта, что и детальное представление на основе классов для объектов проекта.
Проблема, с которой я сталкиваюсь, заключается в том, что я не могу добавить новую запись в модель IDTasks, которая автоматически вставляет идентификатор родительского проекта. Я могу добавить новую IDTask из сайта администратора (или из сайта "клиента", если я включу поле "родитель" в форме модели), вручную выбрав родителя, с которым я хочу связать IDTask. Я также могу редактировать и сохранять существующую IDTask из детального представления родительского проекта без каких-либо проблем. Однако, когда я пытаюсь добавить IDTask с помощью createview, dJango сообщает об ошибке ограничения Not NULL и новая запись не сохраняется.
В дополнение к рассмотрению и опробованию многих других решений этой проблемы, я отключил код, который автоматически добавляет идентификатор вошедшего пользователя, но все еще получаю ту же ошибку null constraint. Странно то, что я использую те же базовые структуры createview для добавления объектов FK в модель Projects, и это прекрасно работает. Я все еще осваиваюсь с представлениями Django, основанными на классах, поэтому наверняка упускаю что-то очевидное.
Спасибо за помощь!
Вот основные мнения, связанные с моим вопросом:
# Detail view for Parent Projects (function-based)
def ParentProjectDetail(request,parent_id):
parents = ParentProject.objects.get(id=parent_id)
projects = Project.objects.filter(parent_project__pk=parent_id).order_by('project_phase', '-launch_date',)
return render(request, 'otis/parent_detail.html', context={'parents':parents, 'projects':projects })
# Detail View for Projects (class-based)
class ProjectDetailView(generic.DetailView):
model = Project
context_object_name = 'project'
template_name = 'otis/project_detail.html'
# Add parent progress report
class add_idtask_view(SuccessMessageMixin, CreateView):
model = IDTasks
template_name = 'otis/id_report_form.html'
form_class = idTaskForm
success_message = "Report added"
def form_valid(self, form):
idtaskform = form.save(commit=False)
idtaskform.user = self.request.user
self.parents_id = self.kwargs.get('parent_id')
form.instance.ParentProject = get_object_or_404(ParentProject,id=self.parents_id)
return super(add_idtask_view, self).form_valid(form)
def get_success_url(self):
return reverse_lazy('otis:parent_detail', kwargs={'pk': self.parents_id})
Вот форма модели:
class idTaskForm(ModelForm):
class Meta:
model = IDTasks
fields = ('parent_phase','complete','milestones','nextsteps','concerns')
widgets = {
'milestones': Textarea(attrs={'cols': 50, 'rows': 5, 'placeholder': 'Task details...'}),
'nextsteps': Textarea(attrs={'cols': 50, 'rows': 5, 'placeholder': 'Task details...'}),
'concerns': Textarea(attrs={'cols': 50, 'rows': 5, 'placeholder': 'Task details...'}),
}
labels = {
'parent_phase': mark_safe('<span class="required">Phase</span>'),
'complete': mark_safe('<span class="required">Percentage Complete</span>'),
'milestones': ('Milestones'),
'nextsteps': ('Next steps'),
'concerns': ('Concerns'),
}
Вот две модели, к которым осуществляется доступ:
# Parent Project Model
class ParentProject(models.Model):
class Meta:
verbose_name = "parent project"
verbose_name_plural = "parent projects"
ordering = ['title']
title = models.CharField('Name', max_length=100, null=True, blank=False)
parent_group = models.ForeignKey(ProjectGroups, on_delete=models.CASCADE, blank=True, null=True)
parent_type = models.ForeignKey(ProjectTypes, on_delete=models.CASCADE, null=True, blank=False)
description = models.TextField('description', blank=True)
term_due = models.ForeignKey(Terms, on_delete=models.CASCADE, blank=True, null=True)
term_year_due = models.ForeignKey(Years, on_delete=models.CASCADE, blank=True, null=True)
launch_date = models.DateField('launch date', blank=True, null=True)
parent_phase = models.ForeignKey(SDLCPhases, on_delete=models.CASCADE, null=True, blank=False)
history = HistoricalRecords()
def __str__(self):
return str(self.title)
def get_absolute_url(self):
return reverse('otis:parent_detail', kwargs={'pk': self.pk})
# Reports Model
class IDTasks(models.Model):
class Meta:
verbose_name = "Parent task"
verbose_name_plural = "Parent tasks"
ordering = ['updated_on']
parent = models.ForeignKey(ParentProject, on_delete=models.CASCADE)
parent_phase = models.ForeignKey(SDLCPhases, on_delete=models.CASCADE, null=True, blank=False)
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
complete = models.IntegerField('percentage complete', blank=True, null=True, default=0)
milestones = models.TextField('milestones', blank=True)
nextsteps = models.TextField('next steps', blank=True)
concerns = models.TextField('concerns', blank=True)
updated_on = models.DateTimeField(auto_now_add=True, null=True)
history = HistoricalRecords()
def __str__(self):
return str(self.complete)
Вот шаблоны url:
# url for the parent project detail view
path('parent_detail/<int:parent_id>/', views.ParentProjectDetail, name='parent_detail'),
# url for the create report accessed within the detail view
path('parent_detail/<int:parent_id>/add_id_report/', views.add_idtask_view.as_view(), name='add_id_report'),
Наконец, ссылка на шаблон, вызывающая модель формы:
<a href="{% url 'otis:add_id_report' parents.id %}">link_title</a>
Возможно, я написал слишком рано (конечно, от разочарования, пытаясь заставить это работать в течение примерно одного дня). Во всяком случае, я смог решить свою первоначальную проблему, перестроив представление следующим образом:
class add_idtask_view(SuccessMessageMixin, CreateView):
model = IDTasks
template_name = 'otis/id_report_form.html'
form_class = idTaskForm
success_message = "Report added"
def form_valid(self, form):
parents_pid = self.kwargs.get('parent_pid')
self.parent_id = parents_pid
form.instance.user = self.request.user
form.instance.parent_id = parents_pid
return super(add_idtask_view, self).form_valid(form)
def get_success_url(self):
return reverse_lazy('otis:parent_detail', kwargs={'parent_pid': self.parent_id})
Первое, что я сделал, это разобрался, к каким полям формы и полям базы данных я пытался получить доступ. Похоже, я перепутал их и не сослался на них должным образом в своем первоначальном представлении.
После того, как они заработали, я начал получать ошибку, в которой говорилось, что представление ожидает целое число, но получает строку. Похоже, по какой-то причине, когда я использовал метод get_object_or_404, представление возвращало название объекта базы данных, а не первичный ключ.
Меня устраивает решение, которое я создал, но я был бы признателен за предложения по его улучшению и объяснение того, почему метод get_object_or_404 не сработал для меня.
Спасибо, что нашли время для рассмотрения моего вопроса.