Django - 将更新的信息保存给现有用户
Django - Saving updated information to existing user
我正在创建一个用于注册的多步骤用户表单。它背后的想法是,当用户注册时,它会获取他们的注册信息。然后,它保存用户信息。在注册表单中,如果用户选择了某个选项(rank = 'Anak'),他们将被重定向到获取部落名称的基本表单。我想要它做的是将部落名称保存到刚刚创建的用户帐户中,但我在执行此操作时遇到了麻烦,因为 Django 中的基本表单没有 save() 函数。
forms.py
class RegisterForm(UserCreationForm):
email = forms.EmailField(
initial='',
required=True,
help_text='Please enter a valid email address'
)
rank = forms.ChoiceField(
label='Are you a PSMC member?',
choices=SavBlock.models.User.rank,
initial=False,
required=True,
help_text='Member accounts will be validated with your HC.',
)
class Meta:
model = User
# username = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
fields = ['username', 'first_name', 'last_name', 'email',
'rank', 'password1', 'password2']
def save(self, commit=True):
user = super(RegisterForm, self).save(commit=False)
user.email = self.cleaned_data['email']
user.ranking = self.cleaned_data['rank']
if commit:
user.save()
return user
class AnakRegisterForm(Form):
tribe = forms.ChoiceField(
label='What tribe are you from, Uce?',
choices=SavBlock.models.Anak.tribe,
initial=False,
required=True,
help_text='Member accounts will be validated with your HC.'
)
class Meta:
model = Anak
fields = ['tribe']
def save(self, commit=True):
user = super(RegisterForm, self).save(commit=False)
user.tribe = self.cleaned_data['tribe']
if commit:
user.save()
return user
views.py
def register(response):
context = {}
# temp_key = {}
if response.method == "POST":
form = RegisterForm(response.POST)
if form.is_valid():
form.save()
if form.cleaned_data.get('rank') == 'Anak':
# temp_key[form.cleaned_data.get('username')] = form.cleaned_data
return redirect('anak_register')
# anak_register(form.cleaned_data)
messages.success(response, 'Registration successful. Please login.')
return redirect('login')
else:
context['register'] = form
else:
form = RegisterForm()
context['register'] = form
return render(request=response, template_name='register/register.html', context={'form': form})
def anak_register(response):
context = {}
if response.method == 'POST':
anak_form = AnakRegisterForm(response.POST)
if anak_form.is_valid():
# TODO: The form obtains the tribe information from the user. Now we must save this information into the
# users account.
"""
anak_form = RegisterForm.save(register)
return anak_form
"""
else:
context['register'] = anak_form
render(request=response, template_name='register/register.html', context={'form': anak_form})
else:
anak_form = AnakRegisterForm(response.POST)
context['anak_register'] = anak_form
# messages.error(request, 'Unsuccessful registration. Invalid information.')
return render(request=response, template_name='register/anak_register.html', context={'form': anak_form})
在重定向到 anak_register 之前,UserCreationForm 会保存用户信息。 anak_form 包含一些我想关联到刚创建的用户帐户的信息,但就像我说的,我不确定该怎么做。可能有更简单的方法
models.py
class UserManager(BaseUserManager):
use_in_migrations = True
def _create_user(self, email, password, **extra_fields):
if not email:
raise ValueError('The given email must be set')
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return User
def create_user(self, email, password=None, **extra_fields):
extra_fields.setdefault('is_super', False)
return self._create_user(email, password, **extra_fields)
def create_superuser(self, email, password, **extra_fields):
extra_fields.setdefault('is_superuser', True)
extra_fields.setdefault('is_staff', True)
if extra_fields.get('is_superuser') is not True:
raise ValueError('Superuser must have is_superuser=True')
if extra_fields.get('is_staff') is not True:
raise ValueError('Superuser must have is_staff=True')
return self._create_user(email, password, **extra_fields)
class User(AbstractBaseUser, PermissionsMixin):
rank = [
('Supporter', 'Supporter (non-member)'),
('Anak', 'Anak'),
('Uso', 'Uso'),
('Chief', 'Chief'),
]
tribe = [
('NaKoaHema', 'Na Koa Hema'),
('Alakai', 'Alaka\'i')
]
username = models.CharField("user name", max_length=50, default='', unique=True)
email = models.EmailField("email address", max_length=30, unique=True, blank=True)
first_name = models.CharField("first name", max_length=50)
last_name = models.CharField("last name", max_length=50)
is_active = models.BooleanField('active', default=True)
# password = models.CharField("password", unique=True, max_length=32, default='')
id = models.AutoField(primary_key=True)
is_staff = models.BooleanField('staff status', default=False)
date_joined = models.DateField('date_joined', default=timezone.now)
ranking = models.CharField(choices=rank, max_length=50, default="Supporter")
tribe = models.CharField(choices=tribe, max_length=50, default="None")
objects = UserManager()
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email', 'password'] # 'ranking'
# Magic method returns string of self
def __str__(self):
return f"User {self.first_name} {self.last_name} rank {self.rank}".strip()
@property
def get_full_name(self):
return f"{self.first_name} {self.last_name}".strip()
class Anak(User):
def __init__(self, tribe, *args, **kwargs):
super().__init__(*args, **kwargs)
self.tribe = tribe.title()
self.rank = User.rank[1]
tribe = [
('NaKoaHema', 'Na Koa Hema'),
('Alakai', 'Alaka\'i')
]
我不能 100% 确定是否正确理解了您的意图,但正如我所看到的,您使用自己的 class 重新定义了 Django 的用户以使用其他内容(等级、部落)对其进行扩展。
更优雅的方法(在我看来)是创建一个附加模型,该模型将包含特定字段并与标准 Django 用户模型一对一连接。所以你的 models.py 将是:
from django.db import models
from django.contrib.auth.models import User
class Anak(models.Model):
rank = [
('Supporter', 'Supporter (non-member)'),
('Anak', 'Anak'),
('Uso', 'Uso'),
('Chief', 'Chief'),
]
tribe = [
('NaKoaHema', 'Na Koa Hema'),
('Alakai', 'Alaka\'i')
]
user = models.OneToOneField(User, on_delete=models.CASCADE) # one Anak instance associated with User instance
tribe = models.CharField(choices=tribe, max_length=50, default="None")
ranking = models.CharField(choices=rank, max_length=50, default="Supporter")
def save(self, *args, **kwargs):
# Create dependent User if not exist
if not self.user.pk:
self.user = User.objects.create_user(username=self.user.username, password=self.user.password)
self.user.is_staff = False
# logic that you need before saving (if needed)
self.tribe = tribe.title()
self.rank = User.rank[1]
self.user.save() # mandatory as create_user is not recognized as save operation
super().save(*args, **kwargs)
因此,现在您可以使用您的表单创建用户 和 Anak 与用户一对一关联。
附加提示 - 当用户已经创建并登录时 - 您的 request.user 将包含一个包含相关用户的用户模型对象。所以你可以用它来 create/update 相关的 Anak。即:
if response.method == 'POST':
anak = models.Anak.objects.get_or_create(user=response.user) # get Anak if exists, create - otherwise
anak_form = AnakRegisterForm(instance=anak, data=response.POST) # update anak from above
if anak_form.is_valid():
anak_form.save()
因此,您将使用标准 Django 用户(无需自己重新定义用户)并将 Anak 信息保存在单独的 table 中,仅在需要时作为标准用户行为的扩展创建
我正在创建一个用于注册的多步骤用户表单。它背后的想法是,当用户注册时,它会获取他们的注册信息。然后,它保存用户信息。在注册表单中,如果用户选择了某个选项(rank = 'Anak'),他们将被重定向到获取部落名称的基本表单。我想要它做的是将部落名称保存到刚刚创建的用户帐户中,但我在执行此操作时遇到了麻烦,因为 Django 中的基本表单没有 save() 函数。
forms.py
class RegisterForm(UserCreationForm):
email = forms.EmailField(
initial='',
required=True,
help_text='Please enter a valid email address'
)
rank = forms.ChoiceField(
label='Are you a PSMC member?',
choices=SavBlock.models.User.rank,
initial=False,
required=True,
help_text='Member accounts will be validated with your HC.',
)
class Meta:
model = User
# username = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
fields = ['username', 'first_name', 'last_name', 'email',
'rank', 'password1', 'password2']
def save(self, commit=True):
user = super(RegisterForm, self).save(commit=False)
user.email = self.cleaned_data['email']
user.ranking = self.cleaned_data['rank']
if commit:
user.save()
return user
class AnakRegisterForm(Form):
tribe = forms.ChoiceField(
label='What tribe are you from, Uce?',
choices=SavBlock.models.Anak.tribe,
initial=False,
required=True,
help_text='Member accounts will be validated with your HC.'
)
class Meta:
model = Anak
fields = ['tribe']
def save(self, commit=True):
user = super(RegisterForm, self).save(commit=False)
user.tribe = self.cleaned_data['tribe']
if commit:
user.save()
return user
views.py
def register(response):
context = {}
# temp_key = {}
if response.method == "POST":
form = RegisterForm(response.POST)
if form.is_valid():
form.save()
if form.cleaned_data.get('rank') == 'Anak':
# temp_key[form.cleaned_data.get('username')] = form.cleaned_data
return redirect('anak_register')
# anak_register(form.cleaned_data)
messages.success(response, 'Registration successful. Please login.')
return redirect('login')
else:
context['register'] = form
else:
form = RegisterForm()
context['register'] = form
return render(request=response, template_name='register/register.html', context={'form': form})
def anak_register(response):
context = {}
if response.method == 'POST':
anak_form = AnakRegisterForm(response.POST)
if anak_form.is_valid():
# TODO: The form obtains the tribe information from the user. Now we must save this information into the
# users account.
"""
anak_form = RegisterForm.save(register)
return anak_form
"""
else:
context['register'] = anak_form
render(request=response, template_name='register/register.html', context={'form': anak_form})
else:
anak_form = AnakRegisterForm(response.POST)
context['anak_register'] = anak_form
# messages.error(request, 'Unsuccessful registration. Invalid information.')
return render(request=response, template_name='register/anak_register.html', context={'form': anak_form})
在重定向到 anak_register 之前,UserCreationForm 会保存用户信息。 anak_form 包含一些我想关联到刚创建的用户帐户的信息,但就像我说的,我不确定该怎么做。可能有更简单的方法
models.py
class UserManager(BaseUserManager):
use_in_migrations = True
def _create_user(self, email, password, **extra_fields):
if not email:
raise ValueError('The given email must be set')
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return User
def create_user(self, email, password=None, **extra_fields):
extra_fields.setdefault('is_super', False)
return self._create_user(email, password, **extra_fields)
def create_superuser(self, email, password, **extra_fields):
extra_fields.setdefault('is_superuser', True)
extra_fields.setdefault('is_staff', True)
if extra_fields.get('is_superuser') is not True:
raise ValueError('Superuser must have is_superuser=True')
if extra_fields.get('is_staff') is not True:
raise ValueError('Superuser must have is_staff=True')
return self._create_user(email, password, **extra_fields)
class User(AbstractBaseUser, PermissionsMixin):
rank = [
('Supporter', 'Supporter (non-member)'),
('Anak', 'Anak'),
('Uso', 'Uso'),
('Chief', 'Chief'),
]
tribe = [
('NaKoaHema', 'Na Koa Hema'),
('Alakai', 'Alaka\'i')
]
username = models.CharField("user name", max_length=50, default='', unique=True)
email = models.EmailField("email address", max_length=30, unique=True, blank=True)
first_name = models.CharField("first name", max_length=50)
last_name = models.CharField("last name", max_length=50)
is_active = models.BooleanField('active', default=True)
# password = models.CharField("password", unique=True, max_length=32, default='')
id = models.AutoField(primary_key=True)
is_staff = models.BooleanField('staff status', default=False)
date_joined = models.DateField('date_joined', default=timezone.now)
ranking = models.CharField(choices=rank, max_length=50, default="Supporter")
tribe = models.CharField(choices=tribe, max_length=50, default="None")
objects = UserManager()
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email', 'password'] # 'ranking'
# Magic method returns string of self
def __str__(self):
return f"User {self.first_name} {self.last_name} rank {self.rank}".strip()
@property
def get_full_name(self):
return f"{self.first_name} {self.last_name}".strip()
class Anak(User):
def __init__(self, tribe, *args, **kwargs):
super().__init__(*args, **kwargs)
self.tribe = tribe.title()
self.rank = User.rank[1]
tribe = [
('NaKoaHema', 'Na Koa Hema'),
('Alakai', 'Alaka\'i')
]
我不能 100% 确定是否正确理解了您的意图,但正如我所看到的,您使用自己的 class 重新定义了 Django 的用户以使用其他内容(等级、部落)对其进行扩展。
更优雅的方法(在我看来)是创建一个附加模型,该模型将包含特定字段并与标准 Django 用户模型一对一连接。所以你的 models.py 将是:
from django.db import models
from django.contrib.auth.models import User
class Anak(models.Model):
rank = [
('Supporter', 'Supporter (non-member)'),
('Anak', 'Anak'),
('Uso', 'Uso'),
('Chief', 'Chief'),
]
tribe = [
('NaKoaHema', 'Na Koa Hema'),
('Alakai', 'Alaka\'i')
]
user = models.OneToOneField(User, on_delete=models.CASCADE) # one Anak instance associated with User instance
tribe = models.CharField(choices=tribe, max_length=50, default="None")
ranking = models.CharField(choices=rank, max_length=50, default="Supporter")
def save(self, *args, **kwargs):
# Create dependent User if not exist
if not self.user.pk:
self.user = User.objects.create_user(username=self.user.username, password=self.user.password)
self.user.is_staff = False
# logic that you need before saving (if needed)
self.tribe = tribe.title()
self.rank = User.rank[1]
self.user.save() # mandatory as create_user is not recognized as save operation
super().save(*args, **kwargs)
因此,现在您可以使用您的表单创建用户 和 Anak 与用户一对一关联。
附加提示 - 当用户已经创建并登录时 - 您的 request.user 将包含一个包含相关用户的用户模型对象。所以你可以用它来 create/update 相关的 Anak。即:
if response.method == 'POST':
anak = models.Anak.objects.get_or_create(user=response.user) # get Anak if exists, create - otherwise
anak_form = AnakRegisterForm(instance=anak, data=response.POST) # update anak from above
if anak_form.is_valid():
anak_form.save()
因此,您将使用标准 Django 用户(无需自己重新定义用户)并将 Anak 信息保存在单独的 table 中,仅在需要时作为标准用户行为的扩展创建