I have a Django model which extends the auth User class, but I can't find a way to render data from both models in a single form.

For example, let's extend the User class with a country field using a One2OneField:

from django.contrib.auth.models import User
import pycountry
class Account(models.Model):
    user = models.OneToOneField(User, primary_key=True)
    COUNTRY_CHOICES = [(country.alpha2, country.name) for country in pycountry.countries]
    country = models.CharField(max_length=2, choices=COUNTRY_CHOICES, default='US')

Now let's create a form which contains elements from both models:

class AccountSettingsForm(Form):
    first_name = TextField(u'First name:', [validators.Length(min=2, max=35,message=u'First name should be between 2 and 35 characters.')])
    last_name = TextField(u'Last name:', [validators.Length(min=2, max=35,message=u'Last name should be between 2 and 35 characters.')])
    email = EmailField(u'E-mail address:', [validators.Email(message=u'Invalid e-mail address.')])
    COUNTRY_CHOICES = [(country.alpha2, country.name) for country in pycountry.countries]
    country = SelectField(u'Country', [valid_country,],choices=COUNTRY_CHOICES)

Now, on my "account settings" page, I have this:

@login_required
def update_settings(request):
    form = AccountSettingsForm(request.POST, obj=request.user)
    if request.method=='POST' and form.validate():
        #processing goes here
    context = {'form': form}
    return render(request, 'account/settings.html', context)

When opening the page, only the info from "User" (like first name, last name, mail address,...) is displayed. However, the "country" part is not retrieved from the model.

What do I need to do to get both displayed on the same form? I don't see how I can explicitly bind the "country" field of the form to the user.account.country field on the model.

有帮助吗?

解决方案 2

Seems it was easier than I thought.

Replace this:

form = AccountSettingsForm(request.POST, obj=request.user)

with:

form = AccountSettingsForm(request.POST, obj=request.user, country=request.user.account.country)

其他提示

You can override the __init__() method like this to populate the data from obj.account (is that even the default name? I always use the related_name option).

class AccountSettingsForm(Form):
    def __init__(self, formdata=None, obj=None, prefix='', data={}, meta=None, **kwargs):
        data['country'] = obj.account.country
        # etc
        super(AccountSettingsForm, self).__init__(formdata, obj, prefix, 
                                                  data, meta, **kwargs)
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top