Django. Сохранение данных из модальной формы в БД
Учусь работать с Django, и в процессе создания приложения столкнулся со следующей проблемой. Есть три модели (Object, Staff, Work), одна из них (Work) посредством FK связана с двумя другими. Также есть шаблон формы для создания записи в таблице Work. В таком виде всё прекрасно работает. Однако, мне захотелось прикрутить модальное окно для вызова упомянутой формы. Собственно, тут я и сталкиваюсь с тем, что не вполне понимаю, как именно передать данные для FK из шаблона в БД посредством POST и вывести их в таблицу на фронте. Уточнение_1: данные для CharField и т.п. передаются и выводятся корректно, проблема только с FK. Уточнение_2: записывать данные в связанные таблицы не требуется, нужно только вывести их значение, выбранное в шаблоне.
UPD: В данный момент получаю такую ошибку: NOT NULL constraint failed: mip_apps_work.work_office_id
Привожу код.
Модели:
class Object(models.Model):
object_name = models.CharField(max_length = 50, default = '',
verbose_name = 'Объект', unique = True)
object_address = models.CharField(max_length = 100, default = '',
verbose_name = 'Адрес', blank = True)
object_contacts = models.TextField(verbose_name = 'Контакты', default = '',
blank = True)
class Meta():
ordering = ['object_name']
def __str__(self):
return f'{self.object_name}'
class Staff(models.Model):
surname = models.CharField(max_length = 30, default = '',
verbose_name = 'Фамилия', blank = True, null = True)
name = models.CharField(max_length = 30, default = '',
verbose_name = 'Имя', blank = True, null = True)
patronymic = models.CharField(max_length = 30, default = '',
verbose_name = 'Отчество', blank = True, null = True)
def __str__(self):
return self.surname + ' ' + self.name + ' ' + self.patronymic
class Work(models.Model):
NONE = ''
STARTED = 'В работе'
PLANNED = 'Запланировано'
COMPLETED = 'Выполнено'
CANCELLED_BY_INITIATOR = 'Отменено инициатором'
PAUSE = 'Пауза'
WORK_STATUS_CHOICES = [(NONE, ''), (STARTED, 'В работе'),
(PLANNED, 'Запланировано'), (COMPLETED, 'Выполнено'),
(CANCELLED_BY_INITIATOR, 'Отменено инициатором'), (PAUSE, 'Пауза')]
work_office = models.ForeignKey(Object, on_delete = models.CASCADE,
default = '', verbose_name = 'Объект')
work_status = models.CharField(max_length = 22,
choices = WORK_STATUS_CHOICES, default = '', verbose_name = 'Статус',
blank = True)
work_start_date = models.DateField(default = datetime.date.today().strftime('%Y-%m-%d'),
verbose_name = 'Дата начала', blank = True, null = True)
work_finish_date = models.DateField(default = datetime.date.today().strftime('%Y-%m-%d'),
verbose_name = 'Дата завершения', blank = True, null = True)
work_description = models.TextField(verbose_name = 'Описание работ',
default = '', blank = True, null = True)
work_executor = models.ForeignKey(Staff, on_delete = models.CASCADE,
default = '', verbose_name = 'Исполнитель', blank = True, null = True)
work_sz_number = models.CharField(max_length = 15,
verbose_name = 'Номер СЗ', default = '',blank = True)
work_sd_number = models.CharField(max_length = 15,
verbose_name = 'Номер в SD', default = '',blank = True)
def __str__(self):
return f'{self.work_description} '
Представления:
class WorkListView(ListView):
model = Work
template_name = 'mip_apps/works_list.html'
context_object_name = 'works_list'
class WorkCreateView(CreateView):
model = Work
template_name = 'mip_apps/create_works_form.html'
fields = ['work_office', 'work_status', 'work_start_date',
'work_finish_date', 'work_description', 'work_executor', 'work_sz_number',
'work_sd_number']
success_url = reverse_lazy('table')
def addWork(request):
if request.method == 'POST':
work = Work.objects.get_or_create(
work_office = request.POST.get('work_office.object_name'),
work_status = request.POST.get('work_status'),
work_start_date = request.POST.get('work_start_date'),
work_finish_date = request.POST.get('work_finish_date'),
work_description = request.POST.get('work_description'),
work_executor = request.POST.get('work_executor_surname'),
work_sz_number = request.POST.get('work_sz_number'),
work_sd_number = request.POST.get('work_sd_number')
)
print(work)
works = Work.objects.all();
return render(request, 'mip_apps/works_list.html')
URLS:
# Список текущих работ.
path('works_list/', views.WorkListView.as_view(), name = 'works_list'),
# Форма создания работ.
path('create_work/', views.WorkCreateView.as_view(), name='create_work'),
# Форма редактирования работ.
path('update_work/<pk>', views.WorkUpdateView.as_view(), name='update_work'),
# Форма удаления работ.
path('delete_work/<pk>', views.WorkDeleteView.as_view(), name='delete_work'),
path('works_list/ajax/table', views.addWork, name='table'),
Кнопка вызовы модальной формы и скрипт:
<a class="contact" href="#" data-form="{% url 'create_work' %}" data-target="{% url 'create_work' %}" title="Edit">edit</a>
<div class="modal hide" id="contactModal">
</div>
<script>
$(".contact").click(function(ev) { // for each edit contact url
ev.preventDefault(); // prevent navigation
var url = $(this).data("form"); // get the contact form url
$("#contactModal").load(url, function() { // load the url into the modal
$(this).modal('show'); // display the modal on url load
});
return false; // prevent the click propagation
});
$('.contact-form').live('submit', function() {
$.ajax({
type: $(this).attr('method'),
url: this.action,
data: $(this).serialize(),
context: this,
success: function(data, status) {
$('#contactModal').html(data);
}
});
return false;
});
</script>
Шаблон создания записи:
<div class="align-baseline w-25 mb-3 mx-auto bg-white">
<form method="post" action="ajax/table">
<div class="modal-header">
<h3>Добавить задачу</h3>
<button type="button" class="close" data-dismiss="modal">×</button>
</div>
<div class="modal-body">
{% csrf_token %}
{{ form.work_start_date|date:'d-m-Y' }}
<table>{{ form|crispy }}</table>
</div>
<div class="modal-footer">
<input class="btn btn-primary" type="submit" value="Добавить" />
<input class="btn btn-danger" class="close" name="cancel" type="submit" value="Отменить" />
</div>
</form>
</div>
Если я правильно понимаю концепцию, то мне требуется определить id связанной записи и записать его в БД Work. Однако, как это правильно реализовать - не пойму. Мануалы курил, перегуглил несколько десятков аналогичных проблем. Просветите, пожалуйста, как решить вопрос!
Проблемав том, как вы используете поле work_office
из формы в обработчике POST, вот тут:
work_office=request.POST.get('work_office.object_name')
В поле формы хранится идентификатор сущности Object
и, чтоб по идентификатору достать сам объект нужно сделать запрос с БД:
work_office=Object.objects.get(id=request.POST.get('work_office'))
Object.objects.get(id=...)
достает из БД объект по полю id
, а id
мы берем из параметра, который пришел в запросе.
как правильно сделать редирект на /works_list
Используйте redirect:
from django.shortcuts import redirect
if request.method == 'POST':
work = Work.objects.get_or_create(
...
)
return redirect("works_list") # works_list - это name из маппинга в urls.py