当我想在Django中注册新用户时,收到以下警告:
UNIQUE constraint failed: polls_usuario.matriculaUsuario
当我通过管理员和主视图编辑注册表时,不会发生此错误。仅当创建新用户时才会发生此错误。当我通过视图注册创建用户时,将使用默认注册创建该用户。当我尝试通过管理员创建时,甚至没有创建用户。可能会发生什么?
views.py
def registrar(request):
if request.method == 'POST':
form = SignUpForm(request.POST)
usuario_form = UsuarioForm(request.POST)
if form.is_valid() and usuario_form.is_valid():
user = form.save(commit=False)
user.refresh_from_db() # load the profile instance created by the signal
user.usuario.matriculaUsuario = form.cleaned_data.get('matriculaUsuario')
usuario_form.save()
user.save()
raw_password = form.cleaned_data.get('password1')
user = authenticate(username=user.username, password=raw_password)
login(request,user)
return render(request, 'polls/index.html', user)
#return HttpResponseRedirect(reverse('/'))
#return redirect('/')
else:
form = SignUpForm()
usuario_form = UsuarioForm()
return render(request, 'polls/registrar.html', {'form': form , 'usuario_form':usuario_form})
forms.py
class UsuarioForm(forms.ModelForm):
class Meta:
model = Usuario
fields = ('matriculaUsuario',)
class SignUpForm(UserCreationForm):
first_name = forms.CharField(label='Primeiro Nome',max_length=30, required=False, help_text='Opcional.')
last_name = forms.CharField(label='Último Nome',max_length=30, required=False, help_text='Opcional.')
email = forms.EmailField(label='E-mail',max_length=254, help_text='Informe o seu e-mail (Requerido)')
username = forms.CharField(label='Nome de usuário', min_length=4, max_length=150)
password1 = forms.CharField(label='Senha', widget=forms.PasswordInput)
password2 = forms.CharField(label='Confirmação da senha', widget=forms.PasswordInput)
matriculaUsuario = forms.CharField(label='Matrícula',max_length=12,validators=[ validators.RegexValidator(re.compile('^[0-9]{12}$'), _('Digite uma matrícula válida'), _('invalid'))])
class Meta:
model = User
fields = ['first_name', 'last_name','username','matriculaUsuario','email','password1', 'password2',]
def clean_username(self):
username = self.cleaned_data['username'].lower()
r = User.objects.filter(username=username)
if r.count():
raise ValidationError("Nome de usuário já cadastrado")
return username
def clean_email(self):
email = self.cleaned_data['email'].lower()
r = User.objects.filter(email=email)
if r.count():
raise ValidationError("E-mail já cadastrado")
return email
def clean_password2(self):
password1 = self.cleaned_data.get('password1')
password2 = self.cleaned_data.get('password2')
if password1 and password2 and password1 != password2:
raise ValidationError("Senhas não conferem")
return password2
def save(self, commit=True):
user = User.objects.create_user(
self.cleaned_data['username'],
self.cleaned_data['email'],
self.cleaned_data['password1']
)
return user
class EditProfileForm(forms.ModelForm):
first_name = forms.CharField(label='Nome')
last_name = forms.CharField(label='Sobrenome')
username = forms.CharField(min_length=4, max_length=150,help_text=("Insira um novo nome de usuário"), label='Nome de usuário')
email = forms.EmailField(label='E-mail')
matriculaUsuario = forms.CharField(label='Matrícula', max_length=12,validators=[ validators.RegexValidator(re.compile('^[0-9]{12}$'), _('Digite uma matrícula válida'), _('invalid'))])
class Meta:
model = User
fields = ['first_name', 'last_name','username','matriculaUsuario','email']
models.py
class Usuario(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE,null=True)
matriculaUsuario = models.CharField(default='000000000000',max_length=12,primary_key=True,null=False,help_text=_('São requeridos os 12 dígitos referentes à sua matrícula'), validators=[ validators.RegexValidator(re.compile('^[0-9]{12}$'), _('Digite uma matrícula válida'), _('invalid'))])
def __str__(self):
return self.user.username
@receiver(post_save, sender=User)
def update_user_usuario(sender, instance, created, **kwargs):
if created:
Usuario.objects.create(user=instance)
instance.usuario.save()
@receiver(post_save, sender=User)
def create_user_usuario(sender, instance, created, **kwargs):
if created:
Usuario.objects.create(user=instance)
post_save.connect(create_user_usuario,sender=User)
@receiver(post_save, sender=User)
def save_user_usuario(sender, instance, created,**kwargs):
if created:
instance.usuario.save()
答案 0 :(得分:0)
在您的models.py中,将matriculaUsuario设置为primary_key:
class Usuario(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE,null=True)
matriculaUsuario = models.CharField(default='000000000000',max_length=12,primary_key=True,null=False,help_text=_('São requeridos os 12 dígitos referentes à sua matrícula'), validators=[ validators.RegexValidator(re.compile('^[0-9]{12}$'), _('Digite uma matrícula válida'), _('invalid'))]) # you set this as primary key
您还为其设置了默认值='000000000000'。这很不好,因为在创建新用户并保存表单时,该字段每次都获得相同的值('000000000000')。因为您设置primary_key = True,所以这是不可能的。主键是对象的唯一标识符,因此它应该是唯一的。
primary_key = True表示null = False和unique = True。一个对象只允许使用一个主键。
参考:https://django.readthedocs.io/en/2.1.x/ref/models/fields.html
考虑使用自动字段,该字段将在创建对象时自动增加pk:
matriculaUsuario = models.AutoField(primary_key=True)
UUIDField还是另一个不错的选择,它可以长期使用较大的数据库,并且使攻击者难以猜测对象的pk。
matriculaUsuario = models.UUIDField(primary_key=True, unique=True, default=uuid.uuid4, editable=False)
此外,我认为您不应该允许用户在EditProfile表单中编辑其matricualUsuario,因为这会造成问题。