Views, urls and templates Django

Notes Single

This article is a continuation of the article "Installation Django", in which we got to the creation of an app called "my_app", it is recommended to read that article if you haven't already.

Create a view

The views are functions that have been tied to an url and are executed when the server receives a request which matches the corresponding url.

These functions can do things that are up to the programmer but the final proposal is returning an HTTPResponse or a 404 error.

The views can be defined at each app or at the project, both cases in the "views.py" file. Always we define a view, this must be registered at "urls.py", defininig the relation between the view and the url.

We already have a simple view at the app's directory:

from django.http import HttpResponse

def index(request):
    return HttpResponse('Hello world my_app!')

Let's add other views that receive parameters:

from django.http import HttpResponse

    def index(request):
        return HttpResponse('Hello world my_app!')
            
    def user_by_id(request, user_id):
        return HttpResponse("The id of user required is: %s." % user_id)
    
    def user_by_name(request, user_name):
        response = "You are asking for %s."
        return HttpResponse(response % user_name)

Now, registering at "my_app/urls.py":

from django.urls import path

from . import views

app_name = 'my_app' # namespace for app's urls
urlpatterns = [
    # ex: /my_app/
    # path(url,function,name for this url)
    path('', views.index, name='index'),
    # ex: /my_app/5/
    path('<int:user_id>/', views.user_by_id, name='id'),
    # ex: /my_app/name/fer
    path('name/<str:user_name>', views.user_by_name, name='name'),
]

Project's urls vs App's urls

It is a good practice managing the urls (also views, and templates) at each app, for this works, the app's url segment must be registered in the project's urls.py, like following "my_project/urls.py":

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('my_app/', include('my_app.urls')),
    path('admin/', admin.site.urls),
]

Let's check the following URLs to test the URLs define in 'my_app/url'

Checking 'localhost:8000/my_app':

Checking 'localhost:8000/my_app/5':

Checking 'localhost:8000/my_app/fer':

Render HTML templates

For rendering templates, we must follow the next steps:

1. Import the function "render" at "my_app/views.py", the function returns a render object which arguments are the request, the template's relative route and a context (dictionary used in case you need to send data to the template). The new function "login" will render the HTML template:

from django.http import HttpResponse
from django.shortcuts import render

def index(request):
    return render(request, "my_app/index.html", {
        "title": 'My first template',
        "content": 'My first template using Django'
    })
        
def user_by_id(request, user_id):
    return HttpResponse("The id of user required is: %s." % user_id)

def user_by_name(request, user_name):
    response = "You are asking for %s."
    return HttpResponse(response % user_name)
    
def login(request):
    return render(request, "my_app/form.html", {})

Register the url for this function, in this case, we are going to use the URL "/login":

from django.urls import path

from . import views
app_name = 'my_app' # namespace for app's urls
urlpatterns = [
    # ex: /my_app/
    # path(url,function,name for this url)
    path('', views.index, name='index'),
    # ex: /my_app/5/
    path('<int:user_id>/', views.user_by_id, name='id'),
    # ex: /my_app/name/fer
    path('name/<str:user_name>', views.user_by_name, name='name'),
    path('login/', views.login, name='login')
]

2. Create a directory "templates" at project's root and register it at settings.py on the key 'DIRS':

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': ['templates'],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

We must store the HTML templates in this directory. Another (and better) option is creating a "templates" directory for each app, then we can store the app's templates within the app's directory. Remember the framework will looking for the file in the project's directory first and later in the app's directory.

3. Create a directory "static" at project's root, where we will put the js, css and images files. We must register this directory in settings.py:

STATIC_URL = 'static/'
STATICFILES_DIRS = ['static', ]

We can use this resources following this sintaxys in the HTML template:

{% load static %}
<link rel="stylesheet" href="{% static 'css/styles.css' %}">
<img src="{% static 'images/draw2.webp' %}">

Example 1: Login form

For this example, we can use this HTML template, which is a login form, the file must be stored at "my_app/templates/my_app", the name for the HTML file is "form.html":

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
  <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css" integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf" crossorigin="anonymous">
  <link rel="stylesheet" href="{% static 'css/styles.css' %}">
  <title>Login</title>
</head>
<body>
  <section class="vh-100">
    <div class="container-fluid h-custom">
      <div class="row d-flex justify-content-center align-items-center h-100">
        <div class="col-md-9 col-lg-6 col-xl-5">
          <img src="{% static 'images/draw.webp' %}"
            class="img-fluid" alt="Sample image">
        </div>
        <div class="col-md-8 col-lg-6 col-xl-4 offset-xl-1">
          <form>
            <div class="d-flex flex-row align-items-center justify-content-center justify-content-lg-start">
              <p class="lead fw-normal mb-0 me-3">Sign in with</p>
              <button type="button" class="btn btn-primary btn-floating mx-1">
                <i class="fab fa-facebook-f"></i>
              </button>
  
              <button type="button" class="btn btn-primary btn-floating mx-1">
                <i class="fab fa-twitter"></i>
              </button>
  
              <button type="button" class="btn btn-primary btn-floating mx-1">
                <i class="fab fa-linkedin-in"></i>
              </button>
            </div>
  
            <div class="divider d-flex align-items-center my-4">
              <p class="text-center fw-bold mx-3 mb-0">Or</p>
            </div>
  
            <!-- Email input -->
            <div class="form-outline mb-4">
              <input type="email" id="form3Example3" class="form-control form-control-lg"
                placeholder="Enter a valid email address" />
              <label class="form-label" for="form3Example3">Email address</label>
            </div>
  
            <!-- Password input -->
            <div class="form-outline mb-3">
              <input type="password" id="form3Example4" class="form-control form-control-lg"
                placeholder="Enter password" />
              <label class="form-label" for="form3Example4">Password</label>
            </div>
  
            <div class="d-flex justify-content-between align-items-center">
              <!-- Checkbox -->
              <div class="form-check mb-0">
                <input class="form-check-input me-2" type="checkbox" value="" id="form2Example3" />
                <label class="form-check-label" for="form2Example3">
                  Remember me
                </label>
              </div>
              <a href="#!" class="text-body">Forgot password?</a>
            </div>
  
            <div class="text-center text-lg-start mt-4 pt-2">
              <button type="button" class="btn btn-primary btn-lg"
                style="padding-left: 2.5rem; padding-right: 2.5rem;">Login</button>
              <p class="small fw-bold mt-2 pt-1 mb-0">Don't have an account? <a href="#!"
                  class="link-danger">Register</a></p>
            </div>
  
          </form>
        </div>
      </div>
    </div>
    <div
      class="d-flex flex-column flex-md-row text-center text-md-start justify-content-between py-4 px-4 px-xl-5 bg-primary">
      <!-- Copyright -->
      <div class="text-white mb-3 mb-md-0">
        Copyright © 2020. All rights reserved.
      </div>
      <!-- Copyright -->
  
      <!-- Right -->
      <div>
        <a href="#!" class="text-white me-4">
          <i class="fab fa-facebook-f"></i>
        </a>
        <a href="#!" class="text-white me-4">
          <i class="fab fa-twitter"></i>
        </a>
        <a href="#!" class="text-white me-4">
          <i class="fab fa-google"></i>
        </a>
        <a href="#!" class="text-white">
          <i class="fab fa-linkedin-in"></i>
        </a>
      </div>
      <!-- Right -->
    </div>
  </section>
  <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.6/dist/umd/popper.min.js" integrity="sha384-oBqDVmMz9ATKxIep9tiCxS/Z9fNfEXiDAYTujMAeBAsjFuCZSmKbSSUnQlmh/jp3" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.min.js" integrity="sha384-cuYeSxntonz0PPNlHhBs68uyIAVpIIOZZ5JqeqvYYIcEL727kskC66kF92t6Xl2V" crossorigin="anonymous"></script>
</body>
</html>

If you are following the steps, you should notice the template couldn't load an image with this route: "images/draw.webp". You can download the next image, rename it to "draw.webp" and store it at "statics/images" at the root's project (my_project/static/images).

Did you get this result?


Example 2: A table that receives data from the view

Let's register the url "products/":

from django.urls import path

from . import views

app_name = 'my_app' # namespace for app's urls
urlpatterns = [
    # ex: /my_app/
    # path(url,function,name for this url)
    path('', views.index, name='index'),
    # ex: /my_app/5/
    path('/', views.user_by_id, name='id'),
    # ex: /my_app/name/fer
    path('name/', views.user_by_name, name='name'),
    path('login/', views.login, name='login'),
    path('products/', views.products, name='products'),
]

Create the function in the view, in this case, let's add the function "products", now using a dictionary to send data to the template:

from django.http import HttpResponse
from django.shortcuts import render

def index(request):
    return render(request, "my_app/index.html", {
        "title": 'My first template',
        "content": 'My first template using Django'
    })
        
def user_by_id(request, user_id):
    return HttpResponse("The id of user required is: %s." % user_id)

def user_by_name(request, user_name):
    response = "You are asking for %s."
    return HttpResponse(response % user_name)
    
def login(request):
    return render(request, "my_app/form.html", {})

def products(request):
    title = "Products"
    content = "This is the content of this page"
    return render(request, "my_app/products.html", {
        "title": title,
        "content": content,
        'products': [
            {'title': 'Shirt', 'price': 5, 'stock': True},
            {'title': 'Blouse', 'price': 3, 'stock': True},
            {'title': 'Pants', 'price': 15, 'stock': False},
        ]
    })

Finally, the HTML template "my_app/templates/my_app/products.html"

<!doctype html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>{{title}}</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet"
        integrity="sha384-0evHe/X+R7YkIZDRvuzKMRqM+OrBnVFBL6DOitfPri4tjfHxaWutUpFmBp4vmVor" crossorigin="anonymous">
</head>

<body>
    <div class="container">
        <div class="row">
            <div class="col">
                <h1>{{content}}</h1>
                {# This is a comment #}
                <ul class="list-group">
                    {% for product in products %}
                    <li class="list-group-item">
                        {{product.title}}
                        {% if product.stock %}
                        <span class="text-success">Available</span>
                        {% else %}
                        <span class="text-danger">Not available</span>
                        {% endif %}
                    </li>
                    {% endfor %}
                </ul>
            </div>
        </div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/js/bootstrap.bundle.min.js"
        integrity="sha384-pprn3073KE6tl6bjs2QrFaJGz5/SUsLqktiwsUTF55Jfv3qYSDhgCecCxMW52nD2"
        crossorigin="anonymous"></script>
</body>

</html>

Did you get this result?


Thanks for reading :)
I invite you to continue reading other entries and visiting us again soon.

Related Posts: