Some recommendations for Python's Django framework deployment

  • 2020-05-07 19:58:39
  • OfStack

"What is the best layout for Django applications, configuration files, and various other related directories?"

We've always had friends ask us this question, so I wanted to take a moment and write down exactly how we think about it, so we can easily get other people to refer to this document. Note that this is based on version 1.7.1 of Django, but can be easily applied to any version after version 1.4 of Django.

Although when Django 1.4 was released, it included an improved project layout (which took a long time), this article has some better Suggestions for optimizing the project layout.
Why is a better layout than

The project layout we recommend here has several advantages, namely:

      lets you get, repackage, and reuse a single Django application for other projects. This is often ambiguous, as you are building an application whether or not you want to reuse it. Building the application in the way you want to reuse it from 1 will make it easier to slice it.       encourages the design of reusable applications. Detailed Settings for the       environment. In a single 1 overall profile, if DEBUG==True makes little sense. This makes it easy to see which configurations are Shared and which are overridden on a per-environment basis. Specific installation requirements for the       environment (PIP requirements). If necessary, project-level templates and static files can override application-level defaults.       small, more specific test files are easier to read and understand.

Suppose you have two applications, blog and users, and two development environments, dev and prod. Your project layout should look like this:
 


myproject/
    manage.py
    myproject/
        __init__.py
        urls.py
        wsgi.py
        settings/
            __init__.py
            base.py
            dev.py
            prod.py
    blog/
        __init__.py
        models.py
        managers.py
        views.py
        urls.py
        templates/
            blog/
                base.html
                list.html
                detail.html
        static/
           ...
        tests/
            __init__.py
            test_models.py
            test_managers.py
            test_views.py
    users/
        __init__.py
        models.py
        views.py
        urls.py
        templates/
            users/
                base.html
                list.html
                detail.html
        static/
            ...
        tests/
            __init__.py
            test_models.py
            test_views.py
     static/
         css/
             ...
         js/
             ...
     templates/
         base.html
         index.html
     requirements/
         base.txt
         dev.txt
         test.txt
         prod.txt

The rest of this article explains how to migrate your project to this layout and why it is a good one.
's current default layout is

We'll call the sample project foo, which I know is a very creative name. So let's say that here, we're going to start foo.com. But when we want to map our project name to the final domain name, the project will exist in a way that doesn't require any meaning.

If you start the project with the django-admin.py startproject foo command, you will get a directory structure like this:
 


foo/
  manage.py
  foo/
    __init__.py
    settings.py
    urls.py
    wsgi.py

This layout is a good starting point. We have a top-level directory, foo, which contains the manage.py files and the project directory, foo/foo/. In this directory, you can look up source control systems (such as Git).

You should think of the subdirectory foo/foo/ as the project. All of the files here are either a single Django application or a set of documents related to the project.
modifies the configuration of

The task here is to fix the bad configuration file. I show this layout to new users, and I'm often surprised how these people know it's even possible. In fact, when everyone knows that these configurations are just Python code, they don't think of them as Python code either.

So let's improve the configuration. For the oo project, there will be four development environments: dev, stage, jenkins, and production. Give each development environment one of its own configuration files. What to do in this process is:

      creates a new configuration directory under foo/foo/ and creates an empty s/s/s file.py.
      foo/foo/settings py mobile and named foo foo/settings/base py.
      creates separate dev.py, stage.py, jenkins.py and production.py files in the foo/foo/settings/ directory. The specific configuration files for these four environments should contain the following:
     


  from base import *

Why is this important? You want to set a DEBUG = True for local development, but it's easy to accidentally pushed this to the production code, so you need to open the foo/foo settings/production py file, after the initial import base plus DEBUG = False. Now, your production environment is safe for such silly mistakes.

What else can be customized? Obviously you can configure staging, jenkins, production and other development environments for different databases or even different hosts. Then adjust those configurations in each environment configuration file.
USES these to configure

No matter which method you normally use, using these configurations is easy. To use the operating system environment, you simply do:
 


export DJANGO_SETTINGS_MODULE= " foo.settings.jenkins " 

Now you are using the jenkins configuration.

Or maybe you prefer them as command-line options like:
 


./manage.py migrate  - settings=foo.settings.production

Similarly, if you use gunicorn, the command is as follows:
 


gunicorn -w 4 -b 127.0.0.1:8001  - settings=foo.settings.dev

What other customizable configurations are available for ?

Another practical recommendation is to change some of the default collection configurations from tuples to lists. For example, INSTALLED_APPS, from:
 


INSTALLED_APPS = ( 
...
 ) 

To:
 


INSTALLED_APPS = [
   ... 
]

Now, based on the specific configuration file each environment, we can more easily in foo/settings/base py file add and remove applications. For example, you might only want to install the Django debugging toolbar in the dev environment and not in any other environment.

This technique is also useful for TEMPLATE_DIRS and MIDDLEWARE_CLASSES configurations.

Another technique we often use is to divide the application into two lists, one that is a prerequisite for the project and one that is used for the actual project. As shown below:
 


PREREQ_APPS = [
   ' django.contrib.auth',
   ' django.contrib.contenttypes',
   ... 
   ' debug_toolbar',
   ' imagekit',
   ' haystack',
]
 
PROJECT_APPS = [
   ' homepage',
   ' users',
   ' blog',
]
 
INSTALLED_APPS = PREREQ_APPS + PROJECT_APPS

Why is this useful? First, it helps to distinguish between Django core applications, third-party applications, and specific applications for your own internal projects. For things like testing and code coverage, a list of PROJECT_APPS that describes your particular application is often useful. You have a list of applications that you can write, so you can easily and automatically ensure that their tests run, that the recorded test coverage only includes them and does not include any third party applications, and that there is no need to maintain this list in two different places.
Modification of requires

Most projects have an requirements.txt file, which is installed with the following command:
 


pip install -r requirements.txt

This is sufficient for simple small projects, but one of the lesser-known features of the requirements.txt file is that you can use the -r parameter to include other files. Therefore, for all common installation requirements, we can create one base.txt file; Then, if we need to be able to run the test, we can create a specific requirements/ test.txt file that contains the following:
 

-r base.txt
pytest==2.5.2
coverage==3.7.1

I admit this isn't a huge benefit, but it does help distinguish between what is required for each development environment. At the same time, for its performance, it does not install 1 heap of things that are not used in actual production, to reduce the installation time of pip in the production environment.
test file

Why would we split a large test file? One of the main reasons for this is that if you write enough tests for each application in an tests.py file, the file will eventually become bloated. This code is not very readable, and you have to spend a lot of time scrolling through the code in the editor.

Small files also allow you to avoid collisions when merging code when working with other developers. The little file is your friend.
URLs

For small projects, put all the URL definitions in the foo/ urls.py file so that they are in the same place. However, if your goal is clear and reusable code, you'd better define url for each application and include them in your main project. You should not do the following:
 


urlpatterns = patterns( ' ',
  url(r'^$', HomePageView.as_view(), name= ' home'),
  url(r'^blog/$', BlogList.as_view(), name= ' blog_list'),
  url(r'^blog/(?P<pk>d+)/$', BlogDetail.as_view(), name= ' blog_detail'),
   ... 
  url(r'^user/list/$', UserList.as_view(), name= ' user_list'),
  url(r'^user/(?P<username>w+)/$', UserDetail.as_view(), name= ' user_detail'),
)

Here's what you should do:
 


  from base import *
0

templates and static resources

Each application has an templates/ and static/ directories, which allows one application to be basically reused to other projects.

For one cool feature, we all get the default template provided by the application and any related static resources, such as special Javascript, in one package.

However, it also allows us to override the template under each project home directory foo/templates/. We by adding 1 templates/blog/detail html template overwrite the default blog templates/blog/detail html template.
multiplexes Django to apply

Suppose you've been using this layout for a while, and one day you'll realize that your new project needs an blog application. The application that comes out of your foo project will be perfect. So you copy and paste documents... Error! Now you have two copies of the application. Assuming you remember, the Bug fixes and new features added in one copy require manual migration between projects.

Instead, create a new directory for your blog and put the contents of the foo/blog/ directory into it. Also, adjust the existing foo project and your new project for installation.

They can still keep track of the two different versions of the application, if needed, or keep updating, and get all the bug fixes and new features they are evolving. You can still override templates and static resources as required on a per-project basis, so there's really no problem with that.


Related articles: