ERROR: repetitive record violates the singular constraint "user_otherinfo_user_id_key"
DETAIL: The key "(user_id) = (52)" already exists.
models.py
class OtherInfo(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE)
phone = models.CharField(max_length=11,verbose_name="phone number")
location = models.CharField(max_length=50,verbose_name="location")
profile_image = models.FileField(blank = True,null = True,verbose_name="image")
class Meta:
verbose_name_plural = 'Other informations'
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
OtherInfo.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.otherinfo.save()
forms.py
class LoginForm(forms.Form):
username = forms.CharField(label = "Username")
password = forms.CharField(label = "Parola",widget = forms.PasswordInput)
class RegisterForm(forms.ModelForm):
password1 = forms.CharField(max_length=100, label='Parola',widget=forms.PasswordInput())
password2 = forms.CharField(max_length=100, label='Parola again', widget=forms.PasswordInput())
phone_number = forms.CharField(required=False, max_length=11, label='Phone Number')
location = forms.CharField(required=False, max_length=50, label='Location')
profile_image = forms.FileField(required=False, label="Image")
class Meta:
model = User
fields = [
'first_name',
'last_name',
'email',
'username',
'password1',
'password2',
'phone_number',
'location',
'profile_image',
]
def clean_password2(self):
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords do not match!")
return password2
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ('first_name', 'last_name', 'email')
class ProfileForm(forms.ModelForm):
class Meta:
model = OtherInfo
fields = ('phone', 'location', 'profile_image')
views.py
#login_required
#transaction.atomic
def updateprofile(request):
if request.method == 'POST':
user_form = UserForm(request.POST, instance=request.user)
profile_form = ProfileForm(request.POST, instance=request.user.otherinfo)
if user_form.is_valid() and profile_form.is_valid():
user_form.save()
profile_form.save()
messages.success(request, _('Your profile has been successfully updated!'))
return redirect('/user/profile/')
else:
messages.error(request, _('Please correct the following error.'))
else:
user_form = UserForm(instance=request.user)
profile_form = ProfileForm(instance=request.user.otherinfo)
return render(request, 'user/update_user.html', {
'user_form': user_form,
'profile_form': profile_form
})
def register(request):
form = RegisterForm(request.POST or None,request.FILES or None )
if form.is_valid():
user = form.save(commit=False)
first_name = form.cleaned_data.get('first_name')
last_name = form.cleaned_data.get('last_name')
username = form.cleaned_data.get("username")
email = form.cleaned_data.get('email')
password = form.cleaned_data.get('password1')
phone = form.cleaned_data.get('phone_number')
location = form.cleaned_data.get('location')
profile_image = form.cleaned_data.get('profile_image')
user.set_password(password)
user.save()
new_user = authenticate(username=user.username, first_name=first_name, last_name=last_name, email=email, password=password)
OtherInfo.objects.create(user=new_user,phone=phone,location=location,
profile_image=profile_image)
login(request,new_user)
messages.info(request,"Successfully Register ...")
return redirect("/")
context = {
"form" : form
}
return render(request,"user/register.html",context)
In Django, the user can register before updating the profile. When I add the profile update code, now the user is failing to register. How can I solve the problem?
It's simply a matter of not creating twice a OtherInfo for the same User:
in the post_save handler of saving a User, you create a OtherInfo object for the user.
in your view, you first create the User, hence you already create the OtherInfo associated with the user.
then you have OtherInfo.objects.create(user=new_user,phone=phone,location=location,
profile_image=profile_image)
This last instruction will fail, because you're trying to create a second OtherInfo for the same user. So you can do two things:
Remove the post_save signal handler that creates the OtherInfo object
or
Update new_user.otherinfo by setting the various values and saving it instead of creating it.
You need to delete the data entry with id=51.
The error you get is related to database, that the entry with id you are trying to create already exists.
Drop your database and create a new one(If you are not on a production environment)
Related
So, I am a beginner and I'm coding a django application that has a 3 user types in total but to make the code readable and understandable I'm just gonna assume we have 2 user types. One is a doctor and one is a patient.
I've created this custom user so far:
in models.py
class User(AbstractUser):
is_doc = models.BooleanField(default=False)
is_patient = models.BooleanField(default=False)
objects = UserManager()
manager.py
class UserManager(BaseUserManager):
def create_user(self, email, password=None):
if email is None:
raise TypeError('Users must have an email address.')
user = self.model(email=self.normalize_email(email))
user.set_password(password)
user.save()
return user
def create_patient(self, email, password):
if password is None:
raise TypeError('Must have a password')
user = self.model(email=self.normalize_email(email))
user.set_password(password)
user.is_patient = True
user.save()
def create_superuser(self, email, password):
if password is None:
raise TypeError('Superusers must have a password.')
user = self.create_user(email, password)
user.is_superuser = True
user.is_staff = True
user.save()
return user
Patient Model is as follows:
class Patient(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
first_name = models.CharField(max_length=70)
last_name = models.CharField(max_length=70)
address = models.CharField(max_length=210)
phone = models.CharField(max_length=15)
email = models.EmailField(max_length=110)
password = models.CharField(max_length=65)
def __str__(self):
return self.first_name + " " + self.last_name
My form for Patient:
class PatientForm(forms.ModelForm):
class Meta:
model = Patient
fields = ['first_name', 'last_name', 'address', 'phone', 'email', 'password']
widgets = {
'first_name': forms.TextInput(attrs={'placeholder': 'First Name'}),
'last_name': forms.TextInput(attrs={'placeholder': 'Last Name'}),
'address': forms.TextInput(attrs={'placeholder': 'Address'}),
'phone': forms.TextInput(attrs={'placeholder': 'Phone Number'}),
'email': forms.EmailInput(attrs={'placeholder': 'Email'}),
'password': forms.PasswordInput(attrs={'placeholder': 'Password (Minimum Length: 8)'}),
}
Current Views.py:
def RegPatient(request):
if request.method == "POST":
form = PatientForm(request.POST)
if form.is_valid():
FName = form.cleaned_data['first_name']
LName = form.cleaned_data['last_name']
C_Address = form.cleaned_data['address']
C_Phone = form.cleaned_data['phone']
C_Email = form.cleaned_data['email']
C_Password = form.cleaned_data['password']
Reg = Patient(first_name= FName, last_name= LName, address= C_Address, phone= C_Phone, email= C_Email, password= C_Password)
Reg.save()
return HttpResponseRedirect('/Login/')
else:
for field in form.errors:
form[field].field.widget.attrs['class'] += ' is-invalid'
return render(request, 'Home/RegPatient.html', {'form': form})
else:
form = PatientForm()
return render(request, 'Home/RegPatient.html', {'form': form})
I have separate signups for patient and doctor and don't want a user type field in my form so I have all the detail fields in my form except user type.
How should my view look like so that it saves Patient with a user type is_patient? and am I missing something out? Cause I've tried to edit it so many times, tried getting help from Django Docs but I'm still stuck.
First, lets talk about the Manager and Models. The Manager you are using is not really necessary, its possible to just set up the field on User object creation. As for the Model you can use model inheritance to have an extended Patient model based on your User model:
class User(AbstractUser):
is_doctor = models.BooleanField(default=False)
is_patient = models.BooleanField(default=False)
class Patient(User):
address = models.CharField(max_length=210)
phone = models.CharField(max_length=15)
class Meta:
verbose_name_plural = "Patients"
Although, I would say the right approach to your problem is to use Django authentication groups, instead of adding fields to your User model.
As for the signup form, it should contain confirmation and validation of the password and the username field unless you are doing a login with email. To hold the information of is_patient field, use an HiddenInput (I couldn't replicate it with 'ModelForm' will need to dig further into that.):
forms.py
from django.contrib.auth.hashers import make_password
from django.forms import ValidationError
class PatientSignUpForm(forms.Form):
username = forms.CharField(
required=True,
widget=forms.TextInput(attrs={'placeholder': 'username'}))
first_name = forms.CharField(
required=True,
widget=forms.TextInput(attrs={'placeholder': 'first name'}))
last_name = forms.CharField(
required=False,
widget=forms.TextInput(attrs={'placeholder': 'last name'}))
email = forms.EmailField(
required=True,
widget=forms.TextInput(attrs={'placeholder': 'email'}))
address = forms.CharField(
required=True,
widget=forms.TextInput(attrs={'placeholder': 'address'}))
phone = forms.CharField(
required=True,
widget=forms.TextInput(attrs={'placeholder': 'XXX-XXXXXXXXX'}))
password = forms.CharField(required=True, widget=forms.PasswordInput)
password_confirmation = forms.CharField(required=True, widget=forms.PasswordInput)
is_patient = forms.BooleanField(widget=forms.HiddenInput)
def clean(self):
password = self.cleaned_data['password']
password_confirmation = self.cleaned_data['password_confirmation']
if len(password) < 8 or len(password_confirmation) < 8:
raise ValidationError("Passwords must have at least 8 characters")
elif password != password_confirmation:
raise ValidationError("Passwords must be equal")
else:
self.cleaned_data['password'] = make_password(self.cleaned_data['password_confirmation'])
del self.cleaned_data['password_confirmation']
return self.cleaned_data
Lastly, in views.py create an instance of PatientSignUpForm with an initial value for is_patient field.
from app import models, forms
def patient_signup(request):
if request.method == 'POST':
form = forms.PatientSignUpForm(request.POST)
if form.is_valid():
models.Patient.objects.create(**form.cleaned_data)
return redirect('')
else:
form = forms.PatientSignUpForm(initial={'is_patient': True})
return render(request, 'patient_signup.html', {'form': form})
I have a register user form which is doing all the validation as expected. However, it is not saving. I am not able to figure out the reason. How do I debug it ? Any help ? I am a newbie to forms and formviews any good document with example would really help me.
class RegisterForm(forms.ModelForm):
phone_number = forms.IntegerField(required=True)
password1 = forms.CharField(widget=forms.PasswordInput())
password2 = forms.CharField(widget=forms.PasswordInput())
country_code = forms.IntegerField()
#schools = school.objects.all()
#school_name = forms.ModelChoiceField(queryset=school.objects.distinct())
MIN_LENGTH = 4
class Meta:
model = User
fields = ['username','country_code','phone_number', 'password1', 'password2',
'full_name' ]
def clean_phone_number(self):
phone_number = self.data.get('phone_number')
print(phone_number)
if User.objects.filter(phone_number=phone_number).exists():
raise forms.ValidationError(
_("Another user with this phone number already exists"))
if len(phone_number) == 10 and phone_number.isdigit():
pass
else:
raise forms.ValidationError(
_("Invalid Phone Number"))
return phone_number
def save(self, *args, **kwargs):
print("saving")
user = super(RegisterForm, self).save(*args, **kwargs)
user.set_password(self.cleaned_data['password1'])
print('Saving user with country_code', user.country_code)
user.save()
return user
Views.py
class RegisterView(SuccessMessageMixin, FormView):
template_name = 'register-2.html'
form_class = RegisterForm
success_message = "One-Time password sent to your registered mobile number.\
The verification code is valid for 10 minutes."
def form_valid(self, form):
full_name=self.request.POST["full_name"]
user = form.save()
print(user.id)
username = self.request.POST['username']
password = self.request.POST['password1']
user = authenticate(username=username, password=password)
kwargs = {'user': user}
self.request.method = 'POST'
print("User created")
The print in clean_phone_number works however, save does not work
I had issue in the my form. One of the field was disabled and the value was not captured because of that.
However to identify that I used
def form_invalid(self,form):
# Add action to invalid form phase
messages.error(self.request, form.errors)
return self.render_to_response(self.get_context_data(form=form))
how to make a user registration form including a model field in it as a required field?
like i want college field to show up on registration page as a drop-down menu
my models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
college = models.ForeignKey(College, on_delete=models.CASCADE)
#receiver(post_save, sender=User)
def update_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
instance.profile.save()
class College(models.Model):
col = models.CharField(max_length=100)
def __str__(self):
return self.col
my forms.py
class UserForm(UserCreationForm):
col = College.objects.all()
password1 = forms.CharField(widget=forms.PasswordInput)
password2 = forms.CharField(widget=forms.PasswordInput)
college = forms.ChoiceField(widget=forms.Select(choices=col))
class Meta:
model = User
fields = ('username', 'college', 'password1', 'password2',)
and the views.py includes this:
def signup(request):
if request.method == 'POST':
form = UserForm(request.POST)
if form.is_valid():
user = form.save()
user.refresh_from_db()
user.save()
raw_password = form.cleaned_data.get('password1')
user = authenticate(username=user.username, password=raw_password)
login(request, user)
return redirect('home')
else:
form = UserForm()
return render(request, 'registration_form.html', {'form': form})
UPDATE
got to know about ModelChoiceField and made these changes in forms.py:
class UserForm(UserCreationForm):
password1 = forms.CharField(widget=forms.PasswordInput)
password2 = forms.CharField(widget=forms.PasswordInput)
college = forms.ModelChoiceField(queryset=College.objects.all(), empty_label=None)
class Meta:
model = User
fields = ('username', 'college', 'password1', 'password2')
but the college chosen is not being saved in the profile
also the admin section is giving an RelatedObjectDoesNotExist at /admin/login/ error
I have a custom registration form for my users to add a profile on my app. However, a bug has recently popped up in that the form is not saving the information that is put into all the fields.
My user model, MyUser has a ManyToMany relationship with another model, Interest, and this is where the issues are arising. I am not sure if it is the RegistrationForm or the register view that is causing it, so I have included both below, as well as the model code.
I also have a view for the users to update their profile, also included, once it is created, and this is working absolutely perfectly. This is the personal view.
As I say, it is only the Interest field that is not being returned, even though it is being filled in on the registration page.
Any help or advice is much appreciated, thanks.
models.py
class Interest(models.Model):
title = models.TextField()
def __unicode__(self):
return self.title
class MyUser(AbstractBaseUser):
email = models.EmailField(
verbose_name='email address',
max_length=255,
unique=True,
)
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=40)
date_of_birth = models.DateField()
course = models.ForeignKey(Course, null=True)
location = models.ForeignKey(Location, null=True)
interests = models.ManyToManyField(Interest, null=True)
bio = models.TextField(blank=True)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
objects = MyUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['date_of_birth']
views.py
def register(request):
if request.method == 'POST':
form = RegistrationForm(data=request.POST)
if form.is_valid():
form.save()
return redirect('/friends/home/')
else:
form = RegistrationForm()
template = "adduser.html"
data = { 'form': form, }
return render_to_response(template, data, context_instance=RequestContext(request))
#login_required(login_url='/friends/login/')
def personal(request):
"""
Personal data of the user profile
"""
profile = request.user
if request.method == "POST":
form = ProfileForm(request.POST, instance=profile)
if form.is_valid():
form.save()
messages.add_message(request, messages.INFO, _("Your profile information has been updated successfully."))
return redirect('/friends/success/')
else:
form = ProfileForm(instance=profile)
template = "update_profile.html"
data = { 'section': 'personal', 'form': form, }
return render_to_response(template, data, context_instance=RequestContext(request))
forms.py
class RegistrationForm(forms.ModelForm):
"""
Form for registering a new account.
"""
email = forms.EmailField(widget=forms.TextInput, label="Email")
password1 = forms.CharField(widget=forms.PasswordInput,
label="Password")
password2 = forms.CharField(widget=forms.PasswordInput,
label="Password (again)")
course = forms.ModelChoiceField(queryset=Course.objects.order_by('title'))
location = forms.ModelChoiceField(queryset=Location.objects.order_by('location'))
class Meta:
model = MyUser
fields = [
'first_name',
'last_name',
'date_of_birth',
'email',
'password1',
'password2',
'course',
'location',
'interests',
'bio',
]
def __init__(self, *args, **kwargs):#Sort interests alphabetically
super(RegistrationForm, self).__init__(*args, **kwargs)
self.fields['interests'].queryset = Interest.objects.order_by('title')
def clean(self):
cleaned_data = super(RegistrationForm, self).clean()
if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data:
if self.cleaned_data['password1'] != self.cleaned_data['password2']:
raise forms.ValidationError("Passwords don't match. Please enter again.")
return self.cleaned_data
def save(self, commit=True):
user = super(RegistrationForm, self).save(commit=False)
user.set_password(self.cleaned_data['password1'])
if commit:
user.save()
return user
Since you use commit=false for the super(RegistrationForm, self).save call, it doesn't save the many-to-many field. You therefore need to add self.save_m2m() after user.save() in your save() method of RegistrationForm.
See https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#the-save-method
EDIT: save_m2m() is on the Form, not the Model
I am using Django 1.5. I am a custom User model like this:
class User(AbstractBaseUser):
#id = models.IntegerField(primary_key=True)
#identifier = models.CharField(max_length=40, unique=True, db_index=True)
username = models.CharField(max_length=90, unique=True, db_index=True)
create_time = models.DateTimeField(null=True, blank=True)
update_time = models.DateTimeField(null=True, blank=True)
email = models.CharField(max_length=225)
#password = models.CharField(max_length=120)
external = models.IntegerField(null=True, blank=True)
deleted = models.IntegerField(null=True, blank=True)
purged = models.IntegerField(null=True, blank=True)
form_values_id = models.IntegerField(null=True, blank=True)
disk_usage = models.DecimalField(null=True, max_digits=16, decimal_places=0, blank=True)
objects = UserManager()
USERNAME_FIELD = 'email'
class Meta:
db_table = u'galaxy_user'
I have a custom authentication:
class AuthBackend:
def authenticate(self, username=None, password=None):
if '#' in username:
kwargs = {'email': username}
else:
kwargs = {'username': username}
try:
user = User.objects.get(**kwargs)
if user.check_password(password):
return user
except User.DoesNotExist:
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
Even after entering the correct username and password check_password() always returning false so that I can't login. I tried that in terminal too:
user.check_password(password)
is always returning False.
#views.py:
def login_backend(request):
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
state = "Username or Password Incorrect!"
if user is not None:
login(request, user)
return HttpResponseRedirect('/overview/')
else:
return render_to_response('login_backend.html', {'state':state}, context_instance=RequestContext(request))
else:
return render_to_response('login_backend.html', context_instance=RequestContext(request))
The problem is that when you create your CustomUser, you save the password in open-way(without hashing). Can you give me your RegistrationForm code?
In my case:
# forms/register.py
class RegistrationForm(forms.ModelForm):
"""
Form for registering a new account.
"""
class Meta:
model = CustomUser
fields = ['username', 'password', 'email']
Register-handler:
# views.py
def register(request):
"""
User registration view.
"""
if request.method == 'POST':
form = RegistrationForm(data=request.POST)
if form.is_valid():
user = form.save() # Save your password as a simple String
return redirect('/')
else:
form = RegistrationForm()
return render(request, 'news/register.html', {'form': form})
So when you try to login:
if user.check_password(password):
return user
check_password always returns False.
Solution:
To set password properly, you should redefine save() method in RegistrationForm:
# forms/register.py
class RegistrationForm(forms.ModelForm):
"""
Form for registering a new account.
"""
class Meta:
model = CustomUser
fields = ['username', 'password', 'email']
def save(self, commit=True):
user = super(RegistrationForm, self).save(commit=False)
user.set_password(user.password) # set password properly before commit
if commit:
user.save()
return user
Or simply change handler:
def register(request):
"""
User registration view.
"""
if request.method == 'POST':
form = RegistrationForm(data=request.POST)
if form.is_valid():
user = form.save(commit=False)
user.set_password(request.POST["password"])
user.save()
return redirect('/')
else:
form = RegistrationForm()
return render(request, 'news/register.html', {'form': form})