Django Advanced Form Processing - Partial Forms, AJAX and Files
Django Advanced Form Processing - Partial Forms, AJAX and Files
Homepage
from an end user, you must take care of giving the email field a value yourself -- note the name field
doesn't present this problem because it's configured with required=False. Therefore, in order for the
template in listing 6-32 to work, the form must be initialized with a value like the following snippet:
By initializing the form in this manner, the email form field is given this initial value as a hidden input. So
All books and
once a user submits the form, the email value is transferred back to Django as part of the form, where
articles
validation passes since the post-processing logic gets all its expected values. Of course, if a form's fields
are all optional (i.e. they're marked with required=False) this initialization process is unnecessary, since
Beginning Django
the validation won't be expecting any value anyways.
Introduction to the A second alternative to achieve partial forms is to create a sub-class from a form class and delete the
Django framework unneeded fields. This is a little more straightforward approach, but it does require creating a form sub-
class, which may be overkill for certain scenarios. Listing 6-33 shows how to sub-class a Django form
Django urls & views class and remove some of its parent's fields.
Listing 6-33. Django form sub-class with removed parent fields
Django templates from coffeehouse.about.forms import ContactForm
Django advanced Listing 6-34. JavaScript jQuery logic to submit Django form via
form processing: AJAX
Partial forms, AJAX
and files
Django formsets
Django models
Django model
queries and managers
https://www.webforefront.com/django/formadvancedprocessing.html 2/7
03-07-2023 15:46 Django advanced form processing: Partial forms, AJAX and files
# NOTE: The following is only the Django (HTML) template with AJAX logic
# See listing 6-35 for AJAX processing views.py and urls.py
<h4>Feedback</h4>
Homepage <div class="row">
<div id="feedbackmessage"</div>
</div>
All books and
<form method="POST" id="feedbackform" action="{% url 'stores:feedback' %}">
articles {% csrf_token %}
<div class="row">
Beginning Django <div class="col-md-12 pull-left">
{{ form.comment }}
</div>
Introduction to the
</div>
Django framework
{{form.name.as_hiddden}}
{{form.email.as_hidden}}
Django urls & views <input type="submit" value="Submit feedback" class="btn btn-primary">
</form>
<script>
Django templates
$(document).ready(function() {
$("#feedbackform").submit(function(event) {
Jinja templates in event.preventDefault();
Django $.ajax({ data: $(this).serialize(),
type: $(this).attr('method'),
url: $(this).attr('action'),
Django application
success: function(response) {
management
console.log(response);
if(response['success']) {
Django forms $("#feedbackmessage").html("<div class='alert alert-success'>
Succesfully sent feedback, thank you!</div>");
Welcome! $("#feedbackform").addClass("hidden");
Django form
}
structure and workflow
if(response['error']) {
It looks like you're using an ad blocker.
$("#feedbackmessage").html("<div class='alert alert-danger'>" +
Django form
We respect your privacy, however, the contentresponse['error']['comment']
you're reading +"</div>");
processing: }
wouldn't be freely available without revenue from advertisers.
Initialization, field },
access, validation and error: function (request, status, error) {
console.log(request.responseText);
error handling
}
});
Django form field });
types: Widgets, })
options and </script>
validations
The first part of listing 6-34 is a standard Django form layout. However, notice the <form> tag includes
Set up the layout the action attribute. In previous Django forms, the action attribute was not used because the serving url
for Django forms in -- GET request -- and processing url -- POST request -- was the same one. In listing 6-34, the action
templates attribute explicitly tells the browser the url where it should send the POST request -- in this case {% url
'stores:feedback' %} is a Django template tag that gets translated into a url (e.g./stores/feedback/).
Different urls are necessary in this case, because Django view methods that handle AJAX
Django custom
requests/responses are different from Django view methods that handle standard web
form fields and
requests/responses.
widgets
Now lets turn our attention to the bottom half of listing 6-34 and the JavaScript logic enclosed in
Django advanced <script> tags. In brief -- as it would go beyond the scope of our discussion to describe jQuery syntax --
form processing: the web page awaits a click on the #feedbackform form's submit button. Once this click is detected, an
Partial forms, AJAX AJAX POST request using the form's data is sent to the url defined in the form's action attribute. Upon
and files completion of the AJAX request (i.e. when the server-side sends a response back), the response -- in
JSON format -- is analyzed. If the AJAX response contains a success message, the message is output at
Django formsets the top of the form and the form is hidden to avoid multiple submissions. If the AJAX response contains
an error message, the message is output at the top of the form.
Django models
Now that you know how Django form data is submitted to the server-side via AJAX, listing 6-35
Django model illustrates the Django view method necessary to handle this AJAX request payload.
queries and managers
Listing 6-35. Django view method to process Django form via AJAX
https://www.webforefront.com/django/formadvancedprocessing.html 3/7
03-07-2023 15:46 Django advanced form processing: Partial forms, AJAX and files
# urls.py (Main)
urlpatterns = [
url(r'^stores/',include('coffeehouse.stores.urls',namespace="stores"))
]
Homepage
# urls.py (App stores)
urlpatterns = [
All books and
url(r'^$',views.index,name="index"),
articles url(r'^feedback/$',views.feedback,name="feedback"),
]
Beginning Django
# views.py (App stores)
from django.http import HttpResponse, JsonResponse
Introduction to the
from coffeehouse.about.forms import ContactForm
Django framework
def feedback(request):
Django urls & views if request.POST:
form = ContactForm(request.POST)
if form.is_valid():
return JsonResponse({'success':True})
Django templates
else:
return JsonResponse({'error':form.errors})
Jinja templates in return HttpResponse("Hello from feedback!")
Django
The first important point about the view method in listing 6-35 is that it only handles POST requests.
Django application Notice that in case the if request.POST: statement isn't true, the view method always responds with the
management Hello from feedback! string.
Next, inside the request.POST segment, the process starts out pretty similar to a standard Django form
Django forms processing sequence (i.e. a bound form instance is created and a call is made to the form's is_valid()
method to validate the user provided data). However, notice the responses for both valid and invalid
Welcome!
Django form form data use JsonResponse(). Since the AJAX form submission operates in a JavaScript context, the
structure and workflow JSON format response is a common format to use to send a response back to the browser.
It looks like you're using an ad blocker.
Django form If you turn your attention back to listing 6-34, you can see the JavaScript logic is designed to handle and
We respect your privacy, however, the content you're reading
processing: output either JSON response (success or error) returned by the view method in listing 6-35.
wouldn't be freely available without revenue from advertisers.
Initialization, field
access, validation and Files in forms
error handling
Django offers a couple of form fields to capture files through forms -- forms.ImageField() and
forms.ImageField() described in table 6-2. However, although these form fields generate the necessary
Django form field
HTML and validation logic to enforce files are submitted via forms, there are a couple of subtleties
types: Widgets,
related to processing files in forms.
options and
validations The first issue is the HTML <form> tag for forms that transfer files must explicitly set the encoding type to
enctype="multipart/form-data", in addition to using method=POST. The second issue is the contents of
Set up the layout files are placed in the Django request object under the special FILES dictionary key. Listing 6-36
for Django forms in illustrates a form with file fields, its corresponding view method and its template layout.
templates
Listing 6-36. Django form with file fields, corresponding view
Django custom method and template layout.
form fields and
widgets
Django advanced
form processing:
Partial forms, AJAX
and files
Django formsets
Django models
Django model
queries and managers
https://www.webforefront.com/django/formadvancedprocessing.html 4/7
03-07-2023 15:46 Django advanced form processing: Partial forms, AJAX and files
# forms.py
from django import forms
class SharingForm(forms.Form):
Homepage # NOTE: forms.PhotoField requires Python PIL & other operating system libraries,
# so generic FileField is used instead
video = forms.FileField()
All books and
photo = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
articles
Django application
management
# social/index.html
<form method="post" enctype="multipart/form-data">
Django forms {% csrf_token %}
<ul>
Welcome!
{{form.as_ul}}
Django form
</ul>
structure and workflow
<input type="submit" value="Submit photo" class="btn btn-primary">
It looks like you're using an ad blocker.
</form>
Django form
We respect your privacy, however, the content you're reading
processing: Notice how the HTML <form> tag declares the required attributes and in addition notice how the
wouldn't be freely available without revenue from advertisers.
Initialization, field request.FILES reference is used to create a bound form -- along with the standard request.POST. The
access, validation and remaining form structures in listing 6-36 are identical to regular non-file forms (e.g. unbound form
error handling creation, call to is_valid()).
But similar to regular Django form processing, once a form is valid -- if is_valid() returns True -- you'll
Django form field
want do something with the contents of the form data, therefore in this case, you'll need to access
types: Widgets,
request.FILES to do something with the files uploaded by a user.
options and
validations But before describing how to process the contents of files in request.FILES it's important you
understand the possible contents of the request.FILES dictionary:
Set up the layout
for Django forms in Option 1) request.FILES = {'photo': [<InMemoryUploadedFile>,<TemporaryUploadedFile>],
templates 'video': [<InMemoryUploadedFile>]}
Option 2) request.FILES = {'photo': [<TemporaryUploadedFile>],
'video': [<InMemoryUploadedFile>]}
Django custom
form fields and The request.FILES dictionary contains keys corresponding to file field names. In this case, you can see
widgets the photo and video keys correspond to the form fields names declared in listing 6-36 that represent files.
Next, notice the value for each key is a list, irrespective if the file form field can accept multiple files --
Django advanced like photo due to the overridden widget with the 'multiple': True attribute -- or a single file -- in the
form processing: case of video.
Partial forms, AJAX
and files Now lets analyze the contents of the lists assigned to each file form field key. Each of the list elements
represents an uploaded file. But notice how the files are represented by either the InMemoryUploadedFile
Django formsets or TemporaryUploadedFile class -- both of which are sub-classes of the
django.core.files.uploadedfile.UploadedFile class. The reason uploaded files are represented by either
an InMemoryUploadedFile or TemporaryUploadedFile instance class, is dependent on the size of an
Django models
uploaded file.
Django model As it turns out, before you even decide how to handle uploaded files, Django must decide what to do
queries and managers and where to place uploaded files. To do this, Django relies on upload handlers. By default and unless
explicitly overridden in the FILE_UPLOAD_HANDLERS variable in settings.py,Django uses the following two
file upload handlers:
https://www.webforefront.com/django/formadvancedprocessing.html 5/7
03-07-2023 15:46 Django advanced form processing: Partial forms, AJAX and files
FILE_UPLOAD_HANDLERS= [
'django.core.files.uploadhandler.MemoryFileUploadHandler',
'django.core.files.uploadhandler.TemporaryFileUploadHandler',
]
Homepage
By default, if a file is less than 2.5 MB, Django uses MemoryFileUploadHandler to place the contents of an
uploaded file into memory; if a file is larger than 2.5 MB, Django uses TemporaryFileUploadHandler to
All books and
place the contents of an uploaded file in a temporary file (e.g. /tmp/Af534.upload).
articles
You can define FILE_UPLOAD_HANDLERS in settings.py to only include the file upload handler you desire
Beginning Django (e.g. if you wish to save memory resources remove MemoryFileUploadHandler). However, note a file
upload handler must always be active in order for file uploads to work. If you don't like the behavior of
Introduction to the Django's built-in file upload handlers, then you'll need to write your own file upload handler[5].
Django framework
In addition to defining FILE_UPLOAD_HANDLERS in settings.py, there are two other parameters you can
Django urls & views declare in settings.py to influence the behavior of file upload handlers. The
FILE_UPLOAD_MAX_MEMORY_SIZE variable sets the threshold size at which files are held in memory vs.
handled as temporary files, defaulting to 2621440 bytes (or 2.5 MB). And the FILE_UPLOAD_TEMP_DIR
variable sets the directory to which temporary uploaded files must be saved, defaulting to None, meaning
Django templates
an operating system's temporary file directory is used (e.g. on Linux OS /tmp/).
Jinja templates in Now that you know where and how Django stores uploaded files even before you decide how to handle
Django them, let's take a look at how to process the contents of request.FILES. Listing 6-37 shows the
continuation of listing 6-36 with the relevant snippets necessary to process uploaded files.
Django application
management Listing 6-37. Django form file processing with save procedure to
MEDIA_ROOT.
Django forms
# views.py
Welcome!
from django.conf import settings
Django form
structure and workflow def save_uploaded_file_to_media_root(f):
It looks
with like you're using
open('%s%s' an ad blocker.
% (settings.MEDIA_ROOT,f.name), 'wb+') as destination:
for chunk in f.chunks():
Django form
We respect your privacy, however, the content you're reading
destination.write(chunk)
processing:
wouldn't be freely available without revenue from advertisers.
Initialization, field def index(request):
access, validation and if request.method == 'POST':
error handling # POST, generate form with data from the request
form = SharingForm(request.POST,request.FILES)
# check if it's valid:
Django form field
if form.is_valid():
types: Widgets,
for field in request.FILES.keys():
options and for formfile in request.FILES.getlist(field):
validations save_uploaded_file_to_media_root(formfile)
return HttpResponseRedirect('/about/contact/thankyou')
Set up the layout else:
for Django forms in # GET, generate blank form
form = SharingForm()
templates
return render(request,'social/index.html',{'form':form})
Django custom After the form is_valid() method, you know each of the keys in the request.FILES dictionary are file
form fields and form fields, so a loop is created to get each file field (i.e. video, photo). Next, using the getlist() method
widgets of the request.FILES dictionary, you obtain the list of file instances (i.e.
InMemoryUploadedFile,TemporaryUploadedFile) for each file field and loop over each element to get file
Django advanced instances. Finally, you execute the save_uploaded_file_to_media_root() method on each file instance.
form processing:
Partial forms, AJAX Each file instance -- represented as the formfile reference in listing 6-37 -- is either a
and files InMemoryUploadedFile or TemporaryUploadedFile instance type. But as I mentioned earlier, these classes
are derived from the parent class django.core.files.uploadedfile.UploadedFile, which means file
Django formsets instances are also UploadedFile instances.
Django model <file_instance>.name.- Outputs the name of the file, as-was on a user's computer.
queries and managers <file_instance>.size.- Outputs the size of the file, in bytes.
<file_instance>.content_type.- Outputs the HTTP Content-Type header assigned to the file (e.g.
text/html, application/zip).
https://www.webforefront.com/django/formadvancedprocessing.html 6/7
03-07-2023 15:46 Django advanced form processing: Partial forms, AJAX and files
With the use of these UploadedFile fields and methods, you can see toward the top of listing 6-37 the
save_uploaded_file_to_media_root() method logic includes: saving the uploaded file with its original
Homepage name -- using Python's standard with...open syntax -- and then using the chunks() method to efficiently
write all the pieces of the uploaded file to the file system.
All books and
articles
Note The uploaded files in listing 6-37 are saved under the settings.MEDIA_ROOT folder. Although
you can save files to any location you want, the standard practice for user uploaded files in Django
Beginning Django
is to save them under the MEDIA_ROOT folder defined in settings.py.
Introduction to the
Django framework
5. https://docs.djangoproject.com/en/1.11/ref/files/uploads/#custom-upload-handlers ↑
Django templates
Jinja templates in
Django
Django application
management
Django forms
Welcome!
Django form
structure and workflow
It looks like you're using an ad blocker.
Django form
We respect your privacy, however, the content you're reading
processing:
wouldn't be freely available without revenue from advertisers.
Initialization, field
access, validation and
error handling
Django custom
form fields and
widgets
Django advanced
form processing:
Partial forms, AJAX
and files
Django formsets
Django models
Django model
queries and managers
https://www.webforefront.com/django/formadvancedprocessing.html 7/7