在form.save(commit = False)

时间:2018-07-10 09:45:08

标签: python django django-models django-forms django-views

我有一个基本的 User 模型和另外两个候选人公司

模型
User:
  email
  password
  is_company => default=False

表单类:

class CustomUserCreationForm(forms.Form):
    email = forms.EmailField(label='Enter email', widget=forms.EmailInput(attrs={'placeholder': 'Email Address', 'spellcheck':'False', 'autofocus':'True'}))
    password = forms.CharField(label='Enter password', min_length=8, widget=forms.PasswordInput(attrs={'placeholder': 'Password'}))

    def clean_email(self):
        email = self.cleaned_data['email'].lower()
        r = User.objects.filter(email=email)
        if r.count():
            raise  ValidationError("Email already exists")
        return email

    def clean_password(self):
        password = self.cleaned_data.get('password')
        return password

    def save(self, commit=True):
        user = User.objects.create_user(
            self.cleaned_data['email'],
            self.cleaned_data['password']
        )
        return user

我的UserManager:

class UserManager(BaseUserManager):
    use_in_migrations = True

    def _create_user(self, email, password, **extra_fields):
        """
        Creates and saves a User with the given email and password.
        """
        try:
            validate_email(email)
            valid_email = True
        except ValidationError:
            valid_email = False
        if not valid_email:
            raise ValueError('Valid Email is required')
        email = self.normalize_email(email)
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        subject = 'Activate Your Account'
        message = render_to_string('registration/account_activation_email.html', {
            'domain': 'example.in',
            'user': user,
            'uid': urlsafe_base64_encode(force_bytes(user.pk)),
            'token': account_activation_token.make_token(user),
        })
        user.email_user(subject, 'example <admin@example.in>', html_message=message)
        return user

    def create_user(self, email, password=None, **extra_fields):
        extra_fields.setdefault('is_superuser', False)
        return self._create_user(email, password, **extra_fields)

    def create_superuser(self, email, password, **extra_fields):
        extra_fields.setdefault('is_superuser', True)

        if extra_fields.get('is_superuser') is not True:
            raise ValueError('Superuser must have is_superuser=True.')

        return self._create_user(email, password, **extra_fields)

在我的用户创建视图中:

class SignUpView(View):
    is_company = False
    def get(self, request):
        if request.user.is_authenticated():
            return redirect(reverse_lazy('dashboard'))
        form = CustomUserCreationForm()
        return render(request, 'registration/signup.html', {'form': form, 'is_company':self.is_company})

    def post(self,request):
        form = CustomUserCreationForm(request.POST or None, request.FILES or None)
        if form.is_valid():
            user = form.save(commit=False)
            user.is_active = False
            user.is_company = self.is_company
            user.save()
            return render(request, 'registration/account_activation_sent.html')
        return render(request, 'registration/signup.html', {'form': form, 'is_company':self.is_company})

我为上述模型创建了一个post_save信号。

  @receiver(post_save, sender=User)
  def update_user_profile(sender, instance, created, **kwargs):
      if created:
          if instance.is_company:
              Company.objects.create(user=instance)
              instance.company.save()
        else:
            Candidate.objects.create(user=instance, 
                                   first_name=instance.is_company )
            instance.candidate.save()

urls.py:

url(r'^accounts/signup/company/',vw.SignUpView.as_view(is_company = True), name='signup_company')

问题是form.save(commit=False)触发了post_save信号。我最终将instance.is_company作为False,从而为公司创建了CandidateProfile。

但是在数据库用户表中,公司的is_company填充为True。

请帮助!

3 个答案:

答案 0 :(得分:0)

在处理实例之前,应先尝试断开post_save信号,然后再连接它。

@receiver(post_save, sender=User)
def update_user_profile(sender, instance, created, **kwargs):
    # disconnect post_save
    post_save.disconnect(update_user_profile, sender=sender)

    # do something with your instance

    # connect post_save
    post_save.connect(update_user_profile, sender=sender)

答案 1 :(得分:0)

在您的表单中,您已覆盖save,并且始终调用create_user,该调用将调用user.save(using=self._db),即未传递commit的值

您可以做的是在用户模型中覆盖_create_user,以将提交值传递给它

class User(AbstractBaseUser):
    ...
    def _create_user(self, username, email, password, commit=True, **extra_fields):            
        if not username:
            raise ValueError('The given username must be set')
        email = self.normalize_email(email)
        username = self.model.normalize_username(username)
        user = self.model(username=username, email=email, **extra_fields)
        user.set_password(password)
        if commit:
            user.save(using=self._db)
        return user

然后在您的表单中可以将commit的值传递给它

class CustomUserCreationForm(forms.Form):
    def save(self, commit=True):
        return User.objects.create_user(
            self.cleaned_data['email'],
            self.cleaned_data['password'],
            commit=False
        )

编辑:再次查看此代码,我觉得这很糟糕。 您最好修正表单中的逻辑以进行多次保存

class CustomUserCreationForm(forms.Form):
    def save(self, commit=True):
        is_create = self.instance.pk is None
        user = super().save(commit=commit)
        user.set_password(self.cleaned_data['password'])
        user.save()
        if not is_create:
            return user

        if user.is_company:
            Company.objects.create(user=user)
            user.company.save()  # not really needed
        else:
            Candidate.objects.create(user=user, first_name=user.is_company)
            user.candidate.save()  # not really needed
        return user

P.S:我个人不喜欢django信号,因为它们会引起混乱。最好在您的视图或表单保存中执行此操作。您应该只有一种创建新用户的方法,所以这不是大问题。

答案 2 :(得分:0)

将您的参数更改为默认False,然后在保存之前检查是否为真...以您的方式进行操作,如果您以commit false或true进行调用,它们将始终保存在数据库中...因此是触发您的post_save

def save(self, commit=False):
    if commit:
        user = User.objects.create_user(
            self.cleaned_data['email'],
            self.cleaned_data['password']
        )