Change language

Why you should choose Django for your next project

Django is a free framework for Python-based web applications using the MVC design pattern. The project is supported by Django Software Foundation.

A Django website is built from one or more applications, which are recommended to be alienated and pluggable. This is one of the essential architectural differences between the framework and some others (such as Ruby on Rails). One of the main principles of the framework is DRY (Don't repeat yourself)

Django web framework is used in Instagram, Disqus, Mozilla, The Washington Times, Pinterest, YouTube, Google, etc.

Django architecture is similar to Model-View-Controller (MVC). The controller of the classic MVC model roughly corresponds to a layer, which in Django is called View, and the presentation logic of the View is implemented in Django by the Template layer. Because of this, Django's layered architecture is often referred to as Model-Template-Presentation (MTV).

Django's main features

  • ORM, a database access API with transaction support;
  • Built-in admin interface with translations already available in many languages;
  • URL manager based on regular expressions;
  • extensible template system with tagging and inheritance;
  • caching system;
  • internationalization;
  • pluggable application architecture that can be installed on any Django site;
  • Generic views - templates for controller functions;
  • authorisation and authentication, connectivity of external authentication modules: LDAP, OpenID, etc.;
  • system of filters (middleware) for building additional request handlers, like filters for caching, compression, URL normalisation and anonymous sessions support;
  • library for working with forms (inheritance, building forms on the existing database model);
  • built-in automatic documentation on template tags and data models, accessible through the administrative application.

Django Rest Framework for API creation

Django Rest Framework (DRF) is a library that works with standard Django models to create a flexible and powerful API for a project. This article will help you understand the structure of DRF and give you an introduction to get started using it.

The DRF API consists of three layers:

  • The Serializer converts the information stored in the database and defined using Django models into a format that is easily and efficiently transferred through the API.
  • ViewSet defines the functions (read, create, update, delete) to be accessed through the API.
  • The router defines the URLs that will provide access to each view.


When not to use Django

  • For very, very large applications, as some functionality is specifically chosen for language and technology, plus Django is architecturally closer to a monolith than to microservices.
  • If you need to write a simple application that doesn't need to handle a database, perform file operations or do anything at all complicated. For such situations, microframeworks are better suited.
  • You want to write everything from scratch yourself and you know what you're doing.
  • You or your colleagues are completely unfamiliar with Django/Python and don't have the time or resources to build the necessary skills.

If the above isn't the case for your project, Django is probably right for you.

From personal experience: the ideal use of Djnago for backend development is to write a backend at a hackathon. Very many built-in features and extensions, the most convenient and fastest development compared to other languages and frameworks. As we know, time is very limited at a hackathon.

See also:


Introduction

Django is a popular, powerful Python framework. It has many "batteries" and allows you to start developing right away. However, all this power means that you can write low-impact code that seems to work. So what is meant by Efficient Django? By Efficient Django we will mean using Django in such a way that the code you write is cohesive, testable, and scalable. So what does each of these words mean?

"Connected" code is code that focuses on doing one thing, just one single thing. This means that when you write a function or a method - the code you write should do one thing and do it well.

This applies directly to writing testable code: code that does many things is quite often overkill for testing. When I catch myself thinking "OK, this piece of code is too complex to write tests for - it's just not worth the effort" - that's the signal to go back and focus on simplification. Testable code is code that makes it easy to write tests for it; code that is easy to find problems in.

Finally, we want to write scalable code. This means not just scalable in terms of execution, but also scalable in terms of command and command understanding. Well tested applications are easier for others to understand (and easier for them to change), which implies a greater opportunity to improve your application by adding new engineers.

My goal is to convince you of the importance of these principles, and provide examples of how following them can build a more resilient Django application. I'm going to go through the process of building a contact management application in sequence, talking about the solutions and testing strategy I use.

These documents are a combination of notes and examples prepared for PyCon 2012, PyOhio 2012, and PyCon 2013 as well as Eventbrite web development. I'm still working on combining them into one document, but I hope you find them useful.

1. Getting started

1.1 Your development environment

When talking about your development environment, there are three important facts to keep in mind: isolation, predeterminism and similarity. Each of these is important, and they all interact in a coherent way.

Isolation means that you cannot accidentally make use of tools or packages that are installed outside your environment. This is especially important when doing this with something like Python packages with extensions written in C: if you use something installed at system level and are not aware of it, you may find that it does not work as intended when you deploy or distribute your code. Tools like virtualenv can help you create something like an isolated environment.

Your environment is predefined as long as you are sure about which version of your dependencies you are relying on and whether you can reproduce the system environment for sure.

Finally, similarity to a production or development server environment means that the same operating system is installed everywhere (perhaps even the same release) and you use the same tools to both configure your development environment and configure your production environment. This is by no means a necessity, but if you are building large and complex software - similarity will be useful to make sure that any problems you may see on a "live" server are reproducible in the environment where you are developing. In addition, similarity limits the scope of your code.

1.1.1 Isolation

We want to avoid using unknown dependencies or unknown versions.
virtualenv provides an easy way to work on your project without using system site-packages.

1.1.2 Predetermination

  • Predefined refers to dependency management.
  • Choose one of the tools and use it in development as well as in a live server:
    • pip and special dependency files;
    • buildout;
    • install-requires in setup.py.
  • Determine the exact versions of the dependencies.

You can specify exact versions using either the PyPI package version or a specific revision (SHA in git, revision number in Subversion, etc.). This ensures that you can get exactly the same versions of packages as you use in testing.

1.1.3 Similarity

Work in an environment similar to the one where you will be deploying your application and trying to diagnose problems.

If you are developing something that requires additional services - similarity becomes even more important.

Vagrant is a virtual machine management tool that allows you to easily set up an environment separate from your production environment.

1.2 Setting up your environment

1.2.1 Creating a clean workspace

First, let's create a directory (tutorial) in which to work:

~$ mkdir tutorial
~$ cd tutorial
~/tutorial$ mkdir venv project

The venv directory will contain our virtual environment and the project directory will contain the Django project.

~/tutorial$ virtualenv --prompt="(venv:tutorial)" ./venv/

New python executable in ./venv/bin/python
Installing setuptools............done.
Installing pip...............done.

~/tutorial$ source ./venv/bin/activate
(venv:tutorial)~/tutorial$

1.2.2 Creating a dependency file

Create a requirements.txt file in the tutorial directory with a single line (dependency) in it:

Django==1.6.7

In case you want to use the latest Django version (1.7 - at the time of writing the translation) - instead of the line Django==1.6.7 leave just Django - pip will install the latest version available.

1.2.3 Installing dependencies

And now we can use pip to install dependencies:

(venv:tutorial)~/tutorial$ pip install -U -r requirements.txt

Downloadping/unpacking Django==1.6.7 (from -r requirements.txt (line 1))
  Downloading Django-1.6.7.tar.gz (6.6MB): 6.6MB downloaded
  Running setup.py egg_info for package Django

    warning: no previously-included files matching ’__pycache__’ found under directory ’*’
    warning: no previously-included files matching ’*.py[co]’ found under directory ’*’
Installing collected packages: Django
  Running setup.py install for Django
    changing mode of build/scripts-2.7/django-admin.py from 644 to 755

    warning: no previously-included files matching ’__pycache__’ found under directory ’*’
    warning: no previously-included files matching ’*.py[co]’ found under directory ’*’
    changing mode of /home/nathan/p/edt/bin/django-admin.py to 755
Successfully installed Django
Cleaning up...

1.3 Starting a Django project

When a building is under construction, scaffolding is often used to support the structure until construction is complete. Scaffolding can be temporary or it can serve as part of the foundation of a building, but despite this, it represents some support when you first start work.

Django, like many web frameworks, presents scaffolding for your development. This happens by making decisions and providing a starting point for your code, allowing you to focus on the problem you're trying to solve rather than how to parse an HTTP request. Django provides scaffolding for both HTTP and filesystem handling.

HTTP scaffolding handles, for example, converting an HTTP request into a Python language object, and also provides tools for creating server-side responses more easily. File system scaffolding is different: it is a set of conventions for organizing your code. These conventions make it easier to add new engineers to the project, since the engineers (hypothetically) already understand how the code is organized. In Django terms, a project is an end product, and it combines one or more applications within it. In Django 1.4, the way in which projects and applications are placed on disk has been changed, making it easier to decouple and reuse applications across projects.

1.3.1 Project creation

Django installs the django-admin.py script on the system to handle scaffolding tasks. The startproject task is used to create the project files. We will define the name of the project and the name of the directory in which we want to host the project. Since, we are already in an isolated environment, we can just write:

We will move to ~/tutorial/project/ and from here on we will only work from this directory (by $ we mean ~/tutorial/project/$):

(venv:tutorial)~/tutorial/$ cd project

(venv:tutorial)$ django-admin.py startproject addressbook

The generated project has the following structure:

manage.py
./addressbook
init.py
settings.py
urls.py
wsgi.py

1.3.2. project scaffolding

  • manage.py - is a link to the django-admin script, but with environment variables already pre-installed pointing to your project, both to read settings from there and to manage it if needed;
  • settings.py - this is where your project settings are located. The file already contains some sensible settings, but no database is specified;
  • urls.py - contains the URLs for mapping views: we'll talk more about this shortly (in later chapters);
  • wsgi.py is the WSGI wrapper for your application. This file is used by the Django development server and possibly other containers such as mod_wsgi, uwsgi, etc. on the "battle" server.

1.3.3 Creating the application

(venv:tutorial)$ python ./manage.py startapp contacts

The created application has the following structure:

./contacts
    __init__.py
    models.py
    tests.py
    views.py
  • Starting with Django 1.4, applications are placed inside a package with the project. This is a great improvement, especially when it comes time to deploy the project on a "live" server;
  • models.py will contain the Django ORM models for your application;
  • views.py will contain the views code;
  • tests.py will contain the unit and integration tests you've written.
  • Django 1.7: admin.py will contain the model for the administrative interface.
  • Django 1.7: migrations/ contains the migrations files

Currently our ~/tutorial/ directory contains a dependencies file (requirements.txt), a virtual environment directory (venv/), one project (project/addressbook), one application (project/contacts) and has the following content:

~/tutorial/
	requirements.txt
	venv/
		...
	project/
		manage.py
		addressbook/
			__init__.py
			settings.py
			urls.py
			wsgi.py
		contacts/
			__init__.py
			models.py
			tests.py
			views.py

2. Using the Django model

2.1 Database Configuration

Django supports MySQL, PostgreSQL, SQLite3 and Oracle out of the box. SQLite3 is included in Python since version 2.5, so we will use it in our project (for simplicity). If you want to use MySQL for example, you will need to add mysql-python to your requirements.txt.

To use SQLite as your database, edit the DATABASES definition in the addressbook/settings.py file. The settings.py file contains the Django settings for our project. It has several settings that you must specify - such as DATABASES - as well as other, optional, settings. Django sets some of the settings itself when it generates the project. The documentation contains a full list of settings. In addition, you can add your own customizations if needed.

To use SQLite, we need to specify an engine (ENGINE) and a database name (NAME). SQLite interprets the database name as a filename for the database:

DATABASES = {
    'defaults': {
	    'ENGINE': 'django.db.backends.sqlite3,' # ’postgresql_psycopg2’, ’mysql’, ’sqlite3’ or ’oracle'.
		'NAME': os.path.join(BASE_DIR, 'address.db'),
		'USER': '',     # Not used with sqlite3.
		'PASSWORD': '', # Not used with sqlite3.
		'HOST': '',     # Set to empty string for localhost. Not used with sqlite3.
		'PORT': '',     # Set to empty string for default. Not used with sqlite3.
	}
}

Note that the database engine is specified by a string rather than a direct reference to a Python object. This is done for the reason that the settings file should be easy to import without causing any third-party effects. You should avoid adding import calls to this file.

You rarely have to import the settings file directly: Django imports it for you, and makes the settings available as django.conf.settings. You typically import settings from django.conf:

from django.conf import settings

2.2 Creating a model

Django models map (roughly speaking) database tables, and provide a place to encapsulate business logic. All models are descendants of the base Model class and contain definition fields. Let's create a simple Contacts model for our application in the contacts/models.py file:

from django.db import models

class Contact(models.Model):

    first_name = models.CharField(
        max_length=255,
    )
    last_name = models.CharField(
        max_length=255,
    )
	
    email = models.EmailField()

	def __str__(self):

	    return ' '.join([
            self.first_name,
            self.last_name,
        ])

Django provides a set of fields for mapping data types and various validation rules. For example, the EmailField we used is a mapping to a column with a CharField type, but adds data validation.

Once you've created the model, you need to augment your database with new tables. The Django syncdb command looks at the installed models and creates (if needed) tables for them:

Django will offer to create a superuser for the andmin which is enabled in this version by default. Take advantage of his suggestion.

Since Django 1.7, native support for migrations has been added to the framework and the syncdb command has been declared deprecated. So be so kind as to use the migrate command instead of syncdb.

(venv:tutorial)$ python ./manage.py syncdb

Creating tables ...
Creating table django_admin_log
Creating table auth_permission
Creating table auth_group_permissions
Creating table auth_group
Creating table auth_user_groups
Creating table auth_user_user_permissions
Creating table auth_user
Creating table django_content_type
Creating table django_session

You just installed Django's auth system, which means you don't have any superusers defined.
Would you like to create one now? (yes/no): yes
Username (leave blank to use 'bjakushka'):
Email address: 
Password:
Password (again):
Superuser created successfully.
Installing custom SQL ...
installing indexes ...
Installed 0 object(s) from 0 fixture(s)

(venv:tutorial)$

If you are using Django version 1.7 and above, the output is as follows:

(venv:tutorial)$ python ./manage.py migrate

Opperation to perform:
    Apply all migrations: admin, contenttypes, auth, sessions
Running migrations:
    Applying contenttypes.0001_initial... OK
    Applying auth.0001_initial... OK
    Applying admin.0001_initial... OK
    Applying sessions.0001_initial... OK

(venv:tutorial)$ 

However, our contact table is nowhere to be seen. The reason for this is that we still need to tell the project to use the application.

The INSTALLED_APPS setting contains a list of applications used in the project. This list contains strings that display Python packages. Django will import each of the specified packages and then watch the models module. Let's add our contacts application to the project settings (addressbook/settings.py):

INSTALLED_APPS = (
  'django.contrib.admin',
  'django.contrib.auth',
  'django.contrib.contenttypes',
  'django.contrib.sessions',
  'django.contrib.messages',
  'django.contrib.staticfiles',
  
  'contacts',
)

After that, run syncdb again.For Django version 1.7 and higher, you will first need to run the makemigrations command - to create migrations based on changes in models, and after that run the migrate command - to apply the created migrations. […]

(venv:tutorial)$ python ./manage.py syncdb

Creating tables ...
Creating table contacts_contact
Installing custom SQL ...
Installing indexes ...
Installed 0 object(s) from 0 fixture(s)

(venv:tutorial)$

Output for Django 1.7 and above:

(venv:tutorial)$ python ./manage.py makemigrations

Migrations for 'contacts':
    0001_initial.py:
        - Create model Contact

(venv:tutorial)$ python ./manage.py migrate

Opperation to perform:
    Apply all migrations: admin, contenttypes, sessions, auth, contacts
Running migrations:
    Applying contacts.0001_initial... OK

(venv:tutorial)$ 

Note that Django creates a table named contacts_contact: by default Dj ango names the tables using a combination of application name and model name. You can change this with the Meta model options.

2.3 Interact with the model

Now that the model is synchronized with the database we can interact with it using the online shell:

(venv:tutorial)$ python ./manage.py shell
Python 2.7.3 (default, Mar 14 2014, 11:57:14)
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from contacts.models import Contact
>>> Contact.objects.all()
[]
>>> Contact.objects.create(first_name='Nathan', last_name='Yergler')
<Contact: Nathan Yergler>
>>> Contact.objects.all()
[<Contact: Nathan Yergler>]
>>> nathan = Contact.objects.get(first_name='Nathan')
>>> nathan
<Contact: Nathan Yergler>
>>> print nathan
Nathan Yergler
>>> nathan.id
1

A few new things have been used here. First, the manage.py shell command runs a Python interactive shell for us with the correct paths for Django. If you try to run the Python interpreter and just import your application, an exception will be thrown because Django doesn't know what settings to use and can't map model instances to the database.

Secondly, the objects property of our model was used here. This is the model manager. So while one model instance is an analogy for a row in the database, the model manager is an analogy for a table. By default the model manager provides query functionality and can be customized. When we call all(), filter() or the manager itself, a QuerySet object is returned. QuerySet is an iterable object and loads data from the database as needed.

One last thing - above we used a field named id, which we didn't define in our model. Django adds this field as a primary key for the model, but only if you haven't defined which field will be the primary key yourself.

2.4 Writing tests

Our model has one method defined, str, so it's time to write tests. The str method will only be used in a few places, and may well be fully exposed to the end user. It's worth writing a test for this method as long as we understand how it works. Django created the tests.py file when it created the application, so we will add the first test to that file, application contacts.

from django.test import TestCase

from contacts.models import Contact

class ContactTests(TestCase):
    """Contact model tests."""
	
    def test_str(self):
	
        contact = Contact(first_name='John', last_name='Smith')
        self.assertEquals(
            str(contact),
            'John Smith',
        )

You can run tests for your application using the manage.py test command:

(venv:tutorial)$ python ./manage.py test

If you run this, you will see that about 420 tests have run. This is surprising because we have only written one. That's because Django runs tests for all installed applications by default. When you added an app to our project, you might have seen that there were a few Django embedded apps added by default. An additional 419 tests were taken from there.

In our case (using Django 1.6.7), the previous paragraph is a bit outdated: only one test will run, the one we created. The output of the command will be as shown below.

But if you want to run tests for a specific application, specify the application name in the command:

(venv:tutorial)$ python manage.py test contacts

Creating test database for alias ’default’...
.
----------------------------------------------------------------------
Ran 1 tests in 0.001s

OK
Destroying test database for alias ’default’...

(venv:tutorial)$

Another interesting thing to note before moving on is the first and last line of output: Creating test database and Destroying test database. Some tests need access to a database, and since we don't want to mix test data with "real" data (for various reasons, not the least of which is predefined), Django helpfully creates a test database for us before running the tests. Essentially, a new database is created, and then syncdb is run for it. If the test class is a descendant of the TestCase class (as we have), Django will also reset the data to defaults after running each test, so that changes to one of the tests will not affect the others.

2.5. Summary

  • The model defines the fields in the table, and contains the business logic.
  • The syncdb command creates tables in your database from models. In Django version 1.7 and later, instead of the syncdb command, you must first use the makemigrations command to create migrations, and then use the migrate command to make changes to the database.
  • The model manager allows you to operate on collections of instances: queries, creation, etc..
  • Write unit tests for the methods you have added to the model.
  • The test management command runs the unit tests for execution.

To test our as-yet-empty application, run the following command:

(venv:tutorial)$ python ./manage.py runserver 0.0.0.0:8080

This will run the built-in server, the functionality of which Django kindly provides us. The parameters after runserver specify the ip address and port to be listened to by the running server. In our case, the server will accept requests from all ip addresses when accessed on port 8080.

I am using a home server with internal IP 192.168.1.51 for development. So to see the result of the development server in my browser I go to http://192.168.1.51:8080/. You have to substitute the address of your server.

Shop

Learn programming in R: courses

$

Best Python online courses for 2022

$

Best laptop for Fortnite

$

Best laptop for Excel

$

Best laptop for Solidworks

$

Best laptop for Roblox

$

Best computer for crypto mining

$

Best laptop for Sims 4

$

Latest questions

NUMPYNUMPY

Common xlabel/ylabel for matplotlib subplots

12 answers

NUMPYNUMPY

How to specify multiple return types using type-hints

12 answers

NUMPYNUMPY

Why do I get "Pickle - EOFError: Ran out of input" reading an empty file?

12 answers

NUMPYNUMPY

Flake8: Ignore specific warning for entire file

12 answers

NUMPYNUMPY

glob exclude pattern

12 answers

NUMPYNUMPY

How to avoid HTTP error 429 (Too Many Requests) python

12 answers

NUMPYNUMPY

Python CSV error: line contains NULL byte

12 answers

NUMPYNUMPY

csv.Error: iterator should return strings, not bytes

12 answers

News


Wiki

Python | How to copy data from one Excel sheet to another

Common xlabel/ylabel for matplotlib subplots

Check if one list is a subset of another in Python

sin

How to specify multiple return types using type-hints

exp

Printing words vertically in Python

exp

Python Extract words from a given string

Cyclic redundancy check in Python

Finding mean, median, mode in Python without libraries

cos

Python add suffix / add prefix to strings in a list

Why do I get "Pickle - EOFError: Ran out of input" reading an empty file?

Python - Move item to the end of the list

Python - Print list vertically