I have created a form in my app where I can take details of a suer. Now i am able to edit the form but i am not able to save the data. I would like to save the changed data and move on.
It says: Adult with this User already exists.
My urls.py:
url(r'^home/editform/(?P<userpk>[^/]+)/$', 'lexuseditform', name='lexuseditform'),
url(r'^home/edited/(?P<userpk>[^/]+)/$', 'lexusedited', name='lexusedited')
My views.py:
#login_required
def lexuseditform(request,userpk):
if int(userpk) != request.user.pk:
return HttpResponseForbidden()
else:
adult = Adult(user=request.user)
if request.method == 'POST': # If the form has been submitted...
form = AdultForm(request.POST,instance=adult) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
form.save()
redirect_url = reverse('lexusedited')
return HttpResponseRedirect(redirect_url) # Redirect after POST
else:
form = AdultForm(instance=adult) # An unbound form
return render(request,'lexus/lexuseditform.html', {'form': form})
#login_required
def lexusedited(request,userpk):
return render(request,'lexus/lexusedited.html')
My forms.py:
from models import Adult
from django.forms import ModelForm
class AdultForm(ModelForm):
"""
Edit Profile Information
"""
class Meta:
model = Adult
fields = ('user', 'email','fullname')
My models.py:
from django.db import models
from django.contrib.auth.models import User
class Adult(models.Model):
"""
Adult Information
"""
user = models.OneToOneField(User)
fullname = models.CharField(max_length=100)
email = models.EmailField()
def __unicode__(self):
return self.user.username
Not sure where my error is. Need some guidance.. Thanks..
Although you haven't shown the Adult model structure, I bet it has something like
class Adult(models.Model):
user = models.ForeignKey(User, unique=True)
That's why you cannot save new Adult() with the same user(name). So you have to either change the models, or to load existing Adult for the specified user:
if Adult.objects.filter(user=request.user).exists():
adult = Adult.objects.get(user=request.user) # load existing Adult
else:
adult = Adult(user=request.user) # create new Adult
But I don't know how your form and models look like.
UPDATE:
or using:
adult, is_created = Adult.objects.get_or_create(user=request.user)
A bit of a guess since you didn't post the code for your form and model, but assuming the form is a regular model form, your problem very probably comes from your Adult model having a unique constraint on User (either a OneToOneField or a ForeignKey with unique=True). Since you create a new Adult instance for the form, it violates the unique constraint. Assuming (once again) this constraint is what you want, and your view is supposed to either create a related Adult instance for the user if it doesn't yet exist or edit the existing one, you need to first check if there's an Adult instance for the user:
#login_required
def lexuseditform(request):
try:
adult = Adult.objects.get(user=request.user)
except Adult.DoesNotExist:
adult = Adult(user=request.user)
#... your code here
Also note that I removed the userpk argument and test against request.user.pk which is useless if you think about it.
Correct Version(Refering to Tisho's Answer):
My views.py:
#login_required
def lexuseditform(request,userpk):
if Adult.objects.filter(user=request.user).exists():
adult = Adult.objects.get(user=request.user) # load existing Adult
else:
adult = Adult(user=request.user) # create new Adult
if request.method == 'POST': # If the form has been submitted...
form = AdultForm(request.POST,instance=adult) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
form.save()
redirect_url = reverse('lexusedited')
return HttpResponseRedirect(redirect_url) # Redirect after POST
else:
form = AdultForm(instance=adult) # An unbound form
return render(request,'lexus/lexuseditform.html', {'form': form})
Related
My Django site has two sorts of user profiles, one for regular users (MyUserProfile) and one, which extends it, for employees (EmployeeUserProfile). models.py:
class MyUserProfile(models.Model):
user = models.OneToOneField('auth.user', related_name='userprofile')
www = models.URLField(null=True, blank=True, verbose_name='website')
affiliation = models.CharField(max_length=200,null=True,blank=True)
...
class EmployeeUserProfile(MyUserProfile):
start_date = models.DateField()
current = models.BooleanField(default=True)
...
I have a problem implementing an profile update form for employees. I create the form thus (forms.py):
from django.forms import ModelForm
from .models import EmployeeUserProfile
class EmployeeUserProfileForm(ModelForm):
class Meta:
model = EmployeeUserProfile
exclude = ['user', 'current']
But when I come to updating the profile:
from django.template import RequestContext
from .forms import EmployeeUserProfileForm
def update_profile(request):
if request.method == 'POST':
form = EmployeeUserProfileForm(request.POST)
if form.is_valid():
profile = form.save(commit=False)
profile.user = request.user
profile.save()
else:
user = request.user
profile = user.userprofile.employeeuserprofile
form = EmployeeUserProfileForm(instance=profile)
c = {'form': form}
return render_to_response('pages/profile/update.html', c,
context_instance=RequestContext(request))
On 'submit' for updating an already-created profile I get an IntegrityError. For example, (1062, "Duplicate entry '2' for key 'user_id'"). Apparently Django is trying to add a copy of the user instead of updating the existing one.
What am I doing wrong?
You need to pass the instance argument in the POST condition too
form = EmployeeUserProfileForm(request.POST)
should be
form = EmployeeUserProfileForm(request.POST, instance=profile)
By not sending the instance argument, form tries to create instead of update. Note that this would mean you would have to move the else block above if
Something like this:
#login_required
def update_profile(request):
user = request.user
profile = user.userprofile.employeeuserprofile
form = EmployeeUserProfileForm(instance=profile)
if request.method == 'POST':
form = EmployeeUserProfileForm(request.POST, instance=profile)
if form.is_valid():
profile = form.save(commit=False)
profile.user = request.user
profile.save()
c = {'form': form}
return render_to_response('pages/profile/update.html', c,
context_instance=RequestContext(request))
You might also want to use the login_required decorator so that you dont run into issues with anonymous user, etc..
I'd like to create a "update user's profile" page to let users modify their profiles, so I come up with the following models:
class Profile(models.Model):
user = models.OneToOneField(User)
nick_name = models.CharField(blank=True,max_length=100)
school = models.CharField(blank=True,max_length=100)
motto = models.CharField(blank=True,max_length=100)
class ProfileForm(ModelForm):
class Meta:
model = Profile
And my view is designed as:
#login_required
def update_profile_view(request):
if request.method == 'POST':
user = request.user
try:
profile = user.get_profile()
except Exception:
profile = Profile.objects.create(user=user)
form = ProfileForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
profile.nick_name = cd['nick_name']
profile.school = cd['school']
profile.motto = cd['motto']
profile.save()
return HttpResponseRedirect('/main_page/')
else:
form = ProfileForm()
return render(request, 'update_profile.html', {'form':form})
The relationship between an user and a profile is apparently 1to1, and with request I can determine the current user. So the form's user field needn't to be filled. Unfortunately, this couldn't pass "the form.is_valid()" test. And it seems hard to modify a form before "is_valid" invoked. For simplicity, I don't want to create my own Form Class, neither do I want to write customized form validation. Is there any other way to solve the problem?
Your view can be greatly simplified:
#login_required
def update_profile_view(request):
try:
profile = Profile.objects.get(user=request.user)
except Profile.DoesNotExist:
profile = None
form = ProfileForm(request.POST or None, instance=profile)
if request.method == 'POST':
if form.is_valid():
form.save()
return HttpResponseRedirect('/main_page/')
return render(request, 'update_profile.html', {'form':form})
There's no need to manually assign the fields like you're doing. Django ORM knows how to do an insert versus an update automatically. So if you simply pass the ProfileForm an instance of a Profile, it knows to do an update. If there's no instance of a profile, it's going to do an insert.
Now, if you want to make the assignment of the user transparent in the UI, you'll need to exclude the user field from the form and assign it yourself. There are a couple of different ways to do that.
I would also recommend leveraging reverse in your redirect so you don't have a hard-coded path.
You have basicly two choices:
1 Modification of ProfileForm:
class ProfileForm(ModelForm):
class Meta:
model = Profileclass
exclude = ('user',)
2 Change this lines as follows:
form = ProfileForm(request.POST, instance=profile)
if form.is_valid():
updated_profile = form.save()
You can either set the user field's value to not required in the init method (self.fields['user'].required = False) of the form or set the user not editable in the model (editable=False).
In your view method, call profile = form.save(commit=False), then do profile.user = your_user and profile.save()
You don't have to apply the cleaned data manually to the profile since the ModelForm does this.
Let's say that I have a model that handles recipes, and I want to allow users to input their own recipes via a form. I then want to associate that recipe entry with the user ID of the user who inputted it. My guess is that my model would look something like this:
class Recipe(models.Model):
name = models.CharField(max_length=100)
body = models.TextField()
creator = models.ManyToManyField(User)
def __unicode__(self):
return self.creator
Is that correct? And if I created a model form, it would look something like this:
class RecipeForm(ModelForm):
class Meta:
model = Recipe
But how would I go about automatically passing the user information to the Recipe model upon submission? Would this take place in my view?
My current view is like this:
def recipe(request):
if request.method == 'POST':
form = RecipeForm(request.POST) #if POST method, bound form to POST data
if form.is_valid():
form.save()
else:
form = RecipeForm() #unbound form.
recipe_list = Recipe.objects.all()
return render_to_response('forms/recipes.html',
{'form': form, 'recipe_list': recipe_list},
context_instance = RequestContext(request))
How would I set the user to the model before saving it?
Yes, your view would need to set the user on the recipe model before saving it.
Edit:
You should accept Ignacio's answer, since he added it in the comment.
Here is how you would add your user:
from django.shortcuts import render
def recipe(request):
if request.method == 'POST':
form = RecipeForm(request.POST) #if POST method, bound form to POST data
if form.is_valid():
obj = form.save(commit=False) # don't save to DB
obj.creator = request.user # adds the user
obj.save()
else:
form = RecipeForm() #unbound form.
recipe_list = Recipe.objects.all()
return render(request,'forms/recipes.html',
{'form': form, 'recipe_list': recipe_list})
I have a form like so:
from django import forms
from django.contrib.auth.models import User
from django_countries.countries import COUNTRIES
from statuses.models import Status
class StatusForm(forms.Form):
country = forms.ChoiceField(choices=COUNTRIES)
mood = forms.IntegerField()
sleep_quality = forms.IntegerField()
This form is only displayed to the users who are logged in, how can I set request.user so that when the user submits this form, I can associate the form entry to them? My model looks like the following with the the user FK:
from django.db import models
from django.contrib.auth.models import User
from django_countries import CountryField
class Status(models.Model):
user = models.ForeignKey(User)
country = CountryField()
mood = models.SmallIntegerField(default=4)
sleep_quality = models.SmallIntegerField(default=4)
Here is my view for this form as well:
#login_required
def index(request, template_name="status/index.html"):
if request.method == 'POST':
postdata = request.POST
form = StatusForm(postdata)
if form.is_valid():
messages.success(request, 'Something happened, good!')
return redirect(urlresolvers.reverse('profile'))
else:
form = StatusForm()
context = RequestContext(request, { 'form': form })
return render_to_response(template_name, context)
I thought maybe I should create a hiddenfield and store request.user in there but that does not seem safe as it can easily be edited with firebug and such. Any suggestions as to how I can store request.user for this form?
Thanks!
The current user will be present in the request as request.user so you don't need to include it in the form. Instead why not leverage ModelForms as they will deal with linking your object to your form.
class StatusForm(forms.ModelForm):
country = forms.ChoiceField(choices=COUNTRIES)
# The other fields are automatically included, we just overwrite country
class Meta:
model = Status
exclude = ("user")
Then in your view:
...
form = StatusForm(request.POST):
if form.is_valid():
# Because your model requires that user is present, we validate the form and
# save it without commiting, manually assigning the user to the object and resaving
obj = form.save(commit=False)
obj.user = request.user
obj.save()
messages.success(request, 'Something happened, good!')
return redirect(urlresolvers.reverse('profile'))
...
I'm using django-registration for registration and login purpose. My Models and Forms.py are working fine. The problem is I want to store the currently logged user's id in the user field of the following Model:
MALE = 1
FEMALE = 2
SEX_CHOICES = (
(MALE,'Male'),
(FEMALE,'Female'),
)
class UserProfile(models.Model):
#user = models.IntegerField() # update : Changed to ForeignKey.
user = models.ForeignKey(User)
gender = models.IntegerField(choices = SEX_CHOICES,null=True, blank=True)
zip_code = models.CharField(max_length=100,null=True, blank=True)
language = models.ManyToManyField(Category)
My ModelForm:
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
widgets = {'language': forms.CheckboxSelectMultiple}
Update 2: Here is my view:
def some_view(request):
if request.method == 'POST':
form = UserProfileForm(request.POST)
if form.is_valid():
form.save()
else:
form = UserProfileForm()
Update: I can get currently logged in user's using {{ user.id }} in template. But now How do i pass this id to user field?
Well, in you view you can access the currently logged user via request.user.
Make this user initial data in your Form :
#login_required
def my_view(request):
logged_user = request.user
initial = {'user': logged_user}
form = MyForm(request.POST or None, initial=initial)
# Here your logical code
# ...
return HttpResponse(...)
And if you are using a ModelForm:
#login_required
def my_view(request):
logged_user = request.user
form = MyUserProfileModelForm(
request.POST or None,\
instance=logged_user.get_profile())
# Here your logical code
# ...
return HttpResponse(...)
Note: get_profile() is a OneToOneField and may raise a DoesNotExist exception if your database is screwed (which may happen if you have tried different things here).