Нужна очень помощь по формам в django formset_factory
Нужна помощь по formset_factory в Django. Есть модель Рабочие места и Комплектующие рабочего места которые должны привязываться к рабочему месту на странице создания. Проблема в том что я уже 6 месяцев весь интернет облазил, прочитал уже много инструкций и статей, но не как не получается сделать так когда переходишь на страницу html создания Рабочего места, добавить несколько комплектующих и что бы они после сохранения закрепились за этим рабочим местом. То есть к одному-многое не получается сделать на одной странице. Хотя в админ панели такой вариант спокойно работает достаточно было прописать в admin.py TabularInline. Вот код может кто подскажите куда хотя бы копать. Что бы на одной странице создания рабочего места можно было закрепить несколько комплектующих к одному рабочему месту через кнопку понимаю что может быть проблема в JavaScript но в нем плоховат я.
#model.py
from django.db import models
from django.utils import timezone
# Предположим, что Organization и Equipment определены в вашем приложении
from organization.models import Organization
from oborudovaniye.models import Equipment
class JobsModel(models.Model):
organization = models.ForeignKey(Organization, on_delete=models.CASCADE, related_name='jobs', null=True, blank=True)
date = models.DateTimeField(default=timezone.now)
jobs_name = models.CharField(max_length=150, null=True, blank=True)
id_anydesk = models.CharField(max_length=50, null=True, blank=True)
id_rudesk = models.CharField(max_length=50, null=True, blank=True)
id_ammyadmin = models.CharField(max_length=50, null=True, blank=True)
def __str__(self):
return str(self.jobs_name) # Исправлено на jobs_name
class Meta:
verbose_name = "Рабочее место"
verbose_name_plural = "Рабочие места"
ordering = ['date'] # Сортировка отображения списка по последнему добавленому
class ComponentsJobsModel(models.Model):
jobs = models.ForeignKey(JobsModel, on_delete=models.CASCADE, related_name='components_jobs', null=True, blank=True)
equipment = models.ForeignKey(Equipment, on_delete=models.CASCADE, related_name='components_jobs', null=True, blank=True)
components_name = models.CharField(max_length=150, null=True, blank=True)
date = models.DateTimeField(default=timezone.now)
def __str__(self):
return str(self.equipment)
class Meta:
verbose_name = "Компонент рабочего места"
verbose_name_plural = "Компоненты рабочего места"
ordering = ['date']
from django.contrib import admin
#admin.py
from .models import JobsModel, ComponentsJobsModel
class ComponentsJobsInline(admin.TabularInline):
model = ComponentsJobsModel
extra = 1
@admin.register(JobsModel)
class JobsModelAdmin(admin.ModelAdmin):
list_display = ('id', 'organization', 'jobs_name', 'date')
search_fields = ('organization__name', 'jobs_name')
list_filter = ('date',)
ordering = ('-date',)
inlines = [ComponentsJobsInline]
@admin.register(ComponentsJobsModel)
class ComponentsJobsModelAdmin(admin.ModelAdmin):
list_display = ('id', 'jobs', 'equipment', 'components_name', 'date')
search_fields = ('jobs__jobs_name', 'equipment__name', 'components_name')
list_filter = ('date',)
ordering = ('-date',)
rom .models import JobsModel, ComponentsJobsModel
#form.py
from django import forms
class JobsForm(ModelForm):
class Meta:
model = JobsModel
fields = ["organization", "jobs_name", "id_anydesk", "id_rudesk", "id_ammyadmin"]
widgets = {
"organization": Select(attrs={
'class': 'form-control'
}),
"jobs_name": TextInput(attrs={
'class': 'form-control'
}),
"id_anydesk": TextInput(attrs={
'class': 'form-control'
}),
"id_rudesk": TextInput(attrs={
'class': 'form-control'
}),
"id_ammyadmin": TextInput(attrs={
'class': 'form-control'
}),
}
class ComponentsJobsForm(ModelForm):
class Meta:
model = ComponentsJobsModel
fields = ["equipment", "components_name"]
widgets = {
"equipment": Select(attrs={
'class': 'form-control'
}),
"components_name": TextInput(attrs={
'class': 'form-control'
}),
}
ComponentsJobsFormSet = formset_factory(ComponentsJobsForm, extra=1)
#views.py
from django.shortcuts import render, redirect, get_object_or_404
from django.views import View
from .models import Organization
from .form import JobsForm, ComponentsJobsForm, ComponentsJobsFormSet
from .models import Equipment
class CreateJobsOrganization(View):
template_name = 'jobs/jobs_create.html'
def get(self, request, organization_id):
organization = get_object_or_404(Organization, id=organization_id)
jobs_form = JobsForm(initial={'organization': organization, 'id_anydesk': 'AnyDesk'})
components_formset = ComponentsJobsFormSet()
equipment_choices = Equipment.objects.all()
context = {
'jobs_form': jobs_form,
'components_formset': components_formset,
'organization': organization,
'equipment_choices': equipment_choices,
}
return render(request, self.template_name, context)
def post(self, request, organization_id):
organization = get_object_or_404(Organization, id=organization_id)
jobs_form = JobsForm(request.POST)
components_formset = ComponentsJobsFormSet(request.POST)
print("Jobs Form Data:", jobs_form.data)
print("Components Formset Data:", components_formset.data)
if jobs_form.is_valid() and components_formset.is_valid():
job = jobs_form.save(commit=False)
job.organization = organization
job.save()
for form in components_formset:
if form.is_valid():
component = form.save(commit=False)
component.jobs = job
component.save()
print(f"Component saved: {component}")
else:
print("Invalid form:", form.errors)
organization_inn = organization.inn
return redirect('organization_detail', inn=organization_inn)
else:
equipment_choices = Equipment.objects.all()
context = {
'jobs_form': jobs_form,
'components_formset': components_formset,
'organization': organization,
'equipment_choices': equipment_choices,
}
return render(request, self.template_name, context)
#html
{% extends 'myapp/analitic.html' %}
{% block title %}
Добавления рабочего места
{% endblock %}
{% block content2 %}
<style>
.hide-organization {
display: none;
}
</style>
<div class="container-fluid">
<div class="card">
<div class="card-body">
<div class="card-title">
<h2 class="text-center fw-bold fs-2">Добавления рабочего места:</h2>
</div>
<hr/>
<form method="post">
{% csrf_token %}
<div class="row">
<div class="col-lg-4 hide-organization">
<label class="col-form-label">Организация:</label>
{{ jobs_form.organization }}
</div>
<div class="col-lg-4">
<label class="col-form-label">Название рабочего места:</label>
{{ jobs_form.jobs_name }}
</div>
</div>
<div class="row">
<div class="col-lg-4">
<label class="col-form-label">ID AnyDesk:</label>
{{ jobs_form.id_anydesk }}
</div>
</div>
<div class="row">
<div class="col-lg-4">
<label class="col-form-label">ID RuDesk:</label>
{{ jobs_form.id_rudesk }}
</div>
</div>
<div class="row">
<div class="col-lg-4">
<label class="col-form-label">ID AmmyAdmin:</label>
{{ jobs_form.id_ammyadmin }}
</div>
</div>
<div id="components-forms">
{{ components_formset.management_form }}
{% for form in components_formset %}
<div class="component-form">
<div class="row">
<div class="col-lg-4">
<label class="col-form-label">Оборудование:</label>
{{ form.equipment }}
</div>
<div class="col-lg-4">
<label class="col-form-label">Название компонента:</label>
{{ form.components_name }}
</div>
</div>
</div>
{% endfor %}
</div>
<div class="row mt-4">
<div class="col-sm-10">
<button type="button" id="add-component" class="btn btn-light px-4">Добавить комплектующее</button>
<button type="submit" class="btn btn-light px-4">Добавить рабочее место</button>
</div>
</div>
</form>
</div>
</div>
</div>
{% load static %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/js/select2.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/css/select2.min.css" rel="stylesheet" />
<script>
$(document).ready(function() {
$('#id_organization').select2({
theme: 'bootstrap4',
width: $('#id_organization').data('width') ? $('#id_organization').data('width') : $('#id_organization').hasClass('w-100') ? '100%' : 'style',
placeholder: $('#id_organization').data('placeholder'),
allowClear: Boolean($('#id_organization').data('allow-clear')),
});
$('#add-component').click(function() {
var formCount = $('#components-forms .component-form').length;
var newForm = `
<div class="component-form">
<div class="row">
<div class="col-lg-4">
<label class="col-form-label">Оборудование:</label>
<select name="form-${formCount}-equipment" class="form-control select2-field">
{% for equipment in equipment_choices %}
<option value="{{ equipment.id }}">{{ equipment.name }}</option>
{% endfor %}
</select>
</div>
<div class="col-lg-4">
<label class="col-form-label">Название компонента:</label>
<input type="text" name="form-${formCount}-components_name" class="form-control">
</div>
</div>
</div>
`;
$('#components-forms').append(newForm);
// Инициализация Select2 для нового поля
$('.select2-field').select2({
theme: 'bootstrap4',
width: '100%',
placeholder: 'Выберите оборудование',
allowClear: true,
});
});
});
</script>
{% endblock %}