2016-07-02 2 views
0

Я расширил пользователя django с помощью OneToOneField, чтобы сохранить адрес и т. Д.Получить поля пользователя OneToOneField в ModelForms

SiteUser - это модель, которая распространяется User с использованием OneToOneField. Как я могу получить поля как User, так и SiteUser в одном ModelForm?

Вот соответствующий код до сих пор:

class ProfileForm(ModelForm): 
    class Meta: 
     model = User 
     fields = ('username', 'first_name', 'last_name', 'email') 


class AddressForm(ModelForm): 
    pass 

Просмотр в вопросе:

def edit_profile(request): 
    username = request.user 
    user = User.objects.get(username__exact=username) 
    profileform_class = ProfileForm 

    if request.method == 'POST': 
     profileform = profileform_class(data=request.POST, instance=user) 
     if profileform.is_valid(): 
      profileform.save() 
      return redirect('profile') 
    else: 
     profileform = profileform_class(instance=user) 

    return render(request, 'edit_profile.html', { 
     'user': user, 
     'profileform': profileform, 
    }) 

И две модели:

class Product(models.Model): 
    order = models.IntegerField(default=0) 
    name = models.CharField(max_length=255) 
    description = models.TextField() 
    image = models.ImageField(upload_to='product-images', default='default.jpg') 
    price = models.FloatField() 
    slug = models.SlugField(unique=True) 


class SiteUser(models.Model): 
    user = models.OneToOneField(User, on_delete=models.CASCADE) 
    address = models.CharField(max_length=255) 
    post_number = models.CharField(max_length=255, default='') 
    post_location = models.CharField(max_length=255, default='') 

HTML страницы Я хочу формы на:

{% extends 'base.html' %} 
{% block title %} 
    Rediger {{ product.name }} - {{ block.super }} 
{% endblock title %} 

{% block content %} 
    <h1>Rediger "{{ user }}"</h1> 
    <form role="form" action="" method="post"> 
    {% csrf_token %} 
    {{ profileform.as_p }} 
    {{ addressform.as_p }} 
    <button type="submit">Submit</button> 
    </form> 
{% endblock content %} 

ответ

2
  • Один из вариантов заключается в использовании inline formsets. Используя это, вам не понадобится вторая ModelForm.

    Inline formsets - это небольшой слой абстракции поверх формных форм. Это упрощает работу с связанными объектами с помощью внешнего ключа.

    good examples here.

  • В качестве альтернативы, если вы хотите, чтобы избежать инлайн FormSets и использовать как ProfileForm и AddressForm под одним <form> тега, как вы сделали в шаблоне, вы можете сделать это, как this.

    формы:

    class ProfileForm(ModelForm): 
        class Meta: 
         model = User 
         fields = ('username', 'first_name', 'last_name', 'email') 
    
    class AddressForm(ModelForm): 
        class Meta: 
         model = SiteUser 
         exclude = ['user'] 
    

    Просмотров:

    def edit_profile(request): 
        username = request.user 
        user = User.objects.get(username__exact=username) 
        profileform_class = ProfileForm 
        addressform_class = AddressForm 
    
        if request.method == 'POST': 
         profileform = profileform_class(data=request.POST, instance=user) 
         addressform = addressform_class(data=request.POST, instance=user.siteuser) 
         if all((profileform.is_valid(), addressform.is_valid())): 
          user = profileform.save() 
          address = addressform.save(commit=False) 
          address.user = user 
          address.save() 
          return redirect('profile') 
        else: 
         profileform = profileform_class(instance=user) 
         addressform = addressform_class(instance=user.siteuser) 
    
        return render(request, 'edit_profile.html', { 
         'user': user, 
         'profileform': profileform, 
         'addressform': addressform, 
        }) 
    
+0

Так что у меня ближе к тому, что я хотел, спасибо! Но проблема в том, что адресная форма не знает, к какому пользователю относится. Таким образом, форма не автозаполняется, когда уже есть адрес, и он не может сохранить новый адрес. Модель «Пользователь» в формах.py уже знает, какой из них является причиной, может быть только один пользователь. Но просто ссылаться на «SiteUser» не будет указывать на текущего пользователя. В других частях сценария я использую user.siteuser для доступа к различным частям модели, если я хочу его отобразить. И «все()», по-видимому, принимает только одно утверждение –

+0

@ AndreasHalvorsenTollånes Отредактировав мой ответ, обратитесь к соответствующей модели SiteUser. Исправлено обращение ко всем(): вы должны передать ему список/кортеж, извините. Скажите, если это работает :) –

+1

Да! Теперь он работает, но для автозаполнения полей вы хотите добавить экземпляр = user.siteuser в else: addressform = addressform_class (instance = user.siteuser) ^^ –

0

Я не знаю много о формах, но я думаю, вы должны использовать «первоначальный» параметр при инстанцировании AddressForm, как проиллюстрировано здесь: https://docs.djangoproject.com/es/1.9/topics/forms/modelforms/#providing-initial-values

Так вы создаете класс AddressForm с SiteUser в качестве модели, и когда вы создаете его экземпляр в представлении, вы делаете это так:

AddressForm(initial={'user': request.user}) 

Если «имя пользователя» не является первичным ключом модели пользователя, вы можете получить первичный ключ, как это:

User.objects.get(username=request.user).pk 

, а затем введите его в «начальный» параметр.

Смежные вопросы