Django - herougo/SoftwareEngineerKnowledgeRepository GitHub Wiki

Sources:

Notes:

  • App: An app is a web application that has a specific meaning in your project, like a home page, a contact form, or a members database.
  • Views: Django views are Python functions that takes http requests and returns http response, like HTML documents. Views are usually put in a file called views.py located on your app's folder.

Commands

django-admin startproject my_tennis_club  # create project
python manage.py migrate  # apply model migrations
py manage.py makemigrations members  # create migrations based on python code changes
python manage.py runserver  # run the project
python manage.py startapp members  # create members app
python manage.py test

File Structure (React App)

my_tennis_club
    manage.py
    members/
        migrations/
            __init__.py
        __init__.py
        admin.py
        apps.py
        models.py
        tests.py
        urls.py  # created by user
        views.py
    frontend
        src/  # created by user, contains javascript
        templates/ # created by user, contains index.html
        static  # created by user, contains css
        ...
    my_tennis_club/
        __init__.py
        asgi.py
        settings.py
        urls.py
        wsgi.py

File Explanations

manage.py: A command-line utility that lets you interact with this Django project in various ways.

my_tennis_club/

  1. urls.py: The URL declarations for this Django project; a “table of contents” of your Django-powered site
  2. mysite/asgi.py: An entry-point for ASGI-compatible web servers to serve your project. See How to deploy with ASGI for more details.
  3. mysite/wsgi.py: An entry-point for WSGI-compatible web servers to serve your project. See How to deploy with WSGI for more details.
  4. settings.py: settings file (BIG)

members/

  1. apps.py: contains the config for the application; name corresponds to the Full Python path to the application (e.g. 'music_project.frontend')
  2. admin.py: register models so you can use admin dashboard to modify the data fields

Add an App and View

my_tennis_club/members/urls.py:

from django.urls import path
from . import views

urlpatterns = [
    path('members/', views.members, name='members'),
]

my_tennis_club/my_tennis_club/urls.py:

from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    path('', include('members.urls')),
    path('admin/', admin.site.urls),
]

my_tennis_club/members/templates/myfirst.html:

...

my_tennis_club/members/views.py:

from django.http import HttpResponse
from django.template import loader

def members(request):
  template = loader.get_template('myfirst.html')
  return HttpResponse(template.render())

my_tennis_club/my_tennis_club/settings.py:

INSTALLED_APPS = [
    ...
    'members'
]

Add API Get Endpoint

my_tennis_club/urls.py

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include('api.urls'))
]

api/urls.py

from django.urls import path
from .views import UserInRoom

urlpatterns = [
    path('user-in-room', UserInRoom.as_view())
]

api/views.py

from rest_framework.views import APIView
from rest_framework import status
from django.http import JsonResponse

class UserInRoom(APIView):
    def get(self, request, format=None):
        if not self.request.session.exists(self.request.session.session_key):
            self.request.session.create()

        data = {
            'code': self.request.session.get('room_code')
        }
        return JsonResponse(data, status=status.HTTP_200_OK)

Add Tests

Use django.test.TestCase, a subclass of unittest.TestCase. Tests go in the tests folder in the appropriate application folder (i.e. my_tennis_club/members/tests).

from django.test import TestCase

class AnimalTestCase(TestCase):
    def setUp(self):
        ...

    def test_animals_can_speak(self):
        ...

Article: Django Best Practices from DoorDash

source: https://medium.com/@DoorDash/tips-for-building-high-quality-django-apps-at-scale-a5a25917b2b5

  1. Don't be afraid of having one big app: If you don’t really understand the point of apps, ignore them and stick with a single app for your backend. You can still organize a growing codebase without using separate apps.
  2. If you do want to create separate applications, you will want to be very intentional about how you define them: Be very explicit about and minimize any dependencies between different apps. (If you are planning to migrate to microservices down the line, I can imagine that “apps” might be a useful construct to define precursors to a future microservice).
  3. Organize your apps inside a package: For example, twitter/app1, twitter/app2, etc. This helps with namespace conflicts.
  4. Explicitly name your DB tables
class Foo(Model):
    class Meta:
        db_table = 'foo'
  1. Explicitly create your many-to-many tables: That way, you can access them easily.
  2. Avoid GenericForeignKey: ???
  3. Keep migrations safe: For example, make sure you have a stable deploy which doesn't reference a column before deploying a migration which deletes the column.
  4. Squash your migrations: Many migrations can be time-consuming when running tests, etc.
  5. Make sure you handle conflicting migration files: i.e. 0001_a, 0002_b, 0003_c, 0003_d
  6. Avoid fat models: Avoid putting the bulk of your business logic inside model methods.
  7. Be careful with (or even avoid) signals: Putting too much logic in signals can make program flow difficult to trace and read. Passing custom arguments or information through a signal is not really possible.
  8. Avoid using the ORM as the main interface to your data: Suppose you want to create a ModelB every time ModelA is created. You can use signals or overload the model.save. A better solution for this is to establish a pattern in which you route all important database operations (create/update/delete) through some kind of simple interface that wraps the ORM layer. This gives you clean entry points to add additional logic before or after database events.
  9. Don't cache Django models: If you migrate your schema (add/change/delete fields from your model), Django actually does not handle this very gracefully when dealing with cached instances. If Django tries to read a model instance that was written to the cache from an earlier version of the schema, it will pretty much die. Under the hood, it’s deserializing a pickled object from the cache backend, but that object will be incompatible with the latest code. This is more of an unfortunate Django implementation detail than anything else.