Form not valid in django - django

Hi I am learning Django for a project and I am trying to upload a file along with a on option in dropdown list through a form using POST.
Here are my files:
views.py
from __future__ import unicode_literals
from django.shortcuts import render
from django.http import HttpResponse
from .forms import UploadFileForm
# function to handle an uploaded file.
from save_uploaded_file import handle_uploaded_file
def index(request):
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
handle_uploaded_file(request.FILES['file'])
return render(request, 'viewer_app/display_image.html')
else:
print('error')
return render(request, 'viewer_app/index.html', {'form': form})
else:
return render(request, 'viewer_app/index.html')
forms.py
from django import forms
class UploadFileForm(forms.Form):
file = forms.FileField()
displayType = forms.ChoiceField(widget=forms.Select(), required=True)
save_uploaded_file.py
def handle_uploaded_file(f):
with open('static/viewer_app/temp.exr', 'wb+') as recieved_exr:
for chunk in f.chunks():
recieved_exr.write(chunk)
index.html
<div id="formDiv" style="display:none;" class="form" >
<form method="post" enctype="multipart/form-data" class="form-style">
<label for="browse">Upload file</label>
<input type="file" value="Browse" id="brow" /><br></br>
<label for="display">Display type</label>
<select id="display-type" name="display">
<option id="RGB1" value="RGB1">RGB1</option>
<option id="RGB2" value="RGB2">RGB2</option>
<option id="RGB3" value="RGB3">RGB3</option>
<option id="RGB4" value="RGB4">RGB4</option>
</select><br></br>
<input type="submit" value="Show file" id="showimage"/><br></br>
{% csrf_token %}
</form>
</div>
So, after I run the server to display the page and I select the upload and click submit, it doesn't upload and save the file and in the terminal I see the "error" text in the terminal which is displayed due to from.is_valid() not being true.
I tried to add {{ form.errors }} {{ form.non_field_errors }} to the html file but I still don't know exactly what is that I am doing wrong.

Also I can see the absence of name attributes inside your <input> tag and a potentially wrong name attribute inside your <select> tag. You should put the exact name of the field inside your html 's name attribute for the form to get bounded. Same goes for the <select> tags.
Try putting:
<input type="file" value="Browse" id="brow" name="file"/>
and
<select id="display-type" name="displayType">
and probably your problem will be solved.
If I may suggest, why aren't you using the standard django template form tags, Such as {{ form.as_p }} ? These methods are quite handy and will also handle the errors successfully. You should try using them. check them here
EDIT
You haven't given any choices attribute to you ChoiceField in your forms.py. Make sure to give a attribute choices as a tuple to your ChoiceField. It can be done as:
#import ugettext_lazy
from django.utils.translation import ugettext_lazy as _
#inside your form class
class UploadFileForm(forms.Form):
CHOICES = (
('RGB1', _('RGB1')),
('RGB2', _('RGB2')),
('RGB3', _('RGB3')),
#And so on
)
#First option in the tuple is stored in db. Second is displayed in Forms.
displayType = forms.ChoiceField(widget=forms.Select(), required=True , choices = CHOICES)
file = forms.FileField()
EDIT 2:
Get the file url as below,
from django.contrib.staticfiles.templatetags.staticfiles import static
url = static('viewer_app/temp.exr')
#See if temp.exr exists prior to this. Otherwise create a file manually or through python.
Then open the file by supplying this url.
Again I would recommend you to check ModelForms. They'll completely eliminate the need to write files this way.
Hope it helps. Thanks.

Related

Django Model form does not display when I include it in the Parent template

Long story short , My form.html Only shows submit button rather than all the fields of the model form
<div class="form">
<form action="{% url 'name' %}" method="POST">
{% csrf_token %}
{{ form }}
<input type="submit" value="submit">
<p style="color: red;">Watch it before it gets removed on The Internet</p>
</div>
Here is forms.py
from django import forms
from django.forms.models import ModelForm
from .models import Person
class PersonForm(forms.ModelForm):
class Meta:
model = Person
fields = ['name','email']
when I tried adding html inputs manually on forms.html I was able to make the inputs show on the page , Is something wrong with importing model form like that ??
Also what's weird is that when I click on that submit button since its the only one showing on the page … It takes me to a plain form.html with validation error , since I was submitting empty values
Here is how I include it in the Parent template {% include "form.html" %}
This is my view for that form
def get_name(request):
if request.method=="POST":
form = PersonForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('thank-you'))
else:
form = PersonForm()
return render(request,'form.html',{ 'form': form })
It works well when I don't just include in other template when it is all alone

DJANGO - Redirect to different page with form data

Hi i want to redirect to a destination page with the from data. For example when user fills a form the data inputted in the form, i want that to be outputted on the destination page
my codes are as follows:-
source page(experiment.html), I am unsure what the action should be for the form so please help me with it
<form action="{% url 'lazer.views.about_experiment' exp.link_name %}" method="POST">
{% csrf_token %}
<label>Researcher Name(s):<input type="text" name="researcher">
<lable>Study Summary<textarea rows="10" cols="50" placeholder="here you go" maxlength="500" class="form-control" name="study"></textarea>
<br>
<input type = "submit" value="Submit" class="btn btn-primary" />
</form>
destination page (about_experiment.html)
<h3>Holding page for {{ exp.name }}.</h3>
<h2> {{ form }} </h2>
views.py
from .forms import AboutHelp
from django.shortcuts import render
from django.http import HttpResponseRedirect
def about_experiment(request):
if request.method == 'POST':
form = AboutHelp(request.POST)
if form.is_valid():
researcher = form.cleaned_data['researcher']
study = form.cleaned_data['study']
else:
form = AboutHelp()
return render(request, 'about_experiment.html', {'form': form})`
forms.py
from django import forms
class AboutHelp(forms.Form):
researcher = forms.CharField(max_length=100)
study = forms.CharField(max_length=500)
urls.py
url(r'^about/(?P<ex_link_name>\w+)', lazer.views.about_experiment, name='lazer.views.about_experiment'),

Submit Data from a HTML form to a Database in Django

What I'm trying to do is to allow a user to enter any text in a form and have the data stored in a database. However, it is not being saved when I test it. I'm sure it's probably something stupid, but any help will be appreciated. I'm also pretty new to using Django.
Below is what I have currently have. Any help will be appreciated.
models.py:
from __future__ import unicode_literals
from django.db import models
class TEST(models.Model):
test_name = models.CharField(max_length=100)
forms.py:
from django import forms
class Test_Form(forms.Form):
test_name = forms.CharField(max_length=100)
views.py:
from django.shortcuts import render
from Test.forms import Test_Form
from Test.models import Test
from django.http import HttpResponseRedirect
def index(request):
return render(request, 'Test/Test.html')
def Test_View(request):
if request.method == 'POST':
form = Test_Form(request.POST)
if form.is_valid():
test_name = request.POST.get('test_name', '')
return HttpResponseRedirect(reverse('Test:IOC'))
else:
form = Test_Form()
return render(request, 'Test/Test.html', {'form': form})
Snippet from test.html
<form action="/Test/" method="POST" id="Test" class="form-horizontal form-groups-bordered" role="form">
{% csrf_token %}
<div class="form-group">
<div class="row">
<label class="col-lg-2 control-label" for="test_title">Full Name of Test</label>
<div class="col-lg-8">
<input id="ioc_name" class="form-control" name="test_name" type="CharField" data-validate="required" placeholder="ex: This is a test">
</div>
<div class="col-lg-1 col-lg-offset-9">
<a class="btn btn-success btn-icon">
Submit
<input type="submit" />
<i class="entypo-check"></i>
</a>
</div>
</form>
The model instance isn't save automatically with magic. You need to instantiate it, assign the data, and call the save method, like this:
test = TEST(test_name=form.cleaned_data["test_name"])
test.save()
Or in one step: TEST.create(test_name=form.cleaned_data["test_name"])
Or even shorter (if I remember well): TEST.create(**form.cleaned_data)
You should check the docs from creating forms from models, it'll get your work easier (this is for Django 1.1.0) (https://docs.djangoproject.com/en/1.10/topics/forms/modelforms/)
Also, your input is wrong:
You have to set type to a valid value (text in this case). Anyway, as t doesn't recognizes CharField as a valid type, it sets its value to text, which is the default, so you don't have problems here. Valid types
I don't know if data-validate is part of your own code, but if not and you wanna the field be required before hitting submit, you should use required, which is an HTML attr.

how to upload multiple images to a blog post in django

I am trying to allow each user to upload multiple pictures to a single blog post. I have been trying to work out the best way to do this for a few days now. What is the best practice to do this?
From what I have read, I should make a seperate image model from the blog post model and use a foreign key. Is that right?
Then there is the matter of how to allow them to upload multiple pictures at the same time. Am I right in assuming I should use something like drop zone?
Any advice on best practices for storing the photos is also welcome. I have looked at Amazon s3 and cloudinary. I want to create something which is scalable.
Any help would be much appreciated!
You'll just need two models. One for the Post and the other would be for the Images. Your image model would have a foreignkey to the Post model:
from django.db import models
from django.contrib.auth.models import User
from django.template.defaultfilters import slugify
class Post(models.Model):
user = models.ForeignKey(User)
title = models.CharField(max_length=128)
body = models.CharField(max_length=400)
def get_image_filename(instance, filename):
title = instance.post.title
slug = slugify(title)
return "post_images/%s-%s" % (slug, filename)
class Images(models.Model):
post = models.ForeignKey(Post, default=None)
image = models.ImageField(upload_to=get_image_filename,
verbose_name='Image')
You need to create a form for each model, but they will be related to each other, as in when the user is filling out the form post he has to complete the image form too for the post to successfully be posted, and we shall do that in the views, but for now your form can look something like this
from django import forms
from .models import Post, Images
class PostForm(forms.ModelForm):
title = forms.CharField(max_length=128)
body = forms.CharField(max_length=245, label="Item Description.")
class Meta:
model = Post
fields = ('title', 'body', )
class ImageForm(forms.ModelForm):
image = forms.ImageField(label='Image')
class Meta:
model = Images
fields = ('image', )
Now this is the most important part of everything, the views, because this is where uploading multiple images to a single magic happens. For us to be able to upload multiple images at once, we need multiple image fields right? That's where you fall in love with Django formsets. We will need django formsets to make this happen, you can read about formsets in the Django documentation, which I have linked :) But here is how your view should look like:
*Very important the imports
from django.shortcuts import render
from django.forms import modelformset_factory
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.http import HttpResponseRedirect
from .forms import ImageForm, PostForm
from .models import Images
#login_required
def post(request):
ImageFormSet = modelformset_factory(Images,
form=ImageForm, extra=3)
#'extra' means the number of photos that you can upload ^
if request.method == 'POST':
postForm = PostForm(request.POST)
formset = ImageFormSet(request.POST, request.FILES,
queryset=Images.objects.none())
if postForm.is_valid() and formset.is_valid():
post_form = postForm.save(commit=False)
post_form.user = request.user
post_form.save()
for form in formset.cleaned_data:
#this helps to not crash if the user
#do not upload all the photos
if form:
image = form['image']
photo = Images(post=post_form, image=image)
photo.save()
# use django messages framework
messages.success(request,
"Yeeew, check it out on the home page!")
return HttpResponseRedirect("/")
else:
print(postForm.errors, formset.errors)
else:
postForm = PostForm()
formset = ImageFormSet(queryset=Images.objects.none())
return render(request, 'index.html',
{'postForm': postForm, 'formset': formset})
In the view, we are getting both of our forms, and it will check both forms whether they are valid or not. In that way, user has to fill the form AND upload all the images which, in this case, are 3 extra=3. Only then will the post successfully get created.
Your template should look like this then:
<form id="post_form" method="post" action="" enctype="multipart/form-data">
{% csrf_token %}
{% for hidden in postForm.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in postForm %}
{{ field }} <br />
{% endfor %}
{{ formset.management_form }}
{% for form in formset %}
{{ form }}
{% endfor %}
<input type="submit" name="submit" value="Submit" />
</form>
Step by step solution => Even, I was stuck too. So this is how I successfully do.
Finally, implementing below code, I achieved this
1 Note model with many Images
Multiple Uploads(at the same time, with same Choose File button, & all save together as like in Gmail file upload)
Here are my Note and Image Model- (or see full code)
class Note(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE)
title = models.CharField(max_length=30)
text = models.TextField(null=True,blank=True)
created_date = models.DateTimeField(auto_now_add=True)
last_modified = models.DateTimeField(auto_now=True)
class Images(models.Model):
note = models.ForeignKey(Note,on_delete=models.CASCADE)
image = models.ImageField(upload_to=user_directory_path,null=True,blank=True)
Here is my form (Link of doc. on multiple upload)- (or see full code)
class NoteForm(forms.ModelForm):
class Meta:
model = Note
fields = ['title','text'] #make sure to mention field here, if nothing is mentioned then all will be required.
class NoteFullForm(NoteForm): #extending form
images = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
class Meta(NoteForm.Meta):
fields = NoteForm.Meta.fields + ['images',]
Here is my View file- (or see full code)
def addNoteView(request):
if request.method == "POST":
#images will be in request.FILES
form = NoteFullForm(request.POST or None, request.FILES or None)
files = request.FILES.getlist('images')
if form.is_valid():
user = request.user
title = form.cleaned_data['title']
text = form.cleaned_data['text']
note_obj = Note.objects.create(user=user,title=title,text=text) #create will create as well as save too in db.
for f in files:
Images.objects.create(note=note_obj,image=f)
else:
print("Form invalid")
And, finally my Html file (be sure to bind files as said in docs)- (or see full code)
<form action="{% url 'note:add_note' %}" method="post" class="note-form" enctype="multipart/form-data">{% csrf_token %}
<div class="form-group">
<label for="note-title">Title</label>
<input type="text" name="title" class="form-control" id="note-title" placeholder="Enter Title" required>
</div>
<div class="form-group">
<label for="note-description">Description</label>
<textarea type="text" name="text" class="form-control" id="note-description" placeholder="Description here"></textarea>
</div>
<div class="form-group">
<label for="note-image">Images</label>
<input type="file" name="images" class="form-control-file" id="note-image" multiple>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
The answer is very simple. So much of code is not required.
HTML File
<input type="file" name = "files" multiple />
VIEWS.PY
files = request.FILES.getlist('files')
for f in files:
a = Image(image=f)
a.save()
I had a similar problem. In my model, an article must have a thumbnail(image), then I set five more fields for optional images. The problem came in when after applying the safe filter, the image source would not render because it was not HTML anymore,
<img src="{{article.image1.url}}" class="some class">
would not work. A temporary solution I used was to name the images according to the title of the article. If I am writing on "django filters", I would name my additional images djangofiltersimage1.png or djangofiltersimage2.png, this helps since in my model each article has a unique title. I then changed the image source to:
<img src="/media/djangofiltersimage1.png" class="some class">
The only issue is the strict naming of images. You can upload more images by creating a model for Blog Images. I am still looking for another solution in the meantime.
You can check out my blog here
getlist name and html input name fiels should be same
for models.py
class studentImage(models.Model):
image = models.ImageField(upload_to='media/')
def __str__(self):
return self.image
for views.py
def studentImageView(request):
if request.method == "POST":
images = request.FILES.getlist('images')
for image in images:
photo = studentImage.objects.create(image=image,)
photo.save()
return render(request, 'image.html')
for template
<form method="post" enctype="multipart/form-data" >
{% csrf_token %}
<input required name="images" type="file" multiple >
<button class="btn btn-primary" type="submit">Upload</button>
</form>

Simple Django Image Upload - Image file not saving

Right I'm learning how to do a simple image upload form to upload an image to MEDIA_ROOT. The form renders fine, I get no errors, but the file is not showing up in the MEDIA_ROOT directory. If followed the documentation example and can't get it to work and I know it is because I have not understood django file upload handeling properly. So here is my code:
forms.py
from django import forms
class UploadImageForm(forms.Form):
image = forms.ImageField()
views.py
def merchant_image_upload(request):
if request.method == 'POST':
form = UploadImageForm(request.POST, request.FILES)
if form.is_valid():
FileUploadHandler(request.FILES['image'])
return HttpResponseRedirect('/dashboard/gallery')
else:
form = UploadImageForm()
return render_to_response('gallery.html', RequestContext(request, {'form': form}))
template file
{% extends 'base.html' %}
{% block main %}
<form action="{% url scvd.views.merchant_image_upload %}" method="post">{% csrf_token %}
{{ form.image }}
<input type="submit" value="Upload" />
</form>
{% endblock %}
Hopefully that's sufficient info to get some help. Please let me know what else I can provide. Thank you, I really appreciate the help.
You don't need to attach it to a model as Matt S states, request.FILES has all the data for the image if your form is set up correctly.
You need to make sure use enctype="multipart/form-data" in your element, as the docs state here: https://docs.djangoproject.com/en/dev/ref/forms/api/#binding-uploaded-files-to-a-form
Aside from that, read the docs about file uploads: https://docs.djangoproject.com/en/dev/topics/http/file-uploads/
All you need is well documented there. Hope this helps!
EDIT OP requested more information on File Uploads
From the docs:
Most of the time, you'll simply pass the file data from request into
the form as described in Binding uploaded files to a form. This would
look something like:
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
# Imaginary function to handle an uploaded file.
from somewhere import handle_uploaded_file
def upload_file(request):
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
handle_uploaded_file(request.FILES['file'])
return HttpResponseRedirect('/success/url/')
else:
form = UploadFileForm()
return render_to_response('upload.html', {'form': form})
And they have an example of how you could write the handle_uploaded_file function:
def handle_uploaded_file(f):
destination = open('some/file/name.txt', 'wb+')
for chunk in f.chunks():
destination.write(chunk)
destination.close()
In order to have your files uploaded and shows in request.FILES, your form MUST contain enctype="multipart/form-data" as shown below:
<form action="{% url scvd.views.merchant_image_upload %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.image }}
<input type="submit" value="Upload" />
</form>
You need to attach it to a model (as an ImageField) as it's not being saved anywhere presently. It may be handled without any issues right now but it gets discarded after the view returns.
Never mind, I didn't realize models were unnecessary.