I have a ModelForm:
class UploadForm(forms.ModelForm):
class Meta:
model = Image
fields = ['image']
which is based on model Image
class Image(models.Model):
def content_file_name(instance, filename):
return filename
name = models.CharField(max_length=50)
image = models.ImageField(upload_to=content_file_name)
user = models.ForeignKey(MyUser, related_name='image')
In views.py, I try to save the image name and user object (from session) along with the uploaded image to database.
form1 = UploadForm(request.POST, request.FILES)
if form1.is_valid():
image = request.FILES['image'] # image is of UploadedFile class
form1.Meta.model.name = image.name
form1.Meta.model.user = get_object_or_404(MyUser,username=request.session['user'])
form1.save()
return render(request, '16_upload01.html', context)
Problem is only the uploaded image gets saved. Error message in browser:
IntegrityError at /competition-big/big1/upload
comp_app_image.user_id may not be NULL
I confirmed this by checking on SQL command:
INSERT INTO "comp_app_image" ("name", "image", "user_id") VALUES ('', 'grey-160-100_1.png', None)
I figure that image name and user are not bounded to form1. But how can I achieve that?
EDIT
After some digging, I know I messed up with above code. Now I changed my code to this:
if form1.is_valid():
form1.cleaned_data['user'] = get_object_or_404(MyUser, username=request.session['user'])
form1.save()
But I still get null user_id error.
EDIT 2
Thanks Jacinda. Now I get this cleaner code:
if form1.is_valid():
form1.cleaned_data['user'] = request.user
form1.save()
But error null user_id remains.
If this form can only be accessed by a logged in user, use the login_required decorator, and you should always redirect after a POST. You should also read this section in the ModelForms documentation; which describes how to properly use a model form that has limited fields.
from django.shortcuts import redirect
from django.contrib.auth.decorators import login_required
#login_required
def your_view(request):
form1 = UploadForm(request.POST, request.FILES)
if form1.is_valid():
image = request.FILES['image'] # image is of UploadedFile class
obj = form1.save(commit=False)
obj.name = image.name
obj.user = request.user
obj.save()
return redirect('your-view-name')
else:
return render(request, 'form.html', {'form': form1})
I think your issue is probably this line:
form1.Meta.model.user = get_object_or_404(MyUser,username=request.session['user'])
When I try and use your syntax (using the Django default django.contrib.auth) I get a KeyError on 'user'.
What I've always done when I need information about the user associated with a request is this:
username = request.user.username
Reference: https://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpRequest.user
Of course, this will only work if your users are required to be logged in to upload images.
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..
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',)
I have a ModelForm containing a field: image = models.ImageField:
class InstanceForm(ModelForm):
class Meta:
model = Instance
exclude = ('created_at','author',)
And my view is:
def add_instance(request):
if request.user.is_authenticated():
if request.POST:
form=InstanceForm(request.POST,request.FILES)
if form.is_valid():
new_instance=form.save(commit=False)
new_instance.author=request.user.username
new_instance.save()
locals().update(csrf(request))
return render_to_response(...)
else:
return render_to_response(...)
else:
form=InstanceForm()
return render_to_response(...)
else: return HttpResponse(...)
When my form is not valid it shows not only errors, but field 'image' without path to image. It's working in this way, even if I have chosen image at first using Browse.
I'm trying to allow users to upload an image. When users are first created, they are given a unique ID / primary key. When users upload an image, I want to save that image in a folder depending on what the users unique ID is. For example, if the users unique ID is 1, I want to save it in
1/uploadedPhotos/imageName
This is my model:
def get_file_path(instance, filename):
return os.path.join('%s/uploadedPhotos' % instance.user_id, filename)
class UserImages(models.Model):
user = models.ForeignKey(User)
photo = models.ImageField(upload_to=get_file_path)
and this is my form:
class UploadImageForm(forms.ModelForm):
class Meta:
model = UserImages
fields = ['photo']
and this is my view:
def uploadImageView(request):
if request.method == 'POST':
form = UploadImageForm(request.POST, request.FILES)
if form.is_valid():
# file is saved
form.save()
return redirect('/')
else:
form = UploadImageForm()
return render(request, 'uploadImagePage.html', {'uploadImageForm': form})
The URL which calls the uploadImageView view is /uploadImage/. when I go to that URL and upload an image using the uploadImageForm, it gives an error saying:
IntegrityError at /uploadImage/
null value in column "user_id" violates not-null constraint
DETAIL: Failing row contains (1, null, None/uploadedPhotos/imageName.png).
and the traceback leads back to the
form.save()
line in my uploadImageView. What am I doing wrong to cause this error?
Your UserImages model requires user but your form UploadImageForm is asking only asking for photo. You need to set user, try something like this:
def uploadImageView(request):
if request.method == 'POST':
form = UploadImageForm(request.POST, request.FILES)
if form.is_valid():
# file is saved
instance = form.save(commit=False)
instance.user = request.user
instance.save()
return redirect('/')
else:
form = UploadImageForm()
return render(request, 'uploadImagePage.html', {'uploadImageForm': form})
obj = form.save(commit=False)
obj.user = request.user
obj.save()
You must extract user from request.user and add it to form data.
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'))
...