Skip to content

Instantly share code, notes, and snippets.

@systemsoverload
Created August 10, 2016 19:39
Show Gist options
  • Save systemsoverload/4513f3b448b9a16d111e99d11b681aab to your computer and use it in GitHub Desktop.
Save systemsoverload/4513f3b448b9a16d111e99d11b681aab to your computer and use it in GitHub Desktop.

% Django % TJ Kells % 05-26-2016

What is it?

Django (/ˈdʒæŋɡoʊ/ jang-goh) is a free and open source web application framework, written in Python. A web framework is a set of components that helps you to develop websites faster and easier.

The components

  • Object-Relational Mapper
  • URLs
  • Views
  • Templates
  • Forms
  • Authentication
  • Admin
  • Security

ORM

Models

  • Models serve as:
    • Schema definitions
    • Containers for meta properties (table name, indexes, constraints, etc)
  • Their Methods define attributes/access patterns of instances of records (row-level)
  • Live in /models.py
    • OR in a package /models/model_name.py (as long as app_label is defined in Meta)

Model

class Person(models.Model):
    AMERICAN, TEXAN = ['USA', 'TX']
    NATIONALITY = ((AMERICAN, 'American'),
                   (TEXAN, 'Texan'))
    name = models.CharField(max_length=200)
    nationality = models.CharField(max_length=2,
                                   choices=NATIONALITY,
                                   default=AMERICAN)
    @property
    def greeting(self):
        if self.nationality == TEXAN:
            return "Howdy, Ya'll!"
        else:
            return "Hi There"

Managers

  • Factories in charge of returning a QuerySet for a given model - Typically through descriptor named objects (just convention though)
  • Define attributes/access patterns of the record type as a whole (table-level)
  • If you find yourself writing helper methods to re-use a set of filters 99% of the time they belong here
  • If you find yourself writing a classmethod on a Model, that logic probably belongs here

Manager

class AtlassianManager():
    def create_texan(self, name):
        self.model(name=name, nationality='TX').save()

    def nationality_count(self, nationality):
        return self.filter(nationality=nationality).count()

    def get_query_set(self):
        return (super(AtlassianManager, self)
                .get_query_set()
                .select_related('team'))

class Atlassian(Person)
    team = models.ForeignKey('auth.Team')

    objects = AtlassianManager()

URLs and Views

URLs

  • A collection of regular expressions that bind callbacks to routes
  • Named capturing groups in the regex get converted into kwargs passed to the bound callback
  • Un-named capturing groups get passed as positional args
  • The urlpatterns are given names to prevent hard-coding URLs - always use reverse.

URLs (cont.)

  • Some magical conventions
    • Only a single URLs file is registered with django
    • It must expose a module-level variable called urlpatterns, which is an iterable of url objects
      • In <1.8 this is encapsulated into a patterns object
    • Convention for chaining imports is using include to compile all installed-apps urls in your main urls.py
  • It can be very slow.

urlpatterns

# urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
    url(r'^person/$', views.person_list, name='person-list')
]
# views.py
def person_list(request):
    return render(request, 'auth/person_list.html',
                  {'people': Person.objects.all()})

Views

  • The callback function bound to a particular URL
  • In MVC parlance, the "Controller"
  • In charge of generating the HttpResponse which also includes template compilation
    • Typically combined into a single step with django.shortcuts.render

Class-Based Views

  • Provides organization of code related to specific HTTP methods (methods vs branching)
  • Allows code reuse through inheritance and mixins rather than shared disparate helper methods
    • Can override class attributes through the calling urls.py
  • If you find yourself writing a view with many logical branches/helper methods, consider a CBV

CBV

from django.views.generic import View

# dispatch -> method_not_allowed/self.method ->
class PersonView(View):
    model = Person
    template = 'auth/person_list.html'

    def get(self, request):
        return render(request, self.template,
                      {'people': self.model.objects.all()})

    def post(self, request):
        self.model.objects.create(**request.POST)
        return render(request, self.template,
                      {'created': True,
                       'people': self.model.objects.all()})

Class attribute overloading

urlpatterns = [
  url(r'^person/$', PersonView.as_view(),
      name='person-list'),
  url(r'^atlassian/$',
      PersonView.as_view(model=Atlassian,
                         template='auth/atlassian.html'),
      name='atlassian-list'),
]

Django is Opinionated

(and so am I)

Thick models, thin views, dumb templates

  • Models should contain the MAJORITY of the code required to do ANYTHING to your data.
  • Rule of thumb: if you can't do it from the django shell, its probably defined in the wrong spot
  • Any models.py ~> 500 LOC should be split into a package.
    • This package's __init__.py should handle making the imports seamless
  • ALL CUSTOM SQL SHOULD LIVE IN MANAGERS/QUERYSETS

AppConfigs

  • New in django 1.7
  • Provided a place for meta-level data about any particular app to live
  • Also provided the ONLY reliable hook for post-app-ready
  • Makes a great place for in-code caching of configurable things (ie - serializers, encodes, etc)
    • Currently used for collecting BBQL filter mappings and registered_facts

Inheritance is your friend.

  • Sane bases make for thinner child classes, decorators make
  • Managers should be composable. (ie - A soft-delete-able, optionally published, blog post's manager should be composed of a SoftDeleteManager and a PublishedManager)

Potpourri

  • Model choices should be defined as a tuple of tuples containing references to class attributes
  • ContentTypes are our friends (real DBA can actually partition things!)
    • ContentType table is maintained by Django when a new model is registered or an old model removed
    • Allows for generic relatable objects which require less boilerplate to create
      • Already being used for Like in bitbucket cloud
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment