I've created a wizard form that worked up until I added an ImageField.
When I got to submit the form with an image file chosen I get returned to the page saying the ImageField is required.
I've set up the MEDIA_ROOT and have that working.
Here are the snippets of code I think are in question:
models.py
# CreatePuzzleWizard forms
class uploadForm(forms.Form):
puzzle_image = forms.ImageField()
puzzle_name = forms.CharField(max_length=30, widget=forms.TextInput(attrs={'class':'form-control'}))
puzzle_description = forms.CharField(max_length=300, widget=forms.TextInput(attrs={'class':'form-control'}))
views.py
class CreatePuzzleWizard(SessionWizardView):
template_name = "create.html"
file_storage = FileSystemStorage(location=os.path.join(settings.MEDIA_ROOT, 'tmp'))
def done(self, form_list, **kwargs):
form_data = process_form_data(form_list)
return render('complete.html', {'form_list', form_list})
def process_form_data(form_list):
form_data = [form.cleaned_data for form in form_list]
# do stuff with form data
return form_data
I get this issue:
http://imgur.com/vFSuprr
I can't seem to find the problem on the internet. I'm using Django 1.6.1
The Django Docs specify that there is unfortunately a little work to do when binding an uploaded file to a form field:
https://docs.djangoproject.com/en/dev/ref/forms/api/#binding-uploaded-files-to-a-form
Related
I am doing an online classroom project in Django where I created a model named create_course which is accessible by teachers. Now I am trying to design this as the teacher who creates a class only he can see this after login another teacher shouldn't see his classes and how to add students into that particular class I created
the course model
class course(models.Model):
course_name = models.CharField(max_length=200)
course_id = models.CharField(max_length=10)
course_sec = models.IntegerField()
classroom_id = models.CharField(max_length=50,unique=True)
created_by = models.ForeignKey(User,on_delete=models.CASCADE)
here if I use "the created_by" field in forms it appears to be a drop-down menu where every user is showing but I want to automatically save the user who creates the object
views.py
def teacher_view(request, *args, **kwargs):
form = add_course(request.POST or None)
context = {}
if form.is_valid():
form.save()
return HttpResponse("Class Created Sucessfully")
context['add_courses'] = form
return render(request, 'teacherview.html', context)
forms.py
from django import forms
from .models import course
class add_course(forms.ModelForm):
class Meta:
model = course
fields = ('course_name', 'course_id', 'course_sec', 'classroom_id')
You can inject the logged in user to the .created_by of the .instance in the form, so:
from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect
#login_required
def teacher_view(request, *args, **kwargs):
if request.method == 'POST':
form = add_course(request.POST, request.FILES)
if form.is_valid():
form.instance.created_by = request.user
form.save()
return redirect('name-of-some-view')
else:
form = add_course()
return render(request, 'teacherview.html', {'add_courses': form})
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.
Note: You can limit views to a view to authenticated users with the
#login_required decorator [Django-doc].
Note: Usually a Form or a ModelForm ends with a …Form suffix,
to avoid collisions with the name of the model, and to make it clear that we are
working with a form. Therefore it might be better to use CourseForm instead of
add_course.
Note: Models in Django are written in PascalCase, not snake_case,
so you might want to rename the model from course to Course.
Note: In case of a successful POST request, you should make a redirect
[Django-doc]
to implement the Post/Redirect/Get pattern [wiki].
This avoids that you make the same POST request when the user refreshes the
browser.
In your view use commit=False to stop the form from saving until you add the created_by field.
def teacher_view(request, *args, **kwargs):
form = add_course(request.POST or None)
context = {}
if form.is_valid():
course = form.save(commit=False)
course.created_by = request.user
course.save()
return HttpResponse("Class Created Sucessfully")
context['add_courses'] = form
return render(request, 'teacherview.html', context)
I am building a PollApp and I am stuck on a Problem..
I build a poll add feature for add images in the poll . BUT images are not adding in the Poll.
When i select images in field then save it redirect to the same page and saying "This field is required".
models.py
class ImageChoice(models.Model):
image_poll = models.ForeignKey(ImagePoll, on_delete=models.CASCADE)
choice_image = models.FileField()
views.py
def polls_add(request):
if request.method == 'POST':
form = ImagePollAddForm(request.POST)
if form.is_valid():
poll = form.save(commit=False)
poll.owner = request.user
poll.save()
new_choice1 = ImageChoice(poll=poll, image=form.cleaned_data['choice1']).save()
context = {
'form': form,
}
return render(request, 'add_poll.html', context)
forms.py
class ImagePollAddForm(forms.ModelForm):
choice1 = forms.FileField()
class Meta:
model = ImagePoll
fields = ['choice1']
When i try to upload images in each field then click to save then it is not uploading.
I also tried by adding request.FILES in form = ImagePollAddForm(request.POST) BUT it is showing ImageChoice() got an unexpected keyword argument 'poll' .
You use invalid field name, your model has image_poll field but not poll. And your model does not have image field but choice_image
ImageChoice(image_poll=poll, choice_image=form.cleaned_data['choice1']).save()
I'm trying to set the current 'upload_to=' directory equal to the current logged-in user's username so that each file uploaded is saved into the user's own directory.
I have tried to follow the django documentation which looks similar to this...
from django.db import models
def user_directory_path(instance, filename):
# file will be uploaded to MEDIA_ROOT/user_<id>/<filename>
return 'user_{0}/{1}'.format(instance.user.id, filename)
class UploadReports(models.Model):
upload = models.FileField(upload_to=user_directory_path, null=True)
I have also tried to add RequestMiddleware to achieve this but it felt wrong as I was implementing it.
I want it to grab the current logged in user and use it in the directory path. The error that comes up is: AttributeError at /stylist/
'UploadReports' object has no attribute 'user'
Solution: The Django documentation does not specify a user needing to be added to the model - though it does expect one.
When it was done the model looked like this:
def user_directory_path(instance, filename):
# file will be uploaded to MEDIA_ROOT/user_<id>/<filename>
return 'uploads/{0}/{1}'.format(instance.user.username, filename)
class UploadReports(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
xls = models.FileField(upload_to=user_directory_path)
If you add the user here then DO NOT FORGET to add the user to the field of the form as such:
class DocumentForm(forms.ModelForm):
class Meta:
model = UploadReports
fields = ('xls', 'user')
Once you add the field to the form there becomes a new field in the template form with the list of possible users. As most people probably don't, I didn't want the form to include the user. Therefore, as ilja stated, you must exclude the form as such:
class DocumentForm(forms.ModelForm):
class Meta:
model = UploadReports
fields = ('xls', 'user')
exclude = ('user', ) # make sure this is a tuple
Once the form is excluded it will go back to throwing the error that the user does not exist. So you need to add the user in the post method of theviews.py as such:
class FileUploadView(View):
form_class = DocumentForm
success_url = reverse_lazy('home')
template_name = 'file_upload.html'
def get(self, request, *args, **kwargs):
upload_form = self.form_class()
return render(request, self.template_name, {'upload_form': upload_form})
def post(self, request, *args, **kwargs):
upload_form = self.form_class(request.POST, request.FILES)
if upload_form.is_valid():
form_done = upload_form.save(commit=False) # save the form but don't commit
form_done.user = self.request.user # request the user
form_done.save() # finish saving the form
return redirect(self.success_url)
else:
return render(request, self.template_name, {'upload_form': upload_form})
It is not an easy task but it is rewarding when it is done!
I'm tring write a view to administrator update a password of another user, using Class Based Views and model SetPasswordForm of Django.
My views.py
class UserSetPasswordUpdateView(GroupRequiredMixin, FormView):
form_class = forms.SetPasswordForm
model = User
template_name = 'app/admin/object_update.html'
success_url = reverse_lazy('portal:admin_user')
group_required = u"Administrator"
def get_form_kwargs(self):
kwargs = super(UserSetPasswordUpdateView, self).get_form_kwargs()
kwargs['user'] = User.objects.filter(pk=self.kwargs['pk'])
return kwargs
update_change_password = UserSetPasswordUpdateView.as_view()
My urls.py
url(r'^app/admin/update-user-pass/(?P<pk>[0-9]+)$', update_views.update_change_password, name='update_change_password'),
And don't show any errors, just go to success_url, but the password don't updated.
Your view is based on FormView. This doesn't have any knowledge of model forms, and doesn't do anything with the data other than check that it is valid. SetPasswordForm changes the password when the form is saved, but this view never does this.
You could override form_valid to call form.save() explicitly, but it would be better to use a more appropriate base class such as UpdateView which will do that for you.
I implemented some ImageFields in my model and installed PIL (not the cleanest install). Things seem to work as I get an upload button in the admin and when I call the .url property in the view I get the string with the filename + its upload property.
The problem is that the file is not there, apparently it doesnt get uploaded once I save the model.
Any idea?
Thanks
Here's a sample of my code situation
models.py
class My_Model(models.Model):
[...]
image = models.ImageField(upload_to = 'images/my_models/main')
view.py
'image': query.my_model.image.url
result:
static/images/my_models/main/theimage.png
Make sure that you're binding request.FILES to the form when POSTing, and that the form is declared as multi-part in the template
Here's the view from one of my applications:
#login_required
def submit(request):
if request.method == 'POST':
(Photo.objects.count()+1, request.FILES['photo'].name.split(".")[1]), request.FILES['photo'])}
form = PhotoForm(request.POST, request.FILES)
if form.is_valid():
new = Photo(photo=request.FILES['photo'], name=request.POST['name'])
new.save()
return HttpResponseRedirect('/') # Redirect after POST
else:
form = PhotoForm()
return render_to_response('app/submit.html', {'form': form}, context_instance=RequestContext(request))
and the PhotoForm class:
class PhotoForm(forms.ModelForm):
class Meta:
model = Photo
fields = ('name', 'photo')