There are a set of classes used to support the four built-in backends, plus a base class that can be used to write your own backend for un-supported databases or database drivers.
SQLCompiler
This is the bridge between high-level queries and the database backend.
It's very complex code.
All the magic happens in as_sql()
.
Query
Data structure and methods representing a database query. It's a tree-like data structure.
Two flavors:
Query
: normal ORM operationsRawQuery
: real, custom SQL queries, that returns something resembling what a normal Query
would expectAlso scary, complex code. It has to support infinite and arbitrary chaining of ORM methods (.filter()
, .distinct()
, etc.). Most of the code comes from this merging process.
You shouldn't often need to subclass Query
, but rather QuerySet
.
All your custom stuff gets access to the Django internals, like as_sql()
and the SQLCompiler
instance. Some ways to do custom stuff:
F objects
Q objects
django.db.models.Lookup
django.db.models.Transform
QuerySet
Wraps Query
in a nice API. It's lazy; doesn't touch the database until you force it to, by calling a method that doesn't return a QuerySet
.
Printing a QuerySet
, say, in the Django shell, it'll only show the first 21 objects... __repr__
adds a LIMIT 21
to the query, so that you don't accidentally run out of memory trying to build a string with a million results in it.
It's a container - it stores results to a cache that is only every populated once.
All operations except for iteration and length/existence checks perform a new query and return a new QuerySet. So you can't get a QuerySet
of several objects, update an attribute on one object, save it, and see the result in the same QuerySet
.
There's an update()
method on QuerySet
, but it doesn't call custom save()
methods or send pre_save
or post_save
signals.
The defer()
and only()
methods allow you get only the specified fields, but you get actual Model
instances. If you access other fields, then a new query is performed.
The values()
and values_list()
get you field values, not Model
instances. With flat=True
, values_list()
gets you a flat list of all values in the QuerySet
.
The select_related()
method solves the N+1 problem for ForeignKey
and OneToOneField
relations - just one SQL query, instead of one for the first model, and one for each of the N results.
The prefetch_related()
method solves it for ManyToManyField
s and GenericRelation
s - one query for model, relations resolved in python code.
Manager
The high-level interaface. The Model
that the Manager
is attached to is available in the Manager
as self.model
.
If a model has multiple Manager
s, the first one defined is the default (Model._default_manager
).
Should always have a Manager
on your model that can get alllll the objects.
Model
Representation of the data and the associated logic.
Uses python metaclasses, via django.db.models.base.ModelBase
. This is how the Meta
class property is created. It also creates all those extra methods and properties on the class, like Model.DoesNotExist
.
ModelBase
calls contribute_to_class()
on each thing in the attribute dictionary of the new class. For example, DateTimeField
has a contribute_to_class()
method that adds the get_next_by_<field-name>
method.
Field
Custom fields can pretend to be another field by setting internal type to something that exists already.
to_python()
converts from DB-level type to correct Python type.
value_to_string()
converts to string for serialization purposes.
Multiple other methods for preparing values for various kinds of DB-level usage - querying, storage, etc.
Multiple types available:
abstract = True
in model's Meta
declarationproxy = True
in Meta
Related to proxy models. Set managed = False
in Meta
. Wraps a database or view that you don't want Django to... manage.
Major components:
The low-level Form components:
value_from_datadict()
pulls out that widget's valuerender()
generates the HTMLMultiWidget
is a special class that wraps multiple other widgetsclean()
to validateto_python()
: convert from what came in on HTTP to the correct python typevalidate()
: Field's built-in validationrun_validators()
: custom validators added in the Field's validators
kwargValidationError
to_python
: when validation constraint is tightly tied to the data typevalidate
: when validation is intrinsic to the field (like email addresses)validators
: when the basic field does almost all the validation you need and it's simpler than writing a whole new fieldForm
with data will cause it to wrap its fields with instances with BoundField
.clean()
methodErrorDict
, ErrorList
as_p
or as_ul
_html_output()
methodIntrospects a Model
and creates a Form
out of it. Uses the model meta API to get list of fields, etc.
formfield()
method on each fieldformfield_callback()
method on the Formvalue_from_object()
method to get values for the given Model
instanceForms and Widgets support an inner class named Media
css
and js
, listing CSS JavaScript assets to include when rendering the form/widgetdjango.forms.widgets.MediaDefiningClass
Major components:
New in Django 1.8. Jinja2 is built-in now.
django.template.backends.base.BaseEngine
get_template()
render()
method that accepts a context dictionaryDoes the hard work of actually finding the template source.
load_template_source()
that accepts a template nameTemplate
objectBuilt to be simple; they didn't want a bunch of business logic in templates when Django was created. Not fast, but wasn't supposed to be.
Key classes:
Template
Lexer
Parser
Token
Node
and NodeList
Template lexing:
Lexer
with template source, then call tokenize()
Text
, Var
, Block
, and Comment
tokensTemplate parsing:
Lexer
is used to instantiate a Parser
, which then calls parse()
Node
or a NodeList
Behaves like a dictionary, but it's actually a stack of dictionaries
RenderContext
cycle
tag uses thisContext
The entry point for a Django project is django.core.handlers.WSGIHandler
, which implements a WSGI application. See PEP 333 and PEP 3333. It's the only supported implementation.
request_started
signalHttpRequest
get_response()
request.url_conf
!)HttpResponse
into output format for WSGIHandler
High-level: django.core.urls.RegexURLResolver
patterns: instances of RegexURLPattern
render()
method returns a ResolverMatch
objectlifecycle
RegexURLResolver
iterates over supplied patternseach include()
causes a nested RegexURLResolver
to be called at resolution time, but will be ignored if the prefix doesn't match
It's really important that your handler404
or handler500
, make it as bullet-proof as possible - really don't want to raise an Exception
Django never tries to catch SystemExit
.
HttpRequest
is technically handler-specific, but there's only one handler now
HttpResponse
comes in multiple flavors depending on status code
JSONResponse
for JSON datarequirements:
HttpRequest
in first positionHttpResponse
or raise an Exception
Inheritance diagram is complex, but usage is not. Complexity exists to let funtionality to be composed.
Basics
self.request
is the current HttpRequest
dispatch()
, based on the HTTP methodTemplateResponseMixin
somewhere in your inheritance chain if it's not alreadyas_view()
when putting it in a URLconfBig advantage of CBVs is composability/reusability of funtionality, and the ease with which they avoid the large argument lists functions would require to support the same customization.
The primary disadvantage is the proliferation of mixins and base classes needed to provide all the combinations of behaviors that Django's generic views support.
Pulls together lots of components, but not in the way you might expect. For example, it uses CBVs, but not the generic CBVs, because it was written before those were available.
You can subclass ModelAdmin
, which is a class that dispatches almost everything you can do in the admin app to view methods. The views are methods that have "_view()
" in their name.
Except for ChangeList
, which is possibly the scariest code outside of the ORM. It's survived two rewrites of the Admin.
Admin urls are also included as an attribute on the ModelAdmin
class. It's crazy.
AdminSite
represents the admin interface. Can have multiple instances in a single Django project, since you can namespace your URLs.
The Django Admin is not a good reference for well-structured Django applications.