![](/img/trans.png)
[英]Django ModelForm not saving data that is added to request.POST or through form.save(commit=False)
[英]django post_signal triggered on form.save(commit=False)
我有一個基本的用戶模型和另外兩個模型候選人和公司
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。
請幫忙!
在處理實例之前,應先嘗試斷開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)
在您的表單中,您已覆蓋save
,並且始終調用create_user
,后者將調用user.save(using=self._db)
即未傳遞commit
的值
您可以做的是在用戶模型中覆蓋_create_user
,將commit的值傳遞給它
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
PS:我個人不喜歡django信號,因為它們會引起混亂。 最好在您的視圖或表單保存中執行此操作。 您應該只有一種創建新用戶的方法,所以這不是一個大問題。
將您的參數更改為默認False,然后在保存之前檢查是否為真...如果您用commit false或true進行調用,它們將始終保存在數據庫中...因此,它們會觸發您的操作后保存
def save(self, commit=False):
if commit:
user = User.objects.create_user(
self.cleaned_data['email'],
self.cleaned_data['password']
)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.