Skip to main content

Django Projects

Project Setup​

  • RULE #1: always start a new project with a fresh new installation of Django with the latest framework and libraries. If the project is similar to a previous one, still do not clone it! In this second scenario, after creating a new project with everything up to date you can copy and paste single functionalities if needed; it would be better to rethink everything. In this way, you can find useless dependencies, dead code, code smells, and pitfalls..

  • RULE #2: if your last Django project was a v2 and now you are starting a v3, first of all read again the Django guides https://docs.djangoproject.com/en/3.2/ . Django is very slow to add notable changes, as well as Python itself. But doing things like 2 years ago only because they still work is a bad idea.

  • RULE #3: if you planning to use MongoDB, Django is not the right solution: consider useing Node or Rails instead.

  • RULE #4: do not start a project that depends from Python 2.x runtime!

  • RULE #5: setup a different setting file for each enviroment in conjunction with django-environ: https://djangostars.com/blog/configuring-django-settings-best-practices/

  • Start thinking from day 1 if the Django project will be only an API and/or will use some frontend framework (React, Vue).

Packages and libraries​

Django is really a batteries included framework, so everything you need is provided by the framework itself.

Below the list of must to have libraries:

If you need background jobs, Celery is the go to solution https://docs.celeryproject.org/en/stable/django/first-steps-with-django.html Also, add Flower to monitor the status of the jobs: https://docs.celeryproject.org/en/stable/userguide/monitoring.html#flower-real-time-celery-web-monitor

Other packages best practices:

  • Do not add packages that are not actively maintained or with a few stars
  • Do not add unknown packages just to reinvent a little wheel: see what they do and create a library.py inside the specific application.
  • Add the minimum number of packages to your project: more dependencies mean more issues in the future if you have to upgrade the project
  • Add all dependencies inside the requirements.txt file!
  • Take a look at https://djangopackages.org/ to check trends and choose the specific library for you needs

Django views? No API only!​

Django templating system and views are very cumbersome sometime, the best way to work with Django is to skip at all the templating layer and use this framework only to build APIs and work with the Django admin.

Django REST framework is a powerful and flexible toolkit for building Web API: https://www.django-rest-framework.org/

But the power of Django is not only in the REST framework: if you plan to work with GraphQL APIs, graphene https://docs.graphene-python.org/en/latest/ and graphene-django https://docs.graphene-python.org/projects/django/en/latest/ are definitely the best choice so far.

Service Objects?​

Django has never supported Service Objects because most of their functionalities are done by Forms and Views together.

So there is not a de facto library to handle services (here's an example: https://github.com/mixxorz/django-service-objects that basically extends the django Form to shape it as a service).

Due to the nature of Django itself, it's best to avoid adding a service layer because it's just a sort of duplication of a Form.

Class Based vs Function Based Views​

Initially, Django started with the Function Based Views but later Django added the concept of class-based views to avoid the redundancy of code in the boilerplate.

1. Function-Based Views​

https://docs.djangoproject.com/en/3.2/topics/http/views/

Function-based views are good for beginners. It is very easy to understand in comparison to class-based views. Initially when you want to focus on core fundamentals, using the function-based views gives the advantage to understand it.

Pros:

  • Easy to read, understand and implement.
  • Explicit code flow
  • Straightforward usage of decorators.
  • Good for the specialized functionality.

Cons:

  • Code redundancy and hard to extend
  • Conditional branching will be used to handle HTTP methods.

2. Class-Based Views​

https://docs.djangoproject.com/en/3.2/topics/class-based-views/intro/

Class-based views are the alternatives of function-based views. It is implemented in the projects as Python objects instead of functions. Class-based views don’t replace function-based views, but they do have certain advantages over function-based views. Class-based views take care of basic functionalities such as deleting an item or add an item.

Pros:

  • The most significant advantage of the class-based view is inheritance. In the class-based view, you can inherit another class, and it can be modified for the different use cases.
  • It helps you in following the DRY principle. You won’t have to write the same code over and over in your boilerplate. Code reusability is possible in class-based views.
  • You can extend class-based views, and you can add more functionalities using Mixins.
  • Another advantage of using a class-based view is code structuring. In class-based views, you can use different class instance methods (instead of conditional branching statements inside function-based views) to generate different HTTP requests.
  • Built-in generic class-based views.

Cons:

  • Complex to implement and harder to read
  • Implicit code flow.
  • Extra import or method override required in view decorators.
  • Lot of hidden magic

3. Built-in class-based generic views​

https://docs.djangoproject.com/en/3.2/topics/class-based-views/generic-display/

A super specialized super set of class based view, these generic views are useful only if you are working on basic CRUD operations. Otherwise forget about them.

Testing​

  • RULE #1: Setup automated tests ONLY if you are sure that for all application lifetime you'll maintain them. Otherwise it's time wasted.

  • RULE #2: Setup automated tests ONLY if you have budget and time to keep them in sync: a good codebase costs 30% of project time.

Once you are really sure you want to add automated tests, do not use external libraries and use the Django built in test suite (based on unittest): https://docs.djangoproject.com/en/3.2/topics/testing/

If you really don't like the built in library, use pytest: https://docs.pytest.org/en/6.2.x/

Use factories to genrate dummy data into the database: https://github.com/FactoryBoy/factory_boy

WHAT TO TEST

  • RULEΒ #1: Do not test everything, don't lose time testing first (unless you are a really fun). Test what means to be tested, like:

    • difficult calculations
    • complex features
    • views and forms (if they have business logic inside)
  • RULE #2: Avoid mocking and stubbing requests because your tests will probably pass also if the external APIs for example has changed their response.

  • RULE #3: Avoid mocking database: create less tests but save data into database: remember to cleanup everything at the end of each test.

  • RULE #4: As per #3, do not generate dependent tests: they should be run randomly and they must pass all the time.

  • RULE #5: forget about code coverage: test what really means to be tested, sometimes fixing the code is less expensive than creating huge test suites

Linting & formatting​

Although it's not the official python linter, setup your editor with Pylint: https://www.pylint.org/ Pylint is a python linter which checks the source code and also acts as a bug and quality checker. It has more verification checks and options than just pycodestyle (formerly PEP8). Also, it's already integrated with VSCode.

To format the code, use Black: https://black.readthedocs.io/en/latest/

Databases​

Postgres should be the first choice for a Django project; if you are planning to use MongoDB, consider moving to Node or Rails.

If you use postgres, enable uuid extension:

CREATE EXTENSION "uuid-ossp";

And remember to define your model's primary keys in this way:

id = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True)

In this way you avoid guessable routes like ```/posts/1/edit````

This doesn't mean you are exempted to check authorizations in the view!

Django admin​

The django admin https://docs.djangoproject.com/en/3.2/ref/contrib/admin/ is a really powerful interface to handle and modify data on the fly.

Consider using it as "admin backoffice", only to help developers and technical teammates to fix and check things.

Do not let client to because customizing the admin panel to fit client's requests can be harmful in a long term.

Useful tips​

TDB