Get up and running with routes, views, and templates in Python’s most popular web framework. Credit: SERSOLL/Shutterstock Django is a one-size-fits-all Python web framework that was inspired by Ruby on Rails and uses many of the same metaphors to make web development fast and easy. Fully loaded and flexible, Django has become one of Python’s most widely used web frameworks. Django includes virtually everything you need to build a web application of any size, and its popularity makes it easy to find examples and help for various scenarios. Plus Django provides tools to allow your application to evolve and add features gracefully, and to migrate its data schema (if there is one). Django also has a reputation for being complex, with many components and a good deal of “under the hood” configuration required. In truth, you can get a simple Python application up and running in relatively short order, then expand its functionality as needed. This article guides you through creating a basic Django 5.0 app. We’ll also touch on the most crucial features for web developers in the Django 5 release. Installing Django’s core libraries To install Django 5.0, you will need Python 3.10 or better. If you’re stuck on an earlier version of Python, you may be able to use version 4; consult Django’s Python version table to find out what versions you can use. Ideally, use the most recent Python version that supports everything you may want to do with your Django project. The first step is to create a virtual environment in which you will install Django. This keeps Django and its associated libraries separate from your base Python installation, always a good practice. Next, install Django in your chosen virtual environment via Python’s pip utility: pip install django This installs the core Django libraries and the django-admin command-line utility used for managing Django projects. Creating a new Django project Django instances are organized into two tiers: projects and apps. A project is an instance of Django with its own database configuration, settings, and apps. It’s best to think of a project as a place to store all the site-level configurations you’ll use. An app is a subdivision of a project, with its own route and rendering logic. Multiple apps can be placed in a single Django project. To create a new Django project from scratch, enter the directory where you want to store the project and type: django-admin startproject <project_name> The <project_name> is the name of both the project and the subdirectory where the project will be stored. Be sure to pick a name that isn’t likely to collide with a name used by Python or Django internally. A name like myproj works well. The newly created directory should contain a manage.py file, which is used to control the app’s behavior from the command line, and another subdirectory (also with the project name) that contains the following files: An __init__.py file, which is used by Python to designate a subdirectory as a code module. settings.py, which holds the settings used for the project. Many of the most common settings will be pre-populated for you. urls.py, which lists the routes or URLs available to your Django project, or that the project will return responses for. wsgi.py, which is used by WSGI-compatible web servers, such as Apache HTTP or Nginx, to serve your project’s apps. asgi.py, which is used by ASGI-compatible web servers to serve your project’s apps. ASGI is a relatively new standard for asynchronous servers and apps, and requires a server that supports it, like uvicorn. Django only recently added native support for asynchronous apps, which will also need to be hosted on an async-compatible server to be fully effective. Next, test the project to ensure it’s functioning. From the command line in the directory containing your project’s manage.py file, run: python manage.py runserver This should start a development web server available at http://127.0.0.1:8000/. Visit that link and you should see a simple welcome page that tells you that the installation was successful. Note that the development web server should not be used to serve a Django project to the public. It’s solely for local testing and is not designed to scale for public-facing apps. Creating a Django app Next, we’ll create an application inside of this project. Navigate to the same directory as manage.py and issue this command: python manage.py startapp myapp This creates a subdirectory for an app named myapp that contains the following: A migrations directory: Contains code used to migrate the site between versions of its data schema. Django projects typically have a database, so the schema for the database—including changes to the schema—is managed as part of the project. admin.py: Contains objects used by Django’s built-in administration tools. If your app has an admin interface or privileged users, you will configure the related objects here. apps.py: Provides configuration information about the app to the project at large, by way of an AppConfig object. models.py: Contains objects that define data structures used by your app to interface with databases. tests.py: Contains any tests used to ensure that your site’s functions and modules are working as intended. views.py: Contains functions that render and return responses. To start working with the app, you need to first register it with the project. Edit myproj/settings.py as follows, adding a line to the top of the INSTALLED_APPS list: INSTALLED_APPS = [ "myapp.apps.MyappConfig", "django.contrib.admin", ... If you look in myproj/myapp/apps.py, you’ll see a pre-generated object named MyappConfig, which we’ve referenced here. Adding routes and views to your Django app Django applications follow a basic pattern for processing requests: When an incoming request is received, Django parses the URL for a route to apply it to. Routes are defined in urls.py, with each route linked to a view, meaning a function that returns data to be sent back to the client. Views can be located anywhere in a Django project, but they’re best organized into their own modules. Views can contain the results of a template, which is code that formats requested data according to a certain design. To get an idea of how all these pieces fit together, let’s modify the default route of our sample application to return a custom message. Routes are defined in urls.py in a list named urlpatterns. If you open the sample urls.py, you’ll see urlpatterns already predefined: urlpatterns = [ path('admin/', admin.site.urls), ] The path function—a Django built-in—takes a route and a view function as arguments and generates a reference to a URL path. By default, Django creates an admin path that is used for site administration, but we need to create our own routes. Add another entry, so that the whole file looks like this: from django.contrib import admin from django.urls import include, path urlpatterns = [ path('admin/', admin.site.urls), path('myapp/', include('myapp.urls')) ] The include function tells Django to look for more route pattern information in the file myapp.urls. All routes found in that file will be attached to the top-level route myapp (e.g., http://127.0.0.1:8080/myapp). Next, create a new urls.py in myapp and add the following: from django.urls import path from . import views urlpatterns = [ path('', views.index) ] Django prepends a slash to the beginning of each URL, so to specify the root of the site (/), we just supply a blank string as the URL. Now, edit the file myapp/views.py so it looks like this: from django.http import HttpResponse def index(request): return HttpResponse("Hello, world!") django.http.HttpResponse is a Django built-in that generates an HTTP response from a supplied string. Note that request, which contains the information for an incoming HTTP request, must be passed as the first parameter to a view function. Stop and restart the development server, and navigate to http://127.0.0.1:8000/myapp/. You should see “”Hello, world!” appear in the browser. Adding routes with variables in Django Django can accept routes that incorporate variables as part of their syntax. Let’s say you wanted to accept URLs that had the format year/<int:year>. You could accomplish that by adding the following entry to urlpatterns: path('year/', views.year) The view function views.year would then be invoked through routes like year/1996, year/2010, and so on, with the variable year passed as a parameter to views.year. To try this out for yourself, add the above urlpatterns entry to myapp/urls.py, then add this function to myapp/views.py: def year(request, year): return HttpResponse('Year: {}'.format(year)) If you navigate to /myapp/year/2010 on your site, you should see Year: 2010 displayed in response. Note that routes like /myapp/year/rutabaga will yield an error because the int: constraint on the variable year allows only an integer in that position. Many other formatting options are available for routes. Earlier versions of Django had a more complex syntax for routes, which was difficult to parse. If you still need to add routes using the old syntax—for instance, for backward compatibility with an old Django project—you can use the django.urls.re_path function, which matches routes using regular expressions. Django templates Django’s built-in template language can be used to generate web pages from data. Templates used by Django apps are stored in a directory that is central to the project: <app_name>/templates/<app_name>/. For our myapp project, the directory would be myapp/templates/myapp/. This directory structure may seem awkward, but allowing Django to look for templates in multiple places avoids name collisions between templates with the same name across multiple apps. In your myapp/templates/myapp/ directory, create a file named year.html with the following content: Year: {{year}} Any value within double curly braces in a template is treated as a variable. Everything else is treated literally. Modify myapp/views.py to look like this: from django.shortcuts import render from django.http import HttpResponse def index(request): return HttpResponse("Hello, world!") def year(request, year): data = {'year':year} return render(request, 'myapp/year.html', data) The render function—a Django “shortcut” (a combination of multiple built-ins for convenience)—takes the existing request object, looks for the template myapp/year.html in the list of available template locations, and passes the dictionary data to it as context for the template. The template uses the dictionary as a namespace for variables used in the template. In this case, the variable {{year}} in the template is replaced with the value for the key year in the dictionary data (that is, data["year"]). The amount of processing you can do on data within Django templates is intentionally limited. Django’s philosophy is to enforce the separation of presentation and business logic whenever possible. Thus, you can loop through an iterable object, and you can perform if/then/else tests, but modifying the data within a template is discouraged. For instance, you could encode a simple “if” test this way: {% if year > 2000 %} 21st century year: {{year}} {% else %} Pre-21st century year: {{year}} {% endif %} The {% and %} markers delimit blocks of code that can be executed in Django’s template language. If you want to use a more sophisticated template processing language, you can swap in something like Jinja2 or Mako. Django includes back-end integration for Jinja2, but you can use any template language that returns a string—for instance, by returning that string in a HttpResponse object as in the case of our "Hello, world!" route. Next steps with Django What you’ve seen here covers only the most basic elements of a Django application. Django includes a great many other components for use in web projects. All of these are worth discussing in detail separately, but I will leave you with a brief overview: Databases and data models: Django’s built-in ORM lets you define data structures and relationships between them for your app, as well as migration paths between versions of those structures. Forms: Django provides a consistent way for views to supply input forms to a user, retrieve data, normalize the results, and provide consistent error reporting. Security and utilities: Django includes many built-in functions for caching, logging, session handling, handling static files, and normalizing URLs. It also bundles tools for common security needs like using cryptographic certificates or guarding against cross-site forgery protection or clickjacking. Related content news Spin 3.0 supports polyglot development using Wasm components Fermyon’s open source framework for building server-side WebAssembly apps allows developers to compose apps from components created with different languages. By Paul Krill Nov 18, 2024 2 mins Microservices Serverless Computing Development Libraries and Frameworks how-to How to use DispatchProxy for AOP in .NET Core Take advantage of the DispatchProxy class in C# to implement aspect-oriented programming by creating proxies that dynamically intercept method calls. By Joydip Kanjilal Nov 14, 2024 7 mins Microsoft .NET C# Development Libraries and Frameworks news Microsoft’s .NET 9 arrives, with performance, cloud, and AI boosts Cloud-native apps, AI-enabled apps, ASP.NET Core, Aspire, Blazor, MAUI, C#, and F# all get boosts with the latest major rev of the .NET platform. By Paul Krill Nov 12, 2024 4 mins C# Generative AI Microsoft .NET feature Can Wasm replace containers? WebAssembly revolutionized browser apps, and promises to upend the server stack. How will it impact containers and Kubernetes? Six experts weigh in. By Bill Doerrfeld Nov 11, 2024 12 mins Containers Kubernetes Cloud Native Resources Videos