1

I have the following classes:

class Account(models.Model):
    instance = models.OneToOneField(Instance, blank=True, null=True)

class Instance(models.Model):
    is_ready = models.BooleanField(default=False, verbose_name=_('Ready?'))

Right now the relationship between Account and Instance is set by a ModelForm for Account via Account.instance.

I would like to be able to set Account.instance via a ModelForm on Instance. Is that possible?

Tinker
  • 4,165
  • 6
  • 33
  • 72
  • When you define a `ModelForm`, at its `Meta` class, you have to define a `model` attribute and a `fields` attribute. In the `fields` attribute there is no way to enter a field from another model. By its construction, the `forms.ModelForm` is dedicated to one `models.Model` – raratiru Jul 04 '18 at 15:52
  • Did you find a better solution? – raratiru Jul 10 '18 at 11:24
  • @raratiru I moved that field to the model instead – Tinker Jul 10 '18 at 21:43
  • Therefore, you can safely assume that your question [is answered](https://stackoverflow.com/help/someone-answers). – raratiru Jul 11 '18 at 10:36

1 Answers1

0

A ModelForm is:

a helper class that lets you create a Form class from a Django model.

An idea would be to write a custom model Field to address this issue. However, according to the relevant chapter of Writing Custom Model Fields

Fields in a model must somehow be converted to fit into an existing database column type.

Trying to spot the available postgreSQL column types I found this page which does not seem to provide a solution.

On the other hand, there is an old but updated SO post, which gives a solution that actually renders both forms in an HTML page and -this way- you gather all the needed fields in one form.

forms.py

class AccountForm(forms.ModelForm):
    ... Do stuff if necessary ...
    class Meta:
        model = Account
        fields = ('the_fields', 'you_want')


class InstanceForm (forms.ModelForm):
    ... Do other stuff if necessary ...
    class Meta:
        model = Instance
        fields = ('the_fields', 'you_want')

views.py

...
def register(request):
    if request.method == 'POST':
        account_form = AccountForm(request.POST)
        instance_form = InstanceForm(request.POST)
        if account_form.is_valid() and instance_form.is_valid():
            account_form.save()
            instance_form.save()
...

the_template.html

<form action="." method="post">
    {% csrf_token %}
    {{ account_form.as_p }}
    {{ instance_form.as_p }}
    <input type="submit" value="Submit">
</form>

This is also the idea of the admin's class InlineModelAdmin.

In the admin, for example, Account will become an inline model to Instance (which is a bad name for a django class).

admin.py:

from django.contrib import admin


class InstanceInline(admin.TabularInline):
    model = Instance


class AccountAdmin(admin.ModelAdmin):
    inlines = [
        InstanceInline,
    ]
raratiru
  • 8,748
  • 4
  • 73
  • 113
  • I don't think that is what I am looking for because I am not referring to Admin here. – Tinker Jul 03 '18 at 08:11
  • @Sparrowcide Thank you for the clarification, I have updated my answer. – raratiru Jul 03 '18 at 08:33
  • Thank you for your answer! Do you think using two forms will actually be easier than using a custom form that has all the fields of Instance and just one field from Account (`Account.instance`)? – Tinker Jul 03 '18 at 18:46
  • @Sparrowcide Technically, you may create a placebo `OneToOne` field in `InstanceForm` and take care of feeding it with initial values and actions that will update any changes to `Instance`. According to my experience, this requires an exceptionally good reason to do it, strong coding skills and many restrictions in place that will severely narrow its potential. By using two forms, validations and save actions work out of the box and you can also chose which fields are shown to the user. – raratiru Jul 03 '18 at 21:42