Please tell me, when a model has a lot of related fields with other tables, how to make a normal form with filling such a model?
How do I create a form for Project?
class City(models.Model):
obl = models.CharField(max_length=255, choices=REGIONS, default="24", verbose_name="Регион")
name = models.CharField(max_length=128, verbose_name="Город")
population = models.IntegerField()
class Address(models.Model):
city = models.ForeignKey(City, on_delete=models.PROTECT, verbose_name="Город")
street = models.CharField(max_length=255, verbose_name="Улица")
numb = models.CharField(max_length=64, verbose_name="Номер дома")
class Project(models.Model):
manager = models.ForeignKey(User, on_delete=models.PROTECT, verbose_name="Сотрудник")
address = models.ForeignKey(Address, on_delete=models.PROTECT, verbose_name="Адрес")
vis = models.DateField(verbose_name="Подписан дата", blank=True)
accept = models.DateField(verbose_name="Принят дата", blank=True)
Maybe I need a step-by-step fill-in form
CodePudding user response:
You can create and customize the admin form based on your needs. I.e. if you create an admin form for the Project and you would like to include the User form as an Inline form you can achieve that easily by inlines
.
Please refer to the documentation regarding adding related objects inside forms. https://docs.djangoproject.com/en/4.1/intro/tutorial07/
CodePudding user response:
I would follow Jamal's answer if you only need the interface in the admin console.
If you want to create a custom interface in your own, I would do it like this (untested):
# forms.py
class ProjectForm(forms.ModelForm):
class Meta:
model = Project
fields = ['manager', 'vis', 'accept']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# When we're creating new instance
if not self.instance.pk:
self.address_form = AddressForm(
data=kwargs.get('data'),
files=kwargs.get('files'),
)
# When we're updating an existing instance
else:
self.address_form = AddressForm(
instance=self.instance.address,
data=kwargs.get('data'),
files=kwargs.get('files'),
)
class AddressForm(forms.ModelForm):
class Meta:
model = Address
fields = ['street', 'numb']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# When we're creating new instance
if not self.instance.pk:
self.city_form = CityForm(
data=kwargs.get('data'),
files=kwargs.get('files'),
)
# When we're updating an existing instance
else:
self.city_form = CityForm(
instance=self.instance.city,
data=kwargs.get('data'),
files=kwargs.get('files'),
)
class CityForm(forms.ModelForm):
class Meta:
model = City
fields = '__all__'
# views.py
class CreateProject(CreateView):
model = Project
form_class = ProjectForm
template_name = 'project_form.html'
class UpdateProject(UpdateView):
model = Project
form_class = ProjectForm
template_name = 'project_form.html'
# project_form.html
<form method="post">
{% csrf_token %}
{# The project form #}
{{ form.as_p }}
<h2>Address</h2>
{# The address form in the project form. Instead of the address field. #}
{{ form.address_form.as_p }}
<h2>City</h2>
{# The city form in the address form. Instead of the city field. #}
{{ form.address_form.city_form.as_p }}
<input type="submit" value="Save" />
</form>
PS., if by any chance you're using django-crispy-forms
package, make sure you don't render the form tags in the AddressForm
and CityForm
.
PSPS., if you come into a situation where two of the forms you're rendering on the same page have attributes with the same name, you will need to use prefix
in your initializer of the forms to namespace these attributes. However, this is not the case in your question, so I didn't want to complicate.