Как на основе заполнения одной формы и передачи данных в одну модель, передать часть данных в другую?

Рейтинг: 0Ответов: 1Опубликовано: 02.05.2023

Я новичок в 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)

Ответы

▲ 0Принят

Ваш код не стал разбирать. Просто приведу мою реализацию данного функционала:

<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)

Их функционал в данном случае неважен.