我在UserCreationForm的子类上覆盖了save()
方法。我之所以这样做是因为我想在创建User对象时创建另一个相关对象
以下是表单以及save方法:
class MyUserCreationForm(UserCreationForm):
error_message = UserCreationForm.error_messages.update({
'duplicate_username': 'This username has already been taken.'
})
class Meta(UserCreationForm.Meta):
model = User
def clean_username(self):
username = self.cleaned_data["username"]
try:
User.objects.get(username=username)
except User.DoesNotExist:
return username
raise forms.ValidationError(self.error_messages['duplicate_username'])
def save(self, commit=True):
user = super(MyUserCreationForm, self).save(commit=False)
if commit:
user.save()
Profile.objects.create(user=user)
return user
因此永远不会创建Profile
对象。从技术上讲,如果我删除if commit:
,我可以让它工作:
def save(self, commit=True):
user = super(MyUserCreationForm, self).save(commit=False)
user.save()
Profile.objects.create(user=user)
return user
但是,我想知道为什么每次创建用户时False
都会传递给save()
方法。基于我所阅读的内容,条件应该存在,以便保留与被覆盖的save()
方法相同的行为。
答案 0 :(得分:1)
这张表格在哪里使用?例如,如果它位于ModelAdmin
,可能是因为ModelAdmin
有自己的save_model
方法。
def save_model(self, request, obj, form, change):
"""
Given a model instance save it to the database.
"""
obj.save()
由于这是要保存模型的地方,我将假设commit
为False
,以便可以在此处完成。
例如,您可以尝试在ModelAdmin
中覆盖此内容,但这取决于使用它的位置。 Dan Loewenherz是正确的,你不应该使用commit
检查这样的东西。通常,它更适合与表单一起使用,而这是围绕模型的问题。
我认为这里的问题是你正在使用的模式。我认为最好保持表格的目的与模型本身更紧密地联系在一起。
如果稍后使用不同的方法或表单创建用户,会发生什么?他们将缺少Profile
。我假设这是常见的用户/用户配置文件问题,它来自内置的auth用户模型的限制,在这种情况下,User
没有Profile
可能是灾难性的。
我的建议是在post_save
中使用models.py
信号:
from django.db.models.signals import post_save
from django.contrib.auth.models import User
from models import UserProfile
from django.db import models
def create_profile(sender, instance, created **kwargs):
if created:
Profile.objects.create(user = instance)
post_save.connect(create_profile, sender = User, dispatch_uid = "users-
profilecreate-signal")
有些人对使用信号犹豫不决,但在这种情况下,它们是保护模型完整性的最可靠方法。
另一种选择是在User
的模型级别进行。像这样:
def save(self, *args, *kwargs):
user = super(User, self).save(*args, **kwargs)
Profile.objects.get_or_create(user = user)
return user
答案 1 :(得分:1)
commit=False
旨在用于内联表单。它用于将父键分配给表单实例并稍后保存该实例。
来源:https://github.com/django/django/blob/master/django/forms/models.py#L942
您应该能够稍微调整一下您的解决方案。
def save(self, *args, **kwargs):
user = super(MyUserCreationForm, self).save(*args, **kwargs)
if user.pk: # If user object has been saved to the db
Profile.objects.get_or_create(user=user)
return user
但我建议使用Django的模型信号。
from django.db.models.signals import post_save
from django.dispatch import receiver
@receiver(post_save, sender=User)
def user_created_signal_handler(request, user, *args, **kwargs):
Profile.objects.get_or_create(user=user)
https://docs.djangoproject.com/en/2.0/ref/signals/#django.db.models.signals.post_save