Two Scoops of Django 3.x: Best Practices for the Django Web Framework

Just bought this book from feldroy.com.
Two-Scoops-of-Django
GitHub for Two-Scoop-of-Django-3.x

Key Points:

  • Keep It Simple, Stupid
  • Fat Models, Utility Modules, Thin Views, Stupid Templates
  • Follow the PEP8;
    • Use 4 spaces per indentation level.
    • Separate top-level function and class definitions with two blank lines.
    • Method definitions inside a class are separated by a single blank line.
  • Limit of text per line is 79 characters (for private projects, it is relaxed to 99 characters).
  • The imports should be grouped in the following order:
    • Standard library imports
    • Core Django imports
    • Related third-party imports
    • Local application or library-specific imports
  • Using aliases to avoid Python Module collisions
    from django.db.models import CharField as ModelCharField
    from django.forms import CharField as FormCharField
  • Use underscores in URL Pattern Names rather than dashes
    patterns = [
        path(route='add/',
            view=views.add_topping,
            name='toppings:add_topping'),
        ]

    Dashes in actual URLs are fine (e.g. route=‘add-topping/’).
  • Using static/ for the (non-user-generated) static media directory.
  • A Django project is a web application powered by the Django web framework.
    Django apps are small libraries designed to represent a single aspect of a project. A Django project is made up of many Django apps. Some of those apps are internal to the project and will never be reused; others are third-party Django packages.
    INSTALLED_APPS is the list of Django apps used by a given project available in its INSTALLED_APPS setting.
    Third-party Django packages are simply reusable Django apps that have been packaged with the Python packaging tools.
  • Each app should be tightly focused on its task.
    James Bennett: “The art of creating and maintaining a good Django app is that it should follow the truncated Unix philosophy according to Douglas McIlroy: ‘Write programs that do one thing and do it well.’
  • Name the Django Apps
    • Keep to single word names, like flavors, animals, blog, and finances.
    • The app’s name should be a plural version of the app’s main model. There are many good exceptions, blog is the example.
    • Consider naming the app according to the URLs to be appeared. For example, http://www.example.com/weblog/, then consider naming your app weblog rather than blog, posts, or blogposts, even if the main model is Post.
    • Use PEP8-compliant, importable Python package names: short, all-lowercase names without numbers, dashes, periods, spaces, or special characters. Using underscores to separate words, although the use of underscores is discouraged.
  • Try to keep your apps small.
  • Sample Project Layout (any module ending with a slash (‘/’) represents a Python package)
    yourprojname_reporoot #This is the <repository_root>.
    |--config/
    |  |--settings/
    |  |--__init__.py
    |  |--asgi.py
    |  |--urls.py
    |  |--wsgi.py
    |--docs/
    |--yourprojname_project/ #The <django_project_root> of the project.
    |  |--media/ #development only!
    |  |--apps1/
    |  |--apps2/
    |  |--apps3/
    |  |--static/ #Non-user-generated static media assets (CSS, JavaScript, and images).
    |  |--templates/ #Your site-wide Django templates
    |--.gitignore
    |--Makefile
    |--README.md
    |--manage.py
    |--requirements.txt #Current dependencies ($ pip freeze > requirements.txt)
  • When coding in Django, the classic example is the process of creating user objects and related data cross multiple models and apps.
  • Service layer example

    apps1/
    |--api/
    |--models.py
    |--services.py #Service layer location for business logic
    |--selectors.py #Service layer location for queries
    |--tests/
  • Each Django app should be tightly-focused on its own task and possess a simple, easy-to-remember name. If an app seems too complex, it should be broken up into smaller apps.
  • Settings module is loaded when your server starts up.
  • Instead of having one settings.py file, you have settings/ directory containing your settings files.
    (Each settings module should have its own corresponding requirements file.)
    settings/
    |--__init__.py
    |--base.py #Settings common to all instances of the project.
    |--local.py #Settings file when working on the project locally.
    |--staging.py #Staging version for running a semi-private version of the site on a production server.
    |--test.py #Settings for running tests including test runners, in-memory database definitions, and log settings.
    |--production.py #Settings file used by your live production server(s). Sometimes called prod.py.

    To start Python interactive interpreter with Django, using your settings/local.py settings file:
    python manage.py shell --settings=config.settings.local

    To run the local development server with your settings/local.py settings file:
    python manage.py runserver --settings=config.settings.local
  • Never hardcoding file paths in Django settings files.
  • The golden rule of Web application security is to never trust data from untrusted sources.
  • Everything except for passwords and API keys ought to be tracked in version control.
  • If there are 20+ models in a single app, break it down into smaller apps, as it probably means the app is doing too much.
    In practice, no more than five to ten models per app.
  • Simple rules of thumb for knowing which type of inheritance to use and when:
    • If the overlap between models is minimal, there might not be needed for model inheritance.
      Just add the fields to both models.
    • If there is enough overlap between models, the code should be refactored so that
      the common fields are in an abstract base model.
    • Proxy models are an occasionally-useful convenient feature, but they’re very different from
      the other two model inheritance styles.
    • Avoid multi-table inheritance. Instead of multi-table inheritance, use explicit OneToOneFields and ForeignKeys
      between models so you can control when joins are traversed.
  • It’s very common in Django projects to include a created and modified timestamp field on all models.

To be continued…


Further readings:
The Twelve-Factor App
PEP8 — Style Guide for Python Code

Leave a Reply

Your email address will not be published. Required fields are marked *