Django注册表单中如何为选定类型用户自动创建对应关联模型实例
实现方案
首先注意你当前的Student模型存在id_number、year_level两个必填字段,现有注册表单没有对应字段,需要先补充否则无法创建Student实例。
步骤1:修改注册表单(forms.py)
给SignUpForm补充Student必填字段,同时增加校验规则:仅选择学生身份时要求填写对应字段。
class SignUpForm(UserCreationForm): # 原有字段保留 username = forms.CharField( widget=forms.TextInput( attrs={ "class": "form-control" } ) ) password1 = forms.CharField( widget=forms.PasswordInput( attrs={ "class": "form-control" } ) ) password2 = forms.CharField( widget=forms.PasswordInput( attrs={ "class": "form-control" } ) ) email = forms.CharField( widget=forms.TextInput( attrs={ "class": "form-control" } ) ) # 新增Student必填字段 id_number = forms.IntegerField( required=False, widget=forms.NumberInput(attrs={"class": "form-control"}) ) year_level = forms.IntegerField( required=False, widget=forms.NumberInput(attrs={"class": "form-control"}) ) class Meta: model = User fields = ('username', 'email', 'password1', 'password2', 'is_admin', 'is_teacher', 'is_student', 'id_number', 'year_level') # 表单校验:学生身份必须填对应字段 def clean(self): cleaned_data = super().clean() is_student = cleaned_data.get('is_student') if is_student: if not cleaned_data.get('id_number'): self.add_error('id_number', '学生身份必须填写学号') if not cleaned_data.get('year_level'): self.add_error('year_level', '学生身份必须填写年级') return cleaned_data
步骤2:修改注册视图(views.py)
在保存用户实例后,判断身份创建对应关联实例即可,代码如下:
def register(request): msg = None if request.method == 'POST': form = SignUpForm(request.POST) if form.is_valid(): user = form.save() # 新增身份判断逻辑 if user.is_student: Student.objects.create( name=user, id_number=form.cleaned_data.get('id_number'), year_level=form.cleaned_data.get('year_level') # 其他学生字段如果表单有补充,可在此处赋值 ) # 如果教师身份也需要自动生成关联实例,可增加下面这段 if user.is_teacher: Teacher.objects.create(name=user) msg = 'user created' return redirect('login_view') else: msg = 'form is not valid' else: form = SignUpForm() return render(request, 'register/register.html', {'form': form, 'msg': msg})
可选方案:用Django信号自动触发
如果不想把逻辑写在视图里,可通过post_save信号实现:User实例创建时自动判断身份生成关联实例。
- 在对应app目录下新建
signals.py:
from django.db.models.signals import post_save from django.dispatch import receiver from .models import User, Student, Teacher @receiver(post_save, sender=User) def create_related_profile(sender, instance, created, **kwargs): if created: if instance.is_student: # 注意使用信号需要提前处理好Student必填字段的取值,否则会报错 Student.objects.create(name=instance, id_number=xxx, year_level=xxx) if instance.is_teacher: Teacher.objects.create(name=instance)
- 在对应app的
apps.py中注册信号:
from django.apps import AppConfig class YourAppConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = '替换为你的app名称' def ready(self): import 替换为你的app名称.signals
内容的提问来源于stack exchange,提问作者Jack Junior
相关产品推荐
相关产品推荐

