Django Forms
\n\nHTML forms are the classic way for website interactivity. This chapter will introduce how to use Django to process user-submitted form data.
\n\n\n\n
HTTP Requests
\n\nThe HTTP protocol works in a "request-response" manner. When a client sends a request, it can attach data to the request. The server parses the request to obtain the data sent by the client and provides specific services based on the URL.
\n\nGET Method
\n\nWe will create a search.py file in our previous project to receive user requests:
\n\n/HelloWorld/HelloWorld/search.py file code:
\n\nfrom django.http import HttpResponse\nfrom django.shortcuts import render\n\ndef search_form(request):\n return render(request, 'search_form.html')\n\ndef search(request):\n request.encoding='utf-8'\n if 'q' in request.GET and request.GET['q']:\n message = 'The content you searched for is: ' + request.GET['q']\n else:\n message = 'You submitted an empty form'\n return HttpResponse(message)\n\nAdd search_form.html form in the templates directory:
\n\n/HelloWorld/templates/search_form.html file code:
\n\n<!DOCTYPE html>\n<html>\n<head>\n <meta charset="utf-8">\n <title>()</title>\n</head>\n<body>\n <form action="/search/" method="get">\n <input type="text" name="q">\n <input type="submit" value="Search">\n </form>\n</body>\n</html>\n\nModify urls.py rules as follows:
\n\n/HelloWorld/HelloWorld/urls.py file code:
\n\nfrom django.conf.urls import url\nfrom . import views,testdb,search\n\nurlpatterns = [\n url(r'^hello/$', views.tutorial),\n url(r'^testdb/$', testdb.testdb),\n url(r'^search-form/$', search.search_form),\n url(r'^search/$', search.search),\n]\n\nVisit http://127.0.0.1:8000/search-form/ and search, the results are shown below:
\n\nPOST Method
\n\nAbove we used the GET method, with view display and request handling split into two functions.
\n\nThe POST method is more commonly used when submitting data. Below we use this method, with one URL and handler function, simultaneously displaying the view and processing the request.
\n\nWe create post.html in templates:
\n\n/HelloWorld/templates/post.html file code:
\n\n<!DOCTYPE html>\n<html>\n<head>\n <meta charset="utf-8">\n <title>()</title>\n</head>\n<body>\n <form action="/search-post/" method="post">\n {% csrf_token %}\n <input type="text" name="q">\n <input type="submit" value="Search">\n </form>\n <p>{{ rlt }}</p>\n</body>\n</html>\n\nAt the end of the template, we add an rlt marker to reserve space for the form processing result.
\n\nThere is also a {% csrf_token %} tag after the form. csrf stands for Cross Site Request Forgery. This is a feature provided by Django to prevent spoofed submission requests. Forms submitted via POST method must have this tag.
\n\nCreate search2.py file in the HelloWorld directory and use the search_post function to handle POST requests:
\n\n/HelloWorld/HelloWorld/search2.py file code:
\n\nfrom django.shortcuts import render\nfrom django.views.decorators import csrf\n\ndef search_post(request):\n ctx ={}\n if request.POST:\n ctx['rlt'] = request.POST['q']\n return render(request, "post.html", ctx)\n\nModify urls.py rules as follows:
\n\n/HelloWorld/HelloWorld/urls.py file code:
\n\nfrom django.conf.urls import url\nfrom . import views,testdb,search,search2\n\nurlpatterns = [\n url(r'^hello/$', views.hello),\n url(r'^testdb/$', testdb.testdb),\n url(r'^search-form/$', search.search_form),\n url(r'^search/$', search.search),\n url(r'^search-post/$', search2.search_post),\n]\n\nVisit http://127.0.0.1:8000/search-post/ to see results as shown below:
\n\nAfter completing the above example, our directory structure is:
\n\nHelloWorld\n|-- HelloWorld\n| |-- __init__.py\n| |-- __init__.pyc\n| |-- search.py\n| |-- search.pyc\n| |-- search2.py\n| |-- search2.pyc\n| |-- settings.py\n| |-- settings.pyc\n| |-- testdb.py\n| |-- testdb.pyc\n| |-- urls.py\n| |-- urls.pyc\n| |-- views.py\n| |-- views.pyc\n| |-- wsgi.py\n| `-- wsgi.pyc\n|-- TestModel\n| |-- __init__.py\n| |-- __init__.pyc\n| |-- admin.py\n| |-- admin.pyc\n| |-- apps.py\n| |-- migrations\n| | |-- 0001_initial.py\n| | |-- 0001_initial.pyc\n| | |-- __init__.py\n| | `-- __init__.pyc\n| |-- models.py\n| |-- models.pyc\n| |-- tests.py\n| `-- views.py\n|-- db.sqlite3\n|-- manage.py\n`-- templates\n |-- base.html\n |-- hello.html\n |-- post.html\n `-- search_form.html\n\n\n\n
Request Object
\n\nThe first parameter of each view function is an HttpRequest object, like this tutorial() function:
\n\nfrom django.http import HttpResponse\n\ndef tutorial(request):\n return HttpResponse("Hello world")\n\nThe HttpRequest object contains some information about the current request URL:
\n\n| Attribute | Description |
|---|---|
| path | The full path of the requested page, not including the domainβfor example, "/hello/". |
| method | A string representing the HTTP method used in the request. In all uppercase. For example: if request.method=='GET': do_something() elif request.method=='POST': do_something_else() |
| GET | A dictionary-like object containing all HTTP GET parameters. See QueryDict documentation. |
| POST | A dictionary-like object containing all HTTP POST parameters. See QueryDict documentation. It is also possible for the server to receive an empty POST request. That is, a form submits a request via HTTP POST method, but the form may contain no data. Therefore, you cannot use the statement if request.POST to determine whether HTTP POST method is used; you should use if request.method == "POST" (see the method attribute in this table). Note: POST does not include file-upload information. See FILES attribute. |
| REQUEST | For convenience, this attribute is a combination of POST and GET attributes, but with special characteristics: it first searches POST attributes, then GET attributes. Modeled after PHP's $_REQUEST. For example, if GET = {"name": "john"} and POST = {"age": '34'}, then REQUEST is "john", and REQUEST is "34". It is strongly recommended to use GET and POST, as these two attributes are more explicit and produce more understandable code. |
| COOKIES | A standard Python dictionary object containing all cookies. Keys and values are strings. |
| FILES | A dictionary-like object containing all uploaded files. Each Key in FILES is the value of the name attribute in the <input type="file" name="" /> tag. Each value in FILES is also a standard Python dictionary object, containing the following three Keys: β’ filename: The uploaded file name, represented as a Python string β’ content-type: The Content type of the uploaded file β’ content: The raw content of the uploaded file Note: FILES only has data when the request method is POST and the <form> in the request page has the enctype="multipart/form-data" attribute. Otherwise, FILES is an empty dictionary. |
| META | A dictionary containing all available HTTP header information. For example: β’ CONTENT_LENGTH β’ CONTENT_TYPE β’ QUERY_STRING: Unparsed raw query string β’ REMOTE_ADDR: Client IP address β’ REMOTE_HOST: Client host name β’ SERVER_NAME: Server host name β’ SERVER_PORT: Server port In META, these headers are prefixed with HTTP_ as Key, and the content after the colon(:) as Value, for example: β’ HTTP_ACCEPT_ENCODING β’ HTTP_ACCEPT_LANGUAGE β’ HTTP_HOST: The HTTP host header information sent by the client β’ HTTP_REFERER: Referring page β’ HTTP_USER_AGENT: Client's user-agent string β’ HTTP_X_BENDER: X-Bender header information |
| user | A django.contrib.auth.models.User object representing the currently logged-in user. If the visiting user is not currently logged in, user will be initialized as an instance of django.contrib.auth.models.AnonymousUser. You can determine whether a user is logged in through the user's is_authenticated() method: if request.user.is_authenticated(): # Do something for logged-in users. else: # Do something for anonymous users. This attribute is only available when Django's AuthenticationMiddleware is activated |
| session | The only read-write attribute, representing the dictionary object of the current session. This attribute is only available when Django's session support is activated. |
| raw_post_data | Raw HTTP POST data, not parsed. Useful for advanced processing. |
The Request object also has some useful methods:
\n\n| Method | Description |
|---|---|
| __getitem__(key) | Returns the key value of GET/POST, taking POST first, then GET. Throws KeyError if the key does not exist. This allows us to access HttpRequest objects using dictionary syntax. For example, request is equivalent to first request.POST then request.GET. |
| has_key() | Checks whether request.GET or request.POST contains the Key specified by the parameter. |
| get_full_path() | Returns the request path including the query string. For example, "/music/bands/the_beatles/?print=true" |
| is_secure() | Returns True if the request is secure, that is, if it is an HTTPS request. |
QueryDict Object
\n\nIn the HttpRequest object, GET and POST attributes are instances of the django.http.QueryDict class.
\n\nQueryDict is a dictionary-like custom class used to handle cases where a single key corresponds to multiple values.
\n\nQueryDict implements all standard dictionary methods. It also includes some unique methods:
\n\n| Method | Description |
|---|---|
| __getitem__ | Slightly different from standard dictionary processing: if the Key corresponds to multiple Values, __getitem__() returns the last value. |
| __setitem__ | Sets the value list (a Python list) for the key specified by the parameter. Note: It can only be called on a mutable QueryDict object (that is, a copy of a QueryDict object produced by copy()). |
| get() | If the key corresponds to multiple values, get() returns the last value. |
| update() | The parameter can be a QueryDict or a standard dictionary. Unlike the standard dictionary's update method, this method adds dictionary items rather than replacing them: >>> q = QueryDict('a=1') >>> q = q.copy() # to make it mutable >>> q.update({'a': '2'}) >>> q.getlist('a') ['1', '2'] >>> q['a'] # returns the last ['2'] |
| items() | Slightly different from the standard dictionary's items() method; this method uses single-value logic __getitem__(): >>> q = QueryDict('a=1&a=2&a=3') >>> q.items() [('a', '3')] |
| values() | Slightly different from the standard dictionary's values() method; this method uses single-value logic __getitem__(): |
In addition, QueryDict also has some methods, as shown in the table below:
\n\n| Method | Description |
|---|---|
| copy() | Returns a copy of the object, internally implemented using Python standard library's copy.deepcopy(). This copy is mutable (changeable)βthat is, you can change the values of this copy. |
| getlist(key) | Returns all values corresponding to the parameter key, as a Python list. If the key does not exist, returns an empty list. It's guaranteed to return a list of some sort. |
| setlist(key,list_) | Sets the value of key to list_ (unlike __setitem__()). |
| appendlist(key,item) | Adds item to the internal list associated with key. |
| setlistdefault(key,list) | Slightly different from setdefault, it accepts a list rather than a single value as parameter. |
| lists() | Slightly different from items(), it returns all values of the key as a list, for example: >>> q = QueryDict('a=1&a=2&a=3') >>> q.lists() [('a', ['1', '2', '3'])] |
| urlencode() | Returns a string formatted in query string format (for example: "a=2&b=3&b=5"). |
YouTip