2015-05-11 4 views
0

У меня есть модель UserProfile, которая связана OneToOne с Django User. Добавляя пользователя через форму, я хотел иметь одну форму для обоих. Я нашел фрагмент, который делает именно это, и у меня не было никаких проблем с ним, пока я не захотел проверить username. Форма не бросает ValidationError, как хотелось бы, но возвращает страницу с ошибкой ValueError: The User could not be created because the data didn't validate..Подтвердить вложенную форму в Django

Из того, что я понимаю (что, очевидно, может быть неправильным), текущая установка не обрабатывает ValidationError s из вложенной формы.

Есть ли способ добавить эту функциональность? Если нет, то как мне решить проблему с использованием одной формы для моделей?

Код:

class CmUserForm(forms.ModelForm): 
    password = forms.CharField(widget=forms.PasswordInput(), 
           required=False, 
           help_text=_("Leave empty if you don't want " 
              "to change it")) 

    def clean_password(self): 
     data = self.cleaned_data['password'] 
     if data.strip(): 
      return make_password(data) 
     else: 
      # If password field is empty, then don't change it 
      return self.instance.password 

    def clean_username(self): 
     username = self.cleaned_data['username'] 

     if get_user_model().objects.filter(username=username).exists(): 
      raise forms.ValidationError(_('This username is already in use.')) 
     return username 

    class Meta: 
     model = get_user_model() 
     fields = ('first_name', 'last_name', 'email', 'username', 'password', 'is_staff', 'is_active') 


class CmUserProfileForm(forms.ModelForm): 
    def __init__(self, *args, **kwargs): 
     # Take User if updating, None if creating 
     try: 
      self.user = kwargs['instance'].user 
     except AttributeError: 
      self.user = None 

     user_kwargs = kwargs.copy() 
     user_kwargs['instance'] = self.user 
     self.uf = CmUserForm(*args, **user_kwargs) 

     super(CmUserProfileForm, self).__init__(*args, **kwargs) 

     self.fields.update(self.uf.fields) 
     self.initial.update(self.uf.initial) 

    class Meta: 
     model = UserProfile 
     exclude = ['user'] 

    def save(self, *args, **kwargs): 
     # Save User and pass it to UserProfile 
     user = self.uf.save(*args, **kwargs) 
     self.instance.user = user 
     return super().save(*args, **kwargs) 
+0

Зачем вам гнездиться таким формам? Просто используйте 2 формы прямо на ваш взгляд. Это слишком сложно для очень простого, общего использования. – knbk

+0

@knbk, потому что я не хочу иметь две формы, я не хочу defrienciate между '' User'' и '' UserProfile''. При добавлении пользователя они расширяют друг друга, и я хочу рассматривать их как один. Или есть лучший способ достичь этого? Может/должен ли я делать две формы с помощью одной кнопки отправки? –

+0

Но они не одно, они две разные вещи, даже если они тесно связаны. Независимо от того, как вы пытаетесь сгибать их, ModelForms создаются для редактирования одной модели. Быть действительно откровенным: это ужасное решение. Какую проблему ты пытаешься решить? Я могу гарантировать, что для его решения существуют более простые и простые методы. Я не хочу быть суровым, я просто хотел бы помочь вам избежать огромного сложного беспорядка, в который вы работаете. – knbk

ответ

1

я реализован тот же сегодня. Я узнал об этом с этого веб-сайта танго с django. http://www.tangowithdjango.com/book/chapters/login.html. Также я представил свой код, как я это достиг. Сама встроенная модель пользователя проверяет, существует ли имя пользователя или нет. надеюсь, это полезно.

class Sam(models.Model): 
     user = model.OneToOneField(User) 
     #custom fields apart from the inbuilt User model 
     region = models.CharField(max_length=10) 
     designation = models.CharField(max_length=10) 
#forms.py form models. Created SamProfileform to capture the custom fields which are specific to One's Profile and SamForm to capture the password and then hash later in the view. 
#Please note that i didnt add any username check here. The inbuilt User does it for us. I verified it. 
class SamForm(forms.ModelForm): 
     #form model to capture inbuilt fields of "User" model 
     password = forms.CharField(widget=PasswordInput()) 
     class Meta: 
      model = User 
      fields = ('username', 'email', 'password', 'firstname', 'lastname') 
class SamProfileForm(forms.ModelForm): 
     #form model to built the custom fields in my case region and designation 
     class Meta: 
      model = Sam 
      fields = ('desgination', 'mgr') 
def register(request): 
    registered = False 
    if request.method == 'POST': 
     user_form = SamForm(data=request.POST) 
     profile_form = SamProfileForm(request.POST) 
     if user_form.is_valid() and profile_form.is_valid(): 
      user = user_form.save() 
      user.set_password(user.password) 
      user.save() 
      profile = profile_form.save(commit=False) 
      profile.user = user 
      profile.save() 
      registered = True 
     else: 
      print user_form.errors, profile_form.errors 
    else: 
     user_form = SamForm() 
     profile_form = SamProfileForm() 
    template = loader.get_template('sam/register.html') 
    context = RequestContext(request, { 
      'user_form' : user_form, 'profile_form' : profile_form, 'registered' : registered, 
    }) 
    return HttpResponse(template.render(context)) 
Смежные вопросы