Home > Net >  Django Form and some ForeingKey fields
Django Form and some ForeingKey fields

Time:01-16

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.

  • Related