{"id":10205,"date":"2016-01-19T16:11:38","date_gmt":"2016-01-19T14:11:38","guid":{"rendered":"http:\/\/www.webcodegeeks.com\/?p=10205"},"modified":"2018-01-09T09:49:21","modified_gmt":"2018-01-09T07:49:21","slug":"python-django-tutorial","status":"publish","type":"post","link":"https:\/\/www.webcodegeeks.com\/python\/python-django-tutorial\/","title":{"rendered":"Python Django Tutorial"},"content":{"rendered":"<p>Django is an open source web framework which solves most common problems of a web application development. It has some very useful features like an auto generated admin page and an ORM.<\/p>\n<p>It&#8217;s a high-level framework, so we just need to focus on the actual core logic of our business and let Django take care of mappings, filters and such. It works by defining some standards that, if you follow them, will make the application&#8217;s development so much easier and faster.<\/p>\n<p>By using Python 3.4.3 and Django 1.9.1, we&#8217;ll build a web application which, through an admin site only available to us, will let us upload riddles. Then we&#8217;ll make a public user interface which will let the users answer the riddles we upload.<br \/>\n&nbsp;<br \/>\n[ulp id=&#8217;R7QVpFMZmjosABLC&#8217;]<\/p>\n<h2>1. Creating the project<\/h2>\n<p>If you&#8217;ve installed django correctly, when you run <code>django-admin --version<\/code>, you&#8217;ll see the version in the output of that command. Now if we run <code>django-admin startproject django_example<\/code>, we&#8217;ll now have the skeleton of our project. Let&#8217;s cd to our project&#8217;s directory and see:<\/p>\n<ul>\n<li><strong>django_example<\/strong> is the actual python package for your project.<\/li>\n<li><strong>django_example\/__init__.py<\/strong> is an empty file that tells python that this directory should be considered a package.<\/li>\n<li><strong>django_example\/settings.py<\/strong> holds the configuration for this Django project.<\/li>\n<li><strong>django_example\/urls.py<\/strong> holds the URL declarations.<\/li>\n<li><strong>django_example\/wsgi.py<\/strong> is an entry-point for WSGI-compatible web servers to serve your project.<\/li>\n<li><strong>manage.py<\/strong> is a command-line utility that lets you interact with this Django project in various ways. We&#8217;ll see some of them below.<\/li>\n<\/ul>\n<p>Now, let&#8217;s see how to run this application. Run <code>python3 manage.py runserver<\/code> and you&#8217;ll see some output on the console to finally see <code>Starting development server at http:\/\/127.0.0.1:8000\/<\/code>. Now if we hit that location we&#8217;ll see a Django welcome screen telling us that everything worked fine.<\/p>\n<p>You will probably see something like <em>&#8220;You have unapplied migrations; your app may not work properly until they are applied.&#8221;<\/em>. We&#8217;ll get back to that later, don&#8217;t worry about it right now.<\/p>\n<h2>2. Creating our application<\/h2>\n<p>Now we have our project up and running and we can start writing our application now. Something to notice here is the difference about the terms project and application. An application is a python program that does something, and a project is a group of applications. The same application can be contained in more than one project. A project will almost always contain many applications.<\/p>\n<p>Each application in Django consists of a package that follows some Django standards. One of the many tools that come with this framework is an utility that automatically generates the basic directory structure of an application, so let&#8217;s run <code>python3 manage.py startapp riddles<\/code>, and now there will be a directory called <em>riddles<\/em> wich will hold our application&#8217;s source code.<\/p>\n<p>Let&#8217;s write a simple view to see how everything works. Django convention tells us to write them in a file called <code>views.py<\/code> within our application&#8217;s module.<\/p>\n<p><span style=\"text-decoration: underline\"><em>riddles\/views.py<\/em><\/span><\/p>\n<pre class=\"brush:python\">\r\nfrom django.http import HttpResponse\r\n\r\n\r\ndef index(request):\r\n    return HttpResponse(\"Hello, World!\")\r\n<\/pre>\n<p>Now, to map this view to a URL we&#8217;ll create a <code>urls.py<\/code> in our application&#8217;s module.<\/p>\n<p><span style=\"text-decoration: underline\"><em>riddles\/urls.py<\/em><\/span><\/p>\n<pre class=\"brush:python\">\r\nfrom django.conf.urls import url\r\n\r\nfrom . import views\r\n\r\napp_name = 'riddles'\r\n\r\nurlpatterns = [\r\n    url(r'^$', views.index, name='index'),\r\n]\r\n<\/pre>\n<p>And in our project&#8217;s urls we include this urls.<\/p>\n<p><span style=\"text-decoration: underline\"><em>django_example\/urls.py<\/em><\/span><\/p>\n<pre class=\"brush:python\">\r\nfrom django.conf.urls import include, url\r\nfrom django.contrib import admin\r\n\r\nurlpatterns = [\r\n    url(r'^riddles\/', include('riddles.urls')),\r\n    url(r'^admin\/', admin.site.urls),\r\n]\r\n<\/pre>\n<p>Now we run our server and hit <em>http:\/\/localhost:8000\/riddles\/<\/em> to see our message <em>&#8220;Hello, World!&#8221;<\/em>. If everything worked fine we&#8217;ll start with our database.<\/p>\n<h2>3. Database Setup<\/h2>\n<p>Now, when we see <code>django_example\/settings.py<\/code>, it&#8217;s a normal module with some variables representing Django settings. There is a variable named <code>DATABASES<\/code> which by default uses SQLite which is included within Python, so you won&#8217;t need to install anything. For this example, we&#8217;ll stick with the default here.<\/p>\n<p>Also, see the variable <code>INSTALLED_APPS<\/code>, it holds the names of all Django applications which are activated in the project. By default it contains:<\/p>\n<ul>\n<li><strong>&#8216;django.contrib.admin&#8217;<\/strong> is the admin site, we&#8217;ll be seeing it in no time.<\/li>\n<li><strong>&#8216;django.contrib.auth&#8217;<\/strong> as an authentication system.<\/li>\n<li><strong>&#8216;django.contrib.contenttypes&#8217;<\/strong> a framework for content types.<\/li>\n<li><strong>&#8216;django.contrib.sessions&#8217;<\/strong> a session framework.<\/li>\n<li><strong>&#8216;django.contrib.messages&#8217;<\/strong> a messaging framework.<\/li>\n<li><strong>&#8216;django.contrib.staticfiles&#8217;<\/strong> a static content framework.<\/li>\n<\/ul>\n<p>This applications are useful in most cases, but some of them uses databases (like <em>django.contrib.auth<\/em>), and these are not created yet. That&#8217;s why you see that migrations message on the output of the runserver command. To create all tables we just run the command <code>python3 manage.py migrate<\/code>. You should see something like:<\/p>\n<pre class=\"brush:bash\">\r\nOperations to perform:\r\n  Apply all migrations: admin, sessions, auth, contenttypes\r\nRunning migrations:\r\n  Rendering model states... DONE\r\n  Applying contenttypes.0001_initial... OK\r\n  Applying auth.0001_initial... OK\r\n  Applying admin.0001_initial... OK\r\n  Applying admin.0002_logentry_remove_auto_add... OK\r\n  Applying contenttypes.0002_remove_content_type_name... OK\r\n  Applying auth.0002_alter_permission_name_max_length... OK\r\n  Applying auth.0003_alter_user_email_max_length... OK\r\n  Applying auth.0004_alter_user_username_opts... OK\r\n  Applying auth.0005_alter_user_last_login_null... OK\r\n  Applying auth.0006_require_contenttypes_0002... OK\r\n  Applying auth.0007_alter_validators_add_error_messages... OK\r\n  Applying sessions.0001_initial... OK\r\n<\/pre>\n<p>Now let&#8217;s create our model, which is our database layout with some additional metadata. For now we&#8217;ll just create <code>Riddle<\/code> and <code>Option<\/code>. A Riddle contains the actual riddle, and an Option is one of the possible answers of a riddle, with a flag that will tell us if it&#8217;s the correct one.<\/p>\n<p><span style=\"text-decoration: underline\"><em>riddles\/models.py<\/em><\/span><\/p>\n<pre class=\"brush:python\">\r\nfrom django.db import models\r\n\r\n\r\nclass Riddle(models.Model):\r\n    riddle_text = models.CharField(max_length=255)\r\n    pub_date = models.DateTimeField('date published')\r\n\r\n\r\nclass Option(models.Model):\r\n    riddle = models.ForeignKey(Riddle, on_delete=models.CASCADE)\r\n    text = models.CharField(max_length=255)\r\n    correct = models.BooleanField(default=False)\r\n\r\n<\/pre>\n<p>This model gives Django all the information needed to create the database schema and the database-access API for accessing these objects, but we need to tell our project that the riddles app is installed, we&#8217;ll just add an element to the <code>INSTALLED_APPS<\/code> in <code>django_example\/settings.py<\/code>:<\/p>\n<p><span style=\"text-decoration: underline\"><em>django_example\/settings.py<\/em><\/span><\/p>\n<pre class=\"brush:python\">\r\nINSTALLED_APPS = [\r\n    'riddles.apps.RiddlesConfig',\r\n    'django.contrib.admin',\r\n    'django.contrib.auth',\r\n    'django.contrib.contenttypes',\r\n    'django.contrib.sessions',\r\n    'django.contrib.messages',\r\n    'django.contrib.staticfiles',\r\n]\r\n<\/pre>\n<p>Now we make the migration for this application running <code>python3 manage.py makemigrations riddles<\/code> and we&#8217;ll see:<\/p>\n<pre class=\"brush:bash\">\r\nMigrations for 'riddles':\r\n  0001_initial.py:\r\n    - Create model Option\r\n    - Create model Riddle\r\n    - Add field riddle to option\r\n<\/pre>\n<p>By doing this we are telling Django that we made some changes to the models and that these should be stored as a migration, these are just files on the disk, you can read them in a directory called <em>migrations<\/em> within your application. They are designed to be human readable so you would be able to change them if you need.<\/p>\n<p>We can see de actual SQL statements that te migration will run if we want by running <code>python3 manage.py sqlmigrate riddles 0001<\/code>. That <em>0001<\/em> is the version of the migration we want to check. In the output we&#8217;ll see:<\/p>\n<pre class=\"brush:bash\">\r\nBEGIN;\r\n--\r\n-- Create model Option\r\n--\r\nCREATE TABLE \"riddles_option\" (\"id\" integer NOT NULL PRIMARY KEY AUTOINCREMENT, \"text\" varchar(255) NOT NULL, \"correct\" bool NOT NULL);\r\n--\r\n-- Create model Riddle\r\n--\r\nCREATE TABLE \"riddles_riddle\" (\"id\" integer NOT NULL PRIMARY KEY AUTOINCREMENT, \"riddle_text\" varchar(255) NOT NULL, \"pub_date\" datetime NOT NULL);\r\n--\r\n-- Add field riddle to option\r\n--\r\nALTER TABLE \"riddles_option\" RENAME TO \"riddles_option__old\";\r\nCREATE TABLE \"riddles_option\" (\"id\" integer NOT NULL PRIMARY KEY AUTOINCREMENT, \"text\" varchar(255) NOT NULL, \"correct\" bool NOT NULL, \"riddle_id\" integer NOT NULL REFERENCES \"riddles_riddle\" (\"id\"));\r\nINSERT INTO \"riddles_option\" (\"riddle_id\", \"id\", \"text\", \"correct\") SELECT NULL, \"id\", \"text\", \"correct\" FROM \"riddles_option__old\";\r\nDROP TABLE \"riddles_option__old\";\r\nCREATE INDEX \"riddles_option_a7c97949\" ON \"riddles_option\" (\"riddle_id\");\r\n\r\nCOMMIT;\r\n<\/pre>\n<p>Now we run migrate, and this script will be executed in the database. Notice that the <em>sqlmigrate<\/em> command was only to check the script it will execute, it&#8217;s not necessary to run it every time.<\/p>\n<p>Now we can start using the admin page, but we need a user to log in. By running the <em>createsuperuser<\/em> command we&#8217;ll be able to create the root user for our application. It will prompt for a name, a mail and a password. Just run <code>python3 manage.py createsuperuser<\/code>. Now if you run the server and visit <em>http:\/\/127.0.0.1:8000\/admin\/<\/em> you will be able to log in with the credentials you just provided.<\/p>\n<p>Let&#8217;s make our model modifiable by the admin. In <code>riddles\/admin.py<\/code> we give Django all the models that are modifiable via the admin page. Let&#8217;s change it to look like this:<\/p>\n<p><span style=\"text-decoration: underline\"><em>riddles\/admin.py<\/em><\/span><\/p>\n<pre class=\"brush:python\">\r\nfrom django.contrib import admin\r\n\r\nfrom .models import Option, Riddle\r\n\r\nadmin.site.register(Riddle)\r\nadmin.site.register(Option)\r\n<\/pre>\n<p>Now, let&#8217;s check out that admin page. First, we hit <em>http:\/\/localhost:8000\/admin<\/em>, it will redirect us to a login page.<\/p>\n<figure id=\"attachment_10302\" aria-describedby=\"caption-attachment-10302\" style=\"width: 760px\" class=\"wp-caption aligncenter\"><img decoding=\"async\" width=\"760\" height=\"400\" src=\"http:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2016\/01\/login.png\" alt=\"Login Page\" class=\"size-full wp-image-10302\" srcset=\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2016\/01\/login.png 760w, https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2016\/01\/login-300x158.png 300w\" sizes=\"(max-width: 760px) 100vw, 760px\" \/><figcaption id=\"caption-attachment-10302\" class=\"wp-caption-text\"><br \/>\n    <\/a> Login Page<br \/><\/figcaption><\/figure>\n<p>We input the credentials of the super user we created before, and now we see the home.<\/p>\n<figure id=\"attachment_10304\" aria-describedby=\"caption-attachment-10304\" style=\"width: 650px\" class=\"wp-caption aligncenter\"><img decoding=\"async\" width=\"650\" height=\"350\" src=\"http:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2016\/01\/home.png\" alt=\"Home\" class=\"size-full wp-image-10304\" srcset=\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2016\/01\/home.png 650w, https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2016\/01\/home-300x162.png 300w\" sizes=\"(max-width: 650px) 100vw, 650px\" \/><figcaption id=\"caption-attachment-10304\" class=\"wp-caption-text\"><br \/>\n    <\/a><br \/>\n    Home<br \/><\/figcaption><\/figure>\n<p>There we see a couple useful things:<\/p>\n<ul>\n<li>\n        <strong>Authentication and Authorization:<\/strong> These are purely administrative data for our project. We can create, modify, delete and list users and groups.\n    <\/li>\n<li>\n        <strong>Riddles:<\/strong> Here it is. We can administer our riddles and options in this page. Full CRUD operations are available out of the box, it all comes free if you follow Django conventions.\n    <\/li>\n<\/ul>\n<p>Take a little pause here and navigate this admin page. Create a couple riddles and options, even a user. Explore the permissions system and how groups work. It&#8217;s pretty awesome.<\/p>\n<h2>4. The Public Page<\/h2>\n<p>What do we need to make our public page?<\/p>\n<ul>\n<li>Templates: The skeleton of the page the user will see.<\/li>\n<li>Views: The python&#8217;s function that will serve the page content.<\/li>\n<\/ul>\n<p>Let&#8217;s start with the templates. Create a module called <em>templates<\/em> within your application module, and there we&#8217;ll write our <em>index.html<\/em>.<\/p>\n<p><span style=\"text-decoration: underline\"><em>riddles\/templates\/index.html<\/em><\/span><\/p>\n<pre class=\"brush:html\">\r\n<h1>Available Riddles<\/h1>\r\n\r\n{% if message %}\r\n    <p><strong>{{ message }}<\/strong><\/p>\r\n{% endif %}\r\n\r\n{% if latest_riddles %}\r\n\r\n    <ul>\r\n        {% for riddle in latest_riddles %}\r\n            <li>\r\n                <a href=\"\/riddles\/{{ riddle.id }}\/\">\r\n                    {{ riddle.riddle_text }}\r\n                <\/a>\r\n            <\/li>\r\n        {% endfor %}\r\n    <\/ul>\r\n\r\n{% else %}\r\n    <p>No riddles are available right now.<\/p>\r\n{% endif %}\r\n<\/pre>\n<p>As you can see, this is an actual template with a decision and an iteration. If there are riddles available, it iterates through them and puts its text in a link to try and answer it (will check it out later). If no riddle is available, it informs the user. The answer template looks like this:<\/p>\n<p><span style=\"text-decoration: underline\"><em>riddles\/templates\/answer.html<\/em><\/span><\/p>\n<pre class=\"brush:html\">\r\n<h1>{{ riddle.riddle_text }}<\/h1>\r\n\r\n{% if error_message %}\r\n    <p>\r\n        <strong>{{ error_message }}<\/strong>\r\n    <\/p>\r\n{% endif %}\r\n\r\n<form action=\"answer' riddle.id %}\" method=\"post\">\r\n    {% csrf_token %}\r\n    {% for option in riddle.option_set.all %}\r\n        &lt;input type=\"radio\" name=\"option\" id=\"option{{ forloop.counter }}\" value=\"{{ option.id }}\" \/&gt;\r\n        <label for=\"option{{ forloop.counter }}\">{{ option.text }}<\/label><br \/>\r\n    {% endfor %}\r\n    &lt;input type=\"submit\" value=\"Answer\" \/&gt;\r\n<\/form>\r\n<\/pre>\n<p>Here, we are informing the riddle text and all the options as radio inputs within a form. There is a <code>csrf_token<\/code> there; its a token provided by Django to avoid Cross Site Request Forgery, every internal form should use it. Pretty simple, but functional. The views to render these templates and answer these requests look like:<\/p>\n<p><span style=\"text-decoration: underline\"><em>riddles\/views.py<\/em><\/span><\/p>\n<pre class=\"brush:python\">\r\nfrom django.http.response import HttpResponse\r\nfrom django.shortcuts import get_object_or_404, render\r\n\r\nfrom .models import Riddle, Option\r\n\r\n\r\ndef index(request):\r\n    return render(request, \"index.html\", {\"latest_riddles\": Riddle.objects.order_by('-pub_date')[:5]})\r\n\r\n\r\ndef detail(request, riddle_id):\r\n    return render(request, \"answer.html\", {\"riddle\": get_object_or_404(Riddle, pk=riddle_id)})\r\n\r\n\r\ndef answer(request, riddle_id):\r\n    riddle = get_object_or_404(Riddle, pk=riddle_id)\r\n    try:\r\n        option = riddle.option_set.get(pk=request.POST['option'])\r\n    except (KeyError, Option.DoesNotExist):\r\n        return render(request, 'answer.html', {'riddle': riddle, 'error_message': 'Option does not exist'})\r\n    else:\r\n        if option.correct:\r\n            return render(request, \"index.html\", {\"latest_riddles\": Riddle.objects.order_by('-pub_date')[:5], \"message\": \"Nice! Choose another one!\"})\r\n        else:\r\n            return render(request, 'answer.html', {'riddle': riddle, 'error_message': 'Wrong Answer!'})\r\n\r\n<\/pre>\n<p>Let&#8217;s explain one by one each of these functions:<\/p>\n<ul>\n<li><strong>index:<\/strong> Index uses a function called <code>render<\/code>, present in a package called <code>shortcuts<\/code> in Django. This function receives the HttpRequest, the location of the template and its context and returns an HttpReponse with the resulting html.<\/li>\n<li><strong>detail:<\/strong> The detail does pretty much the same, but the function <code>get_object_or_404<\/code> results in an HttpResponse404 if the object is not found for the given primary key.<\/li>\n<li><strong>answer:<\/strong> This function is a little bit more complicated. It looks for the provided riddle (and results in 404 if it is not found), and then it checks that the given option belongs to the given riddle, if not returns a bad request. Once all checks passed, it only checks that the given option has the <em>correct<\/em> flag in true, and returns accordingly.<\/li>\n<\/ul>\n<p>Now we just have to map these functions to some urls to make it navigable. And the mapping in <em>urls.py<\/em>:<\/p>\n<p><span style=\"text-decoration: underline\"><em>riddles\/urls.py<\/em><\/span><\/p>\n<pre class=\"brush:python\">\r\nfrom django.conf.urls import url\r\n\r\nfrom . import views\r\n\r\napp_name = 'riddles'\r\n\r\nurlpatterns = [\r\n    url(r'^$', views.index, name='index'),\r\n    url(r'^(?P[0-9]+)\/$', views.detail, name='detail'),\r\n    url(r'^(?P[0-9]+)\/answer\/$', views.answer, name='answer')\r\n]\r\n<\/pre>\n<p>All set, now by hitting <em>http:\/\/localhost:8000\/riddles\/<\/em> we now can see all the riddles we uploaded via de admin page, and choose one to try to answer it.<\/p>\n<p>Now, let&#8217;s add some CSS to this application. It&#8217;s pretty ugly right now, right?<\/p>\n<h2>5. Style Sheets<\/h2>\n<p>First, we create a directory called <code>static<\/code> within our application&#8217;s module and create a <code>main.css<\/code> that makes the site a little bit less ugly.<\/p>\n<p><span style=\"text-decoration: underline\"><em>riddles\/static\/main.css<\/em><\/span><\/p>\n<pre class=\"brush:css\">\r\nbody{\r\n    margin:40px auto;\r\n    max-width:650px;\r\n    line-height:1.6;\r\n    font-size:18px;\r\n    color:#444;\r\n    padding:0 10px;\r\n}\r\nh1,h2,h3{\r\n    line-height:1.2;\r\n    text-align: center;\r\n}\r\na {\r\n    color: blue;\r\n}\r\n\r\nform {\r\n    margin: 0 auto;\r\n    padding: 1em;\r\n    border: 1px solid #CCC;\r\n    border-radius: 1em;\r\n}\r\nform div + div {\r\n    margin-top: 1em;\r\n}\r\nlabel {\r\n    display: inline-block;\r\n    text-align: center;\r\n    width: 40%;\r\n}\r\ninput {\r\n    font: 1em sans-serif;\r\n    -moz-box-sizing: border-box;\r\n    box-sizing: border-box;\r\n    border: 1px solid #999;\r\n    width: 50%;\r\n}\r\ninput:focus {\r\n    border-color: #000;\r\n}\r\np, div.button {\r\n    text-align: center;\r\n}\r\n\r\np.error-message {\r\n    color: lightcoral;\r\n}\r\n<\/pre>\n<p>Now, let&#8217;s change a little bit our templates:<\/p>\n<p><span style=\"text-decoration: underline\"><em>riddles\/templates\/index.html<\/em><\/span><\/p>\n<pre class=\"brush:html\">\r\n{% load staticfiles %}\r\n\r\n&lt;link rel=\"stylesheet\" type=\"text\/css\" href=\"{% static 'main.css' %}\" \/&gt;\r\n\r\n<h1>Available Riddles<\/h1>\r\n\r\n{% if message %}\r\n    <p><strong>{{ message }}<\/strong><\/p>\r\n{% endif %}\r\n\r\n{% if latest_riddles %}\r\n\r\n    <ul>\r\n        {% for riddle in latest_riddles %}\r\n            <li>\r\n                <a href=\"\/riddles\/{{ riddle.id }}\/\">\r\n                    {{ riddle.riddle_text }}\r\n                <\/a>\r\n            <\/li>\r\n        {% endfor %}\r\n    <\/ul>\r\n\r\n{% else %}\r\n    <p>No riddles are available right now.<\/p>\r\n{% endif %}\r\n<\/pre>\n<p><span style=\"text-decoration: underline\"><em>riddles\/templates\/answer.html<\/em><\/span><\/p>\n<pre class=\"brush:html\">\r\n{% load staticfiles %}\r\n\r\n&lt;link rel=\"stylesheet\" type=\"text\/css\" href=\"{% static 'main.css' %}\" \/&gt;\r\n\r\n<h1>{{ riddle.riddle_text }}<\/h1>\r\n\r\n{% if error_message %}\r\n    <p>\r\n        <strong>{{ error_message }}<\/strong>\r\n    <\/p>\r\n{% endif %}\r\n\r\n<form action=\"answer' riddle.id %}\" method=\"post\">\r\n    {% csrf_token %}\r\n    {% for option in riddle.option_set.all %}\r\n        &lt;input type=\"radio\" name=\"option\" id=\"option{{ forloop.counter }}\" value=\"{{ option.id }}\" \/&gt;\r\n        <label for=\"option{{ forloop.counter }}\">{{ option.text }}<\/label><br \/>\r\n    {% endfor %}\r\n    &lt;input type=\"submit\" value=\"Answer\" \/&gt;\r\n<\/form>\r\n<\/pre>\n<p>The first line loads static files, and then we use that <code>{% static '#' %}<\/code> where # is the location of the resource you want to import. For javascripts is the exact same procedure, you just need to build the url within a <code>script<\/code> instead of a <code>link<\/code>.<\/p>\n<h2>6. Download the Code Project<\/h2>\n<p>This was a basic example of a Python Django application. You can now build your own, you just saw how easy it is.<\/p>\n<div class=\"download\">\n    <strong>Download<\/strong><br \/> You can download the full source code of this example here: <a href=\"http:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2016\/01\/django_example.zip\"><strong>python-django-example<\/strong><\/a>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Django is an open source web framework which solves most common problems of a web application development. It has some very useful features like an auto generated admin page and an ORM. It&#8217;s a high-level framework, so we just need to focus on the actual core logic of our business and let Django take care &hellip;<\/p>\n","protected":false},"author":109,"featured_media":1651,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[53],"tags":[311,313],"class_list":["post-10205","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-python","tag-django","tag-riddle"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Python Django Tutorial - Web Code Geeks - 2026<\/title>\n<meta name=\"description\" content=\"Django is an open source web framework which solves most common problems of a web application development. It has some very useful features like an auto\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.webcodegeeks.com\/python\/python-django-tutorial\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Python Django Tutorial - Web Code Geeks - 2026\" \/>\n<meta property=\"og:description\" content=\"Django is an open source web framework which solves most common problems of a web application development. It has some very useful features like an auto\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.webcodegeeks.com\/python\/python-django-tutorial\/\" \/>\n<meta property=\"og:site_name\" content=\"Web Code Geeks\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/webcodegeeks\" \/>\n<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/sgvinci\" \/>\n<meta property=\"article:published_time\" content=\"2016-01-19T14:11:38+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2018-01-09T07:49:21+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"150\" \/>\n\t<meta property=\"og:image:height\" content=\"150\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Sebastian Vinci\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@sebastianvinci_\" \/>\n<meta name=\"twitter:site\" content=\"@webcodegeeks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Sebastian Vinci\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"13 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/python-django-tutorial\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/python-django-tutorial\/\"},\"author\":{\"name\":\"Sebastian Vinci\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/06a43c63e373dff2e159bbc029b405aa\"},\"headline\":\"Python Django Tutorial\",\"datePublished\":\"2016-01-19T14:11:38+00:00\",\"dateModified\":\"2018-01-09T07:49:21+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/python-django-tutorial\/\"},\"wordCount\":1733,\"commentCount\":1,\"publisher\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/python-django-tutorial\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg\",\"keywords\":[\"django\",\"riddle\"],\"articleSection\":[\"Python\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.webcodegeeks.com\/python\/python-django-tutorial\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/python-django-tutorial\/\",\"url\":\"https:\/\/www.webcodegeeks.com\/python\/python-django-tutorial\/\",\"name\":\"Python Django Tutorial - Web Code Geeks - 2026\",\"isPartOf\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/python-django-tutorial\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/python-django-tutorial\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg\",\"datePublished\":\"2016-01-19T14:11:38+00:00\",\"dateModified\":\"2018-01-09T07:49:21+00:00\",\"description\":\"Django is an open source web framework which solves most common problems of a web application development. It has some very useful features like an auto\",\"breadcrumb\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/python-django-tutorial\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.webcodegeeks.com\/python\/python-django-tutorial\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/python-django-tutorial\/#primaryimage\",\"url\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg\",\"contentUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg\",\"width\":150,\"height\":150},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/python-django-tutorial\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.webcodegeeks.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Python\",\"item\":\"https:\/\/www.webcodegeeks.com\/category\/python\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Python Django Tutorial\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#website\",\"url\":\"https:\/\/www.webcodegeeks.com\/\",\"name\":\"Web Code Geeks\",\"description\":\"Web Developers Resource Center\",\"publisher\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.webcodegeeks.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#organization\",\"name\":\"Exelixis Media P.C.\",\"url\":\"https:\/\/www.webcodegeeks.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png\",\"contentUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png\",\"width\":864,\"height\":246,\"caption\":\"Exelixis Media P.C.\"},\"image\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/webcodegeeks\",\"https:\/\/x.com\/webcodegeeks\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/06a43c63e373dff2e159bbc029b405aa\",\"name\":\"Sebastian Vinci\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/12d0233b49dd2a282330a987b16e81c3fbd4a8a8f5d5338348a6edd47cfff99e?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/12d0233b49dd2a282330a987b16e81c3fbd4a8a8f5d5338348a6edd47cfff99e?s=96&d=mm&r=g\",\"caption\":\"Sebastian Vinci\"},\"description\":\"Sebastian is a full stack programmer, who has strong experience in Java and Scala enterprise web applications. He is currently studying Computers Science in UBA (University of Buenos Aires) and working a full time job at a .com company as a Semi-Senior developer, involving architectural design, implementation and monitoring. He also worked in automating processes (such as data base backups, building, deploying and monitoring applications).\",\"sameAs\":[\"http:\/\/www.webcodegeeks.com\/\",\"https:\/\/www.facebook.com\/sgvinci\",\"https:\/\/x.com\/sebastianvinci_\"],\"url\":\"https:\/\/www.webcodegeeks.com\/author\/sebastian-vinci\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Python Django Tutorial - Web Code Geeks - 2026","description":"Django is an open source web framework which solves most common problems of a web application development. It has some very useful features like an auto","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.webcodegeeks.com\/python\/python-django-tutorial\/","og_locale":"en_US","og_type":"article","og_title":"Python Django Tutorial - Web Code Geeks - 2026","og_description":"Django is an open source web framework which solves most common problems of a web application development. It has some very useful features like an auto","og_url":"https:\/\/www.webcodegeeks.com\/python\/python-django-tutorial\/","og_site_name":"Web Code Geeks","article_publisher":"https:\/\/www.facebook.com\/webcodegeeks","article_author":"https:\/\/www.facebook.com\/sgvinci","article_published_time":"2016-01-19T14:11:38+00:00","article_modified_time":"2018-01-09T07:49:21+00:00","og_image":[{"width":150,"height":150,"url":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg","type":"image\/jpeg"}],"author":"Sebastian Vinci","twitter_card":"summary_large_image","twitter_creator":"@sebastianvinci_","twitter_site":"@webcodegeeks","twitter_misc":{"Written by":"Sebastian Vinci","Est. reading time":"13 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.webcodegeeks.com\/python\/python-django-tutorial\/#article","isPartOf":{"@id":"https:\/\/www.webcodegeeks.com\/python\/python-django-tutorial\/"},"author":{"name":"Sebastian Vinci","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/06a43c63e373dff2e159bbc029b405aa"},"headline":"Python Django Tutorial","datePublished":"2016-01-19T14:11:38+00:00","dateModified":"2018-01-09T07:49:21+00:00","mainEntityOfPage":{"@id":"https:\/\/www.webcodegeeks.com\/python\/python-django-tutorial\/"},"wordCount":1733,"commentCount":1,"publisher":{"@id":"https:\/\/www.webcodegeeks.com\/#organization"},"image":{"@id":"https:\/\/www.webcodegeeks.com\/python\/python-django-tutorial\/#primaryimage"},"thumbnailUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg","keywords":["django","riddle"],"articleSection":["Python"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.webcodegeeks.com\/python\/python-django-tutorial\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.webcodegeeks.com\/python\/python-django-tutorial\/","url":"https:\/\/www.webcodegeeks.com\/python\/python-django-tutorial\/","name":"Python Django Tutorial - Web Code Geeks - 2026","isPartOf":{"@id":"https:\/\/www.webcodegeeks.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.webcodegeeks.com\/python\/python-django-tutorial\/#primaryimage"},"image":{"@id":"https:\/\/www.webcodegeeks.com\/python\/python-django-tutorial\/#primaryimage"},"thumbnailUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg","datePublished":"2016-01-19T14:11:38+00:00","dateModified":"2018-01-09T07:49:21+00:00","description":"Django is an open source web framework which solves most common problems of a web application development. It has some very useful features like an auto","breadcrumb":{"@id":"https:\/\/www.webcodegeeks.com\/python\/python-django-tutorial\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.webcodegeeks.com\/python\/python-django-tutorial\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.webcodegeeks.com\/python\/python-django-tutorial\/#primaryimage","url":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg","contentUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg","width":150,"height":150},{"@type":"BreadcrumbList","@id":"https:\/\/www.webcodegeeks.com\/python\/python-django-tutorial\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.webcodegeeks.com\/"},{"@type":"ListItem","position":2,"name":"Python","item":"https:\/\/www.webcodegeeks.com\/category\/python\/"},{"@type":"ListItem","position":3,"name":"Python Django Tutorial"}]},{"@type":"WebSite","@id":"https:\/\/www.webcodegeeks.com\/#website","url":"https:\/\/www.webcodegeeks.com\/","name":"Web Code Geeks","description":"Web Developers Resource Center","publisher":{"@id":"https:\/\/www.webcodegeeks.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.webcodegeeks.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.webcodegeeks.com\/#organization","name":"Exelixis Media P.C.","url":"https:\/\/www.webcodegeeks.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","contentUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","width":864,"height":246,"caption":"Exelixis Media P.C."},"image":{"@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/webcodegeeks","https:\/\/x.com\/webcodegeeks"]},{"@type":"Person","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/06a43c63e373dff2e159bbc029b405aa","name":"Sebastian Vinci","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/12d0233b49dd2a282330a987b16e81c3fbd4a8a8f5d5338348a6edd47cfff99e?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/12d0233b49dd2a282330a987b16e81c3fbd4a8a8f5d5338348a6edd47cfff99e?s=96&d=mm&r=g","caption":"Sebastian Vinci"},"description":"Sebastian is a full stack programmer, who has strong experience in Java and Scala enterprise web applications. He is currently studying Computers Science in UBA (University of Buenos Aires) and working a full time job at a .com company as a Semi-Senior developer, involving architectural design, implementation and monitoring. He also worked in automating processes (such as data base backups, building, deploying and monitoring applications).","sameAs":["http:\/\/www.webcodegeeks.com\/","https:\/\/www.facebook.com\/sgvinci","https:\/\/x.com\/sebastianvinci_"],"url":"https:\/\/www.webcodegeeks.com\/author\/sebastian-vinci\/"}]}},"_links":{"self":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/posts\/10205","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/users\/109"}],"replies":[{"embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/comments?post=10205"}],"version-history":[{"count":0,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/posts\/10205\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/media\/1651"}],"wp:attachment":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/media?parent=10205"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/categories?post=10205"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/tags?post=10205"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}