Как на основе заполнения одной формы и передачи данных в одну модель, передать часть данных в другую?
Я новичок в Django, поэтому если не трудно я бы хотел получить более подробное разъяснение или ссылку на него. У меня есть две модели, статус АСК и компьютер. Между собой они связанный типом "Один к одному". Когда я заполняю объект модели "Статус АСК", у него в поле "компьютер" предлагается выбрать связанный с ним номер компьютера из модели "Компьютер". То есть одному месту соответствует только один номер компьютера ( в самой модели "Компьютер" хранится полная конфигурация компа). Но что если при заполнении формы необходимо указать тот компьютер, которого нет в базе. Вот тут мне и нужна помощь, нужно предложить пользователю выбрать ЛИБО НЕ занятый компьютер (то есть тот, который ещё не привязан к "статус АСК") либо создать свой собственный, то есть необходимо подтвердить валидность формы, записать данные в модель "Статус АСК" и при этом создать новую записать в модели "Компьютер" ( очевидно все колонки кроме номера будут пусты и дальше пользователь сам заполняет данный компьютер). Как это реализовать? Ниже приведён код:
forms.py:
class ComputerForm(ModelForm):
class Meta:
model = Computer
fields = ["number", "CPU", "RAM", "Power_unit",
"Mother_board", "ISA_port", "LPT_port",
"COM_port", "PCI_slot", "PCI_express_slot",
"Data_storage_device", "video_card", "object_place",
"object_work", ]
widgets = {
"number": TextInput(attrs={
'class': 'form-control',
}),
"CPU": TextInput(attrs={
'class': 'form-control',
}),
"RAM": TextInput(attrs={
'class': 'form-control',
}),
"Power_unit": TextInput(attrs={
'class': 'form-control',
}),
"Mother_board": TextInput(attrs={
'class': 'form-control',
}),
"PCI_slot": forms.Select(attrs={
'class': 'form-control',
'title': 'Наличие PCI порта (Да/Нет)'
}),
"PCI_express_slot": forms.Select(attrs={
'class': 'form-control',
'title': 'Наличие PCI порта (Да/Нет)'
}),
"ISA_port": forms.Select(attrs={
'class': 'form-control',
'title': 'Наличие PCI порта (Да/Нет)'
}),
"LPT_port": forms.Select(attrs={
'class': 'form-control',
'title': 'Наличие PCI порта (Да/Нет)'
}),
"COM_port": forms.Select(attrs={
'class': 'form-control',
'title': 'Наличие PCI порта (Да/Нет)'
}),
"Data_storage_device": TextInput(attrs={
'class': 'form-control',
}),
"video_card": TextInput(attrs={
'class': 'form-control',
}),
"object_place": TextInput(attrs={
'class': 'form-control',
}),
"object_work": TextInput(attrs={
'class': 'form-control',
}),
}
class StatusForm(ModelForm):
class Meta:
model = ASKstatus
fields = ["number", "ASK_number", "name", "product_name", "note", "comps_to_work"]
widgets = {
"number": TextInput(attrs={
'class': 'form-control',
'placeholder': '№ п/п'
}),
"ASK_number": TextInput(attrs={
'class': 'form-control',
'placeholder': '№ АСК'
}),
"name": TextInput(attrs={
'class': 'form-control',
'placeholder': 'Название'
}),
"product_name": TextInput(attrs={
'class': 'form-control',
'placeholder': 'Изделие'
}),
"note": TextInput(attrs={
'class': 'form-control',
'placeholder': 'Примечание'
}),
"comps_to_work": TextInput(attrs={
'class': 'form-control',
'placeholder': 'Номер компьютера'
})
}
models.py:
class Computer(models.Model):
CHOICES = [
('Да', 'Да'),
('Нет', 'Нет'),
]
number = models.CharField('Номер компьютера', max_length=6, blank=True)
CPU = models.CharField('Процессор', max_length=50, blank=True)
RAM = models.TextField('Оперативная память', max_length=200, blank=True)
Power_unit = models.CharField('Блок питания', max_length=50, blank=True)
Mother_board = models.CharField('Материнская плата', max_length=100, blank=True)
PCI_slot = models.CharField('PCI слот', max_length=3, blank=True, choices=CHOICES)
PCI_express_slot = models.CharField('PCI express слот', max_length=3, blank=True, choices=CHOICES)
ISA_port = models.CharField('ISA порт', max_length=3, blank=True, choices=CHOICES)
LPT_port = models.CharField('LPT порт/параллельный порт', max_length=3, blank=True, choices=CHOICES)
COM_port = models.CharField('COM порт/последовательный порт', max_length=3, blank=True, choices=CHOICES)
Data_storage_device = models.CharField('Устройство хранения данных', max_length=100, blank=True)
video_card = models.CharField('Видеокарта', max_length=100, blank=True)
object_place = models.CharField('Место положения', max_length=200, blank=True)
object_work = models.CharField('Рабочее место', max_length=200, blank=True, null=True)
def __str__(self):
return f'{self.number}'
class Meta:
verbose_name = 'Компьютер'
verbose_name_plural = 'Компьютеры'
class ASKstatus(models.Model):
number = models.CharField('№ п/п', max_length=10, blank=True)
ASK_number = models.CharField('№ АСК',max_length=10, blank=True)
name = models.CharField('Название', max_length=100, blank=True)
product_name = models.CharField('Изделие', max_length=100, blank=True)
note = models.CharField('Примечание', max_length=100, blank=True)
comps_to_work = models.OneToOneField('Computer', on_delete=models.SET_NULL, null=True, blank=True)
class Meta:
verbose_name = 'Статус'
verbose_name_plural = 'Статусы'
views.py:
def add_ASK(request):
error = ''
if request.method == 'POST':
form = StatusForm(request.POST)
if form.is_valid():
form.save()
return redirect('/index_S')
else:
error = 'Неверная форма данных'
form = StatusForm()
context = {
'form': form,
'error': error
}
return render(request, "base_comp/add_ASK.html", context)
Ответы (1 шт):
Ваш код не стал разбирать. Просто приведу мою реализацию данного функционала:
<form method="post" action="{% url 'rich:change_rich' object.id %}" id="rich_select_form">
{% csrf_token %}
Выберите РИЧ для данного РЭС:
<br>
<select name="select_rich" id="select_rich" onchange="richFunction()" class="rich_input_class">
<option value="" selected></option>
{% for i in related_rich %}
<option value="{{ i }}">{{ i }}</option>
{% endfor %}
<option value="Добавить">Добавить новое разрешение</option>
</select>
</form>
<form id="rich_add" method="post" action="{% url 'rich:add_rich' object.id %}" enctype="multipart/form-data" class="rich_add_form">
{% csrf_token %}
{{ rich_form.as_p }}
</form>
<div id="rich_buttons">
<input type="submit" value="Изменить" id="select_rich_button" form="rich_select_form">
<button onmousedown="showhide_changeform('change_rich')" class="close_button">
<i class="fa-solid fa-xmark"></i>
</button>
</div>
В шаблон передаем две формы. В поле action указываем разные функции view. При этом форму с id rich_add делаем невидимой при помощи css:
#rich_add {
padding-top: 0;
display: none;
}
Также на первой форме на select добавляем функцию js onchange="richFunction()" которая срабатывает при выборе "Добавить новое разрешение". Ниже сама функция:
function richFunction() {
var a = document.getElementById('select_rich');
var e = document.getElementById('rich_add');
var b = document.getElementById('select_rich_button');
if (a.value == "Добавить") {
e.style.display = 'block';
b.setAttribute("form", "rich_add");
b.value = 'Добавить';
}
else {
e.style.display = 'none';
b.setAttribute("form", "rich_select_form");
b.value = 'Изменить';
}
}
Функция richFunction() отвечает за смену свойства у элемента rich_add и смену текста кнопки (select_rich_button) и, что самое важное смену целевого id формы (атрибут form кнопки меняем на rich_add и обратно). Далее просто обрабатываем две различные view функции:
@login_required(login_url='account:login')
@is_staff
def change_rich(request, id):
res_object = Res.objects.get(id=id)
if request.method == 'POST':
rich_name = request.POST['select_rich']
obj = Rich.objects.get(name=rich_name)
if obj.end_date < date.today():
return res_detail(request, id, msg='Вы не можете присвоить РИЧ с истекшим сроком действия!')
else:
res_object.related_rich = obj
res_object.save()
return redirect('rich:res_detail', id=id)
@login_required(login_url='account:login')
@is_staff
def add_rich(request, id):
res_object = Res.objects.get(id=id)
if request.method == 'POST':
rich_form = RichForm(request.POST, request.FILES)
file = request.FILES['doc']
name = file.name.replace(Path(file.name).suffix, '')
name = name.replace('_', ' ')
end_date = request.POST['end_date']
end_date = datetime.strptime(end_date, '%Y-%m-%d').date()
if rich_form.is_valid() and (Rich.objects.filter(name=name).exists() is False) and (end_date > date.today()):
a = rich_form.save()
res_object.related_rich = a
res_object.save()
return redirect('rich:res_detail', id=id)
elif Rich.objects.filter(name=name).exists():
return res_detail(request, id, msg='Разрешение с таким именем уже существует!')
elif end_date < date.today():
return res_detail(request, id, msg='Вы не можете добавить РИЧ с истекшим сроком действия!')
else:
msg = form_errors_text(rich_form)
return res_detail(request, id, msg=msg)
return redirect('rich:res_detail', id=id)
Их функционал в данном случае неважен.