% Django % TJ Kells % 05-26-2016
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.
- Object-Relational Mapper
- URLs
- Views
- Templates
- Forms
- Authentication
- Admin
- Security
- 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 inMeta
)
- OR in a package /models/model_name.py (as long as
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"
- 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
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()
- 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
.
- 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 ofurl
objects- In <1.8 this is encapsulated into a
patterns
object
- In <1.8 this is encapsulated into a
- Convention for chaining imports is using
include
to compile all installed-apps urls in your mainurls.py
- It can be very slow.
# 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()})
- 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
- Typically combined into a single step with
- 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
- Can override class attributes through the calling
- If you find yourself writing a view with many logical branches/helper methods, consider a 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()})
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'),
]
- 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
- This package's
- ALL CUSTOM SQL SHOULD LIVE IN MANAGERS/QUERYSETS
- 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
- 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)
- 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
- Already being used for