Skip to content

Instantly share code, notes, and snippets.

@garrypolley
Last active December 4, 2022 14:06
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save garrypolley/5486165 to your computer and use it in GitHub Desktop.
Save garrypolley/5486165 to your computer and use it in GitHub Desktop.
Django ORM explanation

Notes on Django ORM

What's the ORM

  • Object Relation Mapper
  • Abstraction Layer to DB
  • Makes DB relate like OOP
  • Learn a lot more from Django-in-depth

What can the ORM do

  • Nearly anything SQL can with tables and views
  • Allows for a concise way to query your database
  • Gives an easy way to help validate data
  • Supported Multiple DBs
    • Oracle
    • PostgreSQL
    • MySQL
    • SQLite
  • Third Party DBs
  • Intelligent DB Routing

How does it work

Give an overview of each piece

  • Model

    • OOP Class
    • Table or View
    • Fields map to columns
    • Define data relationships (don't think in terms of tables)
    • Define how data is retrieved
    • Can pass save() a using argument to specify DB
  • Manager

    • First place to generate query
    • Connects Model and queryset
    • Created by default on all models as objects
    • First defined manager is the _default_manager (you can have multiple managers)
  • Queryset

    • Builds Query
    • Contains model instances (after query is ran)
    • Like a Python list
    • Lazy loads all query calls
    • Does sensible caching
    • Slicing always creates a query
    • Use .iterator() for large data sets
    • Use .exists() for boolean checks
    • Can specify the DB to hit at this level
    • Programtic API to create DB Queries
  • Query

    • Connects Queryset to SQLCompiler
    • Most high level calls to Queryset become .add_filter on the Query class instance
    • Has many Classes to create where/insert/form etc. query clauses
  • SQLCompiler

    • Has classes for each piece of a query for ease modification and custom queries (select, from, where, order_by)
    • Creates the actual SQL
  • Backend

    • DB Abstraction
    • RDBMS default supported
    • Contains the driver or calls to db driver (e.g. cx_Oracle)
    • Can be modified to help generate custom SQL
    • Can be modified to help do connection pooling

Fields

  • get_prep_value -- returns the value to send to the DB (get_db_prep_value does backend specific logic)
  • to_python -- converts DB value to python value

Extra bits

  • Options Class

    • Is the super to the Meta class
    • Has lots of internal logic to ensure specific behavior of Meta
    • Contains the field information and lot of other info for your model at ._meta
  • new

    • This does the magic sauce when creating models
    • Ensures the Meta class is defined correctly
    • Makes dynamic model generation very difficult (don't do it if you can help it)
  • init

    • Don't override this
  • Validation

    • Done at field or instance
    • Can be combined with forms for lots of power
    • clean() method will validate all fields and any custom combo validation
    • FIELD_clean method for each field that needs unique validation per model
  • Inheritance

    • Abstract, acts like a regular OOP class
    • Concrete, acts like OOP class but adds an implicit one-to-one relation
    • Proxy, acts like OOP class but allows multiple classes to access the same table (requires one none-abstract parent)
    • Subclasses can never override parent fields (see the _ new _ magic)

Advanced Querying

  • Q class

    • Use the bitwise operators & and | for more clever select and where clauses
    • negate with ~ operator
  • F class

    • Allows reference to other fields during lookup (e.g. MyModel.objects.filter(group='hi').update(parent_group='parent_' + F('group'))
    • Allows self field referencing as well
  • extra

    • Allows some raw SQL for very advanced queries
    • Useful for creating sub-queries

Examples

  • Simple Table

Python

from django.db import models

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)

SQL

CREATE TABLE myapp_person (
    "id" serial NOT NULL PRIMARY KEY,
    "first_name" varchar(30) NOT NULL,
    "last_name" varchar(30) NOT NULL
);

Optimizing

Do database work in the database rather than in Python For instance:

  • At the most basic level, use filter and exclude to do filtering in the database.
  • Use F() object query expressions to do filtering against other fields within the same model.
  • Use annotate to do aggregation in the database.

Try to take advantage of the extra when you need it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment