Django forms and set initial value to logged in user? - django

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'))
...

Related

Saving Profile model after update: IntegrityError (duplicate user_id key)

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..

Django using a form with an ImageField and a User

In Django, the user can upload a comment with the image.
from sorl.thumbnail import ImageField
class Comment(models.Model):
count_votes = models.Integer(default=0)
user = models.ForeignKey(User)
thumb = ImageField(upload_to="thumbnails")
# ...
This is what I am trying to do :
# views.py
def add_comment(request):
if request.method == 'POST' and request.user.is_authenticated():
comment = Comment(user=request.user)
form = CommentForm(request.POST, request.FILES, instance=comment)
if form.is_valid():
form.save()
# ...
# forms.py
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
But there are some errors :
none of the fields are filled
the count_votes is not defaulted to 0 as I would like to
the user is not taken into account either
the image is said to be empty too
How can I achieve that ? I have read many questions on SO and tried various other things, like fill in things in the __init__ of the form, use initial instead of instance, ...
First, make sure in your template you have enctype="multipart/form-data" in your <form> tag, otherwise the image file will not get uploaded and your form will not validate (and thus, nothing will be added to the database).
In addition, you need to fix your views. Start by using the login_required decorator so that your view is restricted to logged-in users, and then fix your form logic:
from django.shortcuts import redirect, render
from django.contrib.auth.decorators import login_required
#login_required
def add_comment(request):
form = CommentForm(request.POST or None, request.FILES or None)
if form.is_valid():
obj = form.save(commit=False) # create the record, but don't save it
obj.user = request.user # add the user from the request
obj.save() # now save the record
return redirect('/')
return render(request, 'template.html', {'form': form})
Finally, in your form exclude the user because you will be adding it later. In fact, your form should just have the comment and image field. You don't need to include the count_votes field because it already has a default value; unless you want the user to modify this field.
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ('thumb', 'comment',)

Saving the edited information in Django

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})

Django: associating a user with model instance

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})

want to get currently logged user's id (using django-registration )

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).