In my Django project i create an app to have additional information about registered users. So my model looks like this:
class UserProfile(models.Model):
class Meta:
verbose_name_plural = u'User Profile'
user = models.OneToOneField(User)
birthday = models.DateField(blank=True, null=True)
avatar = models.ImageField(upload_to='media/profile/avatar', blank=True, null=True)
name = models.CharField(blank=True, null=True, max_length=20)
surname = models.CharField(blank=True, null=True, max_length=50)
phone = models.CharField(blank=True, null=True, max_length=12)
def __unicode__(self):
return '%s' % self.user
Here is my registration form:
class RegistrationForm(ModelForm):
username = forms.CharField(label=(u'Username'))
email = forms.EmailField(label=(u'Email'))
password = forms.CharField(label=(u'Password'), widget=forms.PasswordInput(render_value=False))
password1 = forms.CharField(label=(u'Password'), widget=forms.PasswordInput(render_value=False))
class Meta:
model = UserProfile
exclude = ('user',)
fields = ('username', 'email', 'password', 'password1')
def clean_email(self):
email = self.cleaned_data['email']
try:
User.objects.get(email=email)
except User.DoesNotExist:
return email
raise forms.ValidationError("User with same email already exist, please change your email")
And here is view of my registration form:
def UserProfileRegistration(request):
if request.user.is_authenticated():
return HttpResponseRedirect('/profile/')
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
user = User.objects.create_user(username=form.cleaned_data['username'], email=form.cleaned_data['email'], password=form.cleaned_data['password'])
user.save()
user_profile = UserProfile(user=user)
user_profile.save()
return HttpResponseRedirect('/profile/')
else:
return render(request, 'profiles/registration.html', {'form':form})
else:
form = RegistrationForm()
context = {'form':form}
return render (request, 'profiles/registration.html', context)
In user profile i create modelform where user can fill the fields from UserProfile model:
class ExtraProfileDataForm(ModelForm):
name = forms.CharField(label=(u'Enter your name'))
surname = forms.CharField(label=(u'Enter your surname'))
phone = forms.CharField(label=(u'Enter your phone'))
birthday = forms.DateField(label=(u'Enter birthday'))
avatar = forms.ImageField(label=(u'Enter avatar'))
class Meta:
model = UserProfile
fields = ('name', 'surname', 'phone', 'birthday', 'avatar')
def __init__(self, *args, **kwargs):
super(ExtraProfileDataForm, self).__init__(*args, **kwargs)
for key in self.fields:
self.fields[key].required = False
This is the view of the model form:
#login_required
def UserFullDataForm(request):
if request.method == 'POST':
form = ExtraProfileDataForm(request.POST)
if form.is_valid():
profile_user = request.user
user_profile = UserProfile(user=profile_user)
user_profile.name = form.cleaned_data['name']
user_profile.surname = form.cleaned_data['surname']
user_profile.phone = form.cleaned_data['phone']
user_profile.birthday = form.cleaned_data['birthday']
user_profile.avatar = form.cleaned_data['avatar']
user_profile.save()
return HttpResponseRedirect('/profile/')
else:
return render(request, 'profiles/extra_profile.html', {'form':form})
else:
form = ExtraProfileDataForm()
context = {'form':form}
return render (request, 'profiles/extra_profile.html', context)
But when I fill this form I got the error:
duplicate key value violates unique constraint "profiles_userprofile_user_id_key" DETAIL: Key (user_id)=(23) already exists.
On the traceback i see that error in this line user_profile.save(). As i understand it happens because this script create new item with same id but not update it. What i have to change on my code to update existing item but not to create. Thank you.
You need to use get_or_create, which will return an existing item if it was found; otherwise create a new instance of the model.
In your user profile update view:
user_profile, created = UserProfile.objects.get_or_create(user=profile.user)
Now, instead of creating a new profile each time - you are updating if a profile for that user already exists.
Related
I wrote the following code:
class RegisterForm(UserCreationForm):
email = forms.EmailField(max_length=200, help_text='Required')
class Meta:
model = CustomUser
fields = ('username', 'email', 'password1', 'password2')
#login_required(login_url="/login")
def index(request):
if request.method == 'POST':
form = RegisterForm(request.POST)
if form.is_valid():
profile = Profile().save()
user = form
user.profile = profile
user.save()
return redirect('users')
else:
print(form.errors)
else:
form = RegisterForm()
user_model = get_user_model()
users = user_model.objects.all()
paginator = Paginator(users, 15)
page = request.GET.get('page')
users = paginator.get_page(page)
return render(request, 'users/index.html', {'users': users, 'form': form})
class Profile(models.Model):
has_premium_until = models.DateTimeField(null=True, blank=True)
has_premium = models.BooleanField(default=False)
has_telegram_premium_until = models.DateTimeField(null=True, blank=True)
has_telegram_premium = models.BooleanField(default=False)
updated_at = models.DateTimeField(auto_now=True)
created_at = models.DateTimeField(auto_now_add=True)
class CustomUser(AbstractUser):
email = models.EmailField(max_length=255, unique=True)
profile = models.OneToOneField(Profile, on_delete=models.CASCADE, null=True)
When I'm submitting the form the user as well as the profile is created but the profile is not stored in the user (the profile_id stays null).
Anyone who can help me out?
Change your code to
if form.is_valid():
profile = Profile().save()
user = form.save(commit=False)
user.profile = profile
user.save()
return redirect('users')
This way the user object will be created and then you refer to the profile ju just created and save it.
There is however another way of doing it with signals:
#receiver(models.signals.post_save, sender=CustomUser)
def create_profile_on_user_reg(sender, instance, created,**kwargs):
if created:
instance.profile = Profile()
instance.save()
Check out more on Django signals documentation
I have a registration form which is an extension of UserCreationForm and I have a UserProfileForm. I am rendering both the forms to the same html during user registration.
The problem is, inputs are getting saved to the inbuilt users model but not to the Profile Model. No data is showing up in Profile Model.
I have tried many ways and looked for many solution but unable to find the mistake.
My forms.py looks like this -
class RegistrationForm(UserCreationForm):
email = forms.EmailField(required=True)
first_name = forms.CharField(required=True)
last_name = forms.CharField(required=True)
username = forms.CharField(required=True)
class Meta:
model = User
fields = ['username',
'first_name',
'last_name',
'email',
'password1',
'password2'
]
def save(self,commit):
user = super(RegistrationForm,self).save(commit=False)
if commit:
user.save()
return user
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
exclude = ['user']
def save(self,commit):
user = super(RegistrationForm,self).save(commit=False)
USN =self.cleaned_data['USN']
year = self.cleaned_data['year']
sem = super(RegistrationForm,self).save(commit=False)
if commit:
user.save()
return user
Have created UserProfile model in models.py
class UserProfile(models.Model):
alphanumeric = RegexValidator(r'^[0-9A-Z]*$', 'Only alphanumeric
characters are allowed.')
user = models.OneToOneField(User, related_name =
'profile',on_delete=models.CASCADE)
USN = models.CharField(max_length=50, blank=True, null=True, validators=
[alphanumeric])
year = models.IntegerField(default=0)
sem = models.IntegerField(default=0)
def __str__(self):
return self.user.username
def create_profile(sender, **kwargs):
if kwargs['created']:
objects=models.Manager()
user_profile = UserProfile.objects.create(user=kwargs['instance'])
post_save.connect(create_profile, sender = User)
I have used both the forms in Views.py -
def register(request):
if request.method == 'POST':
form_1 = RegistrationForm(request.POST)
form_2 = UserProfileForm(request.POST)
if form_1.is_valid() and form_2.is_valid():
save_1 = form_1.save(commit = False)
save_2 = form_1.save(commit = False)
save_1.save()
save_2.save()
return render(request,'main/home.html')
else:
form_1 = RegistrationForm()
form_2 = UserProfileForm()
args = {'form_1':form_1,'form_2':form_2}
return render(request, 'account/register.html',args)
The username in the profile model object shows correctly, but other fields are not getting updated. I want other fields also getting updated in the profile object.
I need to get the selected value(s) of year from the PreceptorForm. I can get the internal_tel using post.internal_tel but I can't do that with year because it's a ManyToManyField. I need something like preceptor.year.add(post.year) but it gives me an error. What is the best way to do it?
models.py
class Year(models.Model):
year_number = models.IntegerField(choices=YEAR_CHOICES)
division = models.CharField(choices=DIVISION_CHOICES, max_length=1)
def getStudents(self):
results = Student.objects.filter(year=self)
return results
def __str__(self):
return "{}-{}".format(self.year_number, self.division)
class Preceptor(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete = models.CASCADE)
internal_tel = models.IntegerField(blank=True)
year = models.ManyToManyField(Year,blank=True,related_name='preceptores')
def getYear(self):
results = self.year.all()
return results
def __str__(self):
return "{} {}".format(self.user.first_name, self.user.last_name)
forms.py
class PreceptorForm(ModelForm):
class Meta:
model = Preceptor
fields = '__all__'
exclude = ['user']
views.py
def register_user(request):
if request.method == "POST":
form = PreceptorForm(request.POST)
username = request.POST['username']
password = request.POST['password']
sec_pass = request.POST['sec_password']
email = request.POST['email']
first_name = request.POST['first_name']
last_name = request.POST['last_name']
if form.is_valid():
if password == sec_pass:
user = User.objects.create_user(username, email, password)
user.is_active = True
user.first_name = first_name
user.last_name = last_name
user.save()
print "form"
post = form.save(commit=False)
post.user = user
preceptor = Preceptor(user=user,internal_tel=post.internal_tel)
preceptor.save()
preceptor.year.add(post.year)
preceptor.save()
return redirect('/')
else:
form = PreceptorForm()
return render(request, 'register.html', {'form': form})
I'm having this error at preceptor.year.add(post.year):
< Preceptor: 'name' > needs to have a value for field "id" before this many-to-many relationship can be used.
I'm new to django and my task is to make user able to create a lot profiles after registration when he's logged in.
This is my models.py:
class Profile(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(blank=False, max_length=100)
lastname = models.CharField( blank=False, max_length=100)
city = models.CharField( blank=True, max_length=100)
country = models.CharField( blank=True, max_length=100)
phonenumber = models.CharField(blank=False, null=True, max_length=20)
email = models.EmailField(blank=False, max_length=100)
date_of_birth = models.DateField( blank=True, null=True)
date_of_addition = models.DateField(auto_now=True, editable=False, null=True)
When I create my user, do login and press create profile button I get :
django.db.utils.IntegrityError: (1048, "Column 'user_id' cannot be null")
This is my views.py:
#login_required
def profile_create(request):
data = dict()
if request.method == 'POST':
form = ProfileForm(request.POST)
if form.is_valid():
form.save()
data['form_is_valid'] = True
profiles = Profile.objects.all()
data['html_profile_list'] = render_to_string('basic_app/users_list_1_10.html', {'profiles': profiles})
else:
data['form_is_valid'] = False
else:
form = ProfileForm()
context = {'form': form}
data['html_form'] = render_to_string('basic_app/partial_profile_create.html', context, request=request)
return JsonResponse(data)
def register(request):
registered = False
if request.method == "POST":
user_form = UserForm(data=request.POST)
if user_form.is_valid():
user = user_form.save()
user.set_password(user.password)
user.save()
registered = True
else:
print(user_form.errors)
else:
user_form = UserForm()
return render(request,'basic_app/registration.html',{'user_form':user_form,'registered':registered})
This is my forms.py:
from django import forms
from django.forms import ModelForm
from django.contrib.auth.models import User
from .models import Profile
class ProfileForm(ModelForm):
class Meta:
model = Profile
fields = ('name', 'lastname', 'city', 'country', 'phonenumber', 'email', 'date_of_birth')
class UserForm(ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
username = forms.CharField(help_text=False)
class Meta():
model = User
fields = ('username','password')
Thanks
It happens because in your Profile model you have user field which is ForeignKey. In Django ForeignKey is required by default, which means that you can't create new Profile without specifying user field. But you don't provide user in ProfileForm.
You can either provide user in ProfileForm or set user field as not required by adding:
user = models.ForeignKey(User, blank=True, null=True, on_delete=models.CASCADE)
I should request user before saving ProfileForm:
#login_required
def profile_create(request):
data = dict()
if request.method == 'POST':
form = ProfileForm(request.POST)
if form.is_valid():
add = form.save(commit=False)
add.user = request.user
add.save()
data['form_is_valid'] = True
profiles = Profile.objects.all()
data['html_profile_list'] = render_to_string('basic_app/users_list_1_10.html', {'profiles': profiles})
else:
data['form_is_valid'] = False
else:
form = ProfileForm()
context = {'form': form}
data['html_form'] = render_to_string('basic_app/partial_profile_create.html', context, request=request)
return JsonResponse(data)
When my users create a profile, their image gets saved fine but when they update it it doesn't get saved. I also don't know how to pull the pic so that they can see it before updating it.
This is the form:
class UpdateProfileForm(forms.ModelForm):
city = models.ForeignKey(City)
class Meta:
model = UserProfile
fields = ('city', 'profilepic')
def save(self, commit=True):
profile = super(UpdateProfileForm, self).save(commit=False)
if commit:
profile.save()
return profile
This is the view:
def updateprofile(request):
if request.method == 'POST':
update_user_form = UpdateUserForm(request.POST, instance=request.user)
update_profile_form = UpdateProfileForm(request.POST, request.FILES, instance=request.user.profile)
if update_user_form.is_valid() and update_profile_form.is_valid():
update_user_form.save()
'''************************************************'''
profile = update_profile_form.save(commit=False)
if 'profilepic' in request.FILES:
profile.profilepic = request.FILES['profilepic']
profile.save()
'''************************************************'''
return HttpResponseRedirect(reverse('index'))
else:
update_user_form = UpdateUserForm(instance=request.user)
update_profile_form = UpdateProfileForm(instance=request.user.profile)
return render(request, 'updateprofile.html', {'update_user_form' : update_user_form, 'update_profile_form' : update_profile_form})
And this is model:
# this is model for user
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='profile')
hobbies = models.ManyToManyField(Hobby)
languages = models.ManyToManyField(Language)
profilepic = models.ImageField(upload_to='static/images/Profile Pictures', blank=True)
city = models.ForeignKey(City)
slug = models.SlugField(unique=True)
average_rating = models.IntegerField(default=0)
ratings_count = models.IntegerField(default=0)
def save(self, *args, **kwargs):
# Uncomment if you don't want the slug to change every time the name changes
self.slug = slugify(self.user.username)
super(UserProfile, self).save(*args, **kwargs)
def __unicode__(self):
return self.user.username
Thank you.
Add request.FILES to the form:
update_profile_form = UpdateProfileForm(request.POST, request.FILES,
instance=request.user)
By default django doesn't includes files in request.POST
Also, I think instance for UserProfile model should be request.user.profile instead of request.user or am I missing something here?
Follow instructions from django-docs