Django is a high-level Python Web framework that encourages rapid development and clean, pragmatic design.
MVT (Model View Template)
Flexible template language that can be used to generate HTML, CSV, Email or any other format.
Includes ORM that supports many databases – Postgresql, MySQL, Oracle, SQLite.
Lots of extras included – middleware, csrf protections, sessions, caching, authentication
Models contains anything and everything about the data: how to access it, how to validate it.
Each model is a Python class that subclasses django.db.models.Model.
Each attribute of the model represents a database field.
Django gives you an automatically-generated database-access API
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
CREATE TABLE myapp_person (
"id" serial NOT NULL PRIMARY KEY,
"first_name" varchar(30) NOT NULL,
"last_name" varchar(30) NOT NULL
);
The most important part of a model – and the only required part of a model – is the list of database fields.
Field types
Each field in your model should be an instance of the appropriate Field class.
The column type, which tells the database what kind of data to store
e.g. INTEGER, VARCHAR.
The default HTML widget to use when rendering a form field
e.g. <input type="text">, <select>.
The minimal validation requirements, used in Django’s admin and in automatically-generated forms.
Available field types in django
Field options
Each field takes a certain set of field-specific arguments .
For example, CharField require a max_length argument.
Common field options: null, black , choices, default, help_text, primary key, unique
Available field options in django
PostgreSQL specific fields
For example: ArrayField, JSONField
Many-To-One(Foreign Key)
Primary key of other model.
from django.db import models
class Manufacturer(models.Model):
# ...
pass
class Car(models.Model):
manufacturer = models.ForeignKey(
Manufacturer,
on_delete=models.CASCADE
)
# ...
Many-to-many
A row in a table in a database can be associated with one or (likely) more rows in another table.
It doesn’t matter which model has the ManyToManyField, but you should only put it in one of the models – not both.
Add extra fields on many-to-many relationships
from django.db import models
class Topping(models.Model):
# ...
pass
class Pizza(models.Model):
# ...
toppings = models.ManyToManyField(Topping)
One-to-one relationships
from django.db import models
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
class Restaurant(models.Model):
place = models.OneToOneField(Place,
on_delete=models.CASCADE,
primary_key=True,
)
serves_hot_dogs = models.BooleanField(default=False)
serves_pizza = models.BooleanField(default=False)
Model metadata is “anything that’s not a field”, such as ordering options
from django.db import models
class Ox(models.Model):
horn_length = models.IntegerField()
class Meta:
db_table = 'ox'
ordering = ["horn_length"]
verbose_name_plural = "oxen"
Define custom methods on a model to add custom “row-level” functionality to your objects
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
birth_date = models.DateField()
@staticmethod
def full_name(self):
"Returns the person's full name."
return '%s %s' % (self.first_name, self.last_name)
def full_name(self):
"Returns the person's full name."
return '%s %s' % (self.first_name, self.last_name)
Model inheritance in Django works almost identically to the way normal class inheritance works in Python
There are three styles of inheritance that are possible in Django.
This model will then not be used to create any database table. Instead, when it is used as a base class for other models
write your base class and put abstract=True in the Meta class
from django.db import models
class CommonInfo(models.Model):
name = models.CharField(max_length=100)
age = models.PositiveIntegerField()
class Meta:
abstract = True
class Student(CommonInfo):
home_group = models.CharField(max_length=5)
When using multi-table inheritance, a new database table is created for each subclass of a model.
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
class MyPerson(Person):
class Meta:
proxy = True
def do_something(self):
# ...
pass
To inherit from multiple parent models
from django.db import models
class Article(models.Model):
article_id = models.AutoField(primary_key=True)
...
class Book(models.Model):
book_id = models.AutoField(primary_key=True)
...
class BookReview(Book, Article):
pass
Creating objects
An instance of that class represents a particular record in the database table.
from blog.models import
b = Blog(name='Beatles Blog',
tagline='All the latest Beatles news.'
)
b.save()
Blog.objects.create(
name='Beatles Blog',
tagline='All the latest Beatles news.'
)
Entry.objects.get(id=1)
Entry.objects.filter(name='ggk')
Entry.objects.all()
Entry.objects.all()[:5]
Limiting querysets
Retrieving objects
Entry.objects.filter(pub_date__lte='2006-01-01') #lessthan
Blog.objects.get(name__iexact="beatles blog")
A case-insensitive match.
Field lookups are how you specify the meat of an SQL WHERE clause.
Entry.objects.get(headline__exact="Cat bites dog")
Case-sensitive containment test
Icontains, startswith, endswith, istartswith, iendswith
Entry.objects.get(headline__contains='Lennon')
Entry.objects.filter(blog__name='Beatles Blog')
Django offers a powerful and intuitive way to “follow” relationships in lookups, taking care of the SQL JOINs for you automatically.
Entry.objects.filter(n_comments__gt=F('n_pingbacks'))
Entry.objects.filter(authors__name=F('blog__name'))
It supports time objects also
Entry.objects.filter(mod_date__gt=F('pub_date') + \
timedelta(days=3))
Poll.objects.get(
Q(question__startswith='Who'),
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
)
Q objects - queries with or statements
some_entry == other_entry or some_entry.id == other_entry.id
e.delete()
This method immediately deletes the object and returns the number of objects deleted and a dictionary with the number of deletions per object type.
blog = Blog(name='My blog', tagline='Blogging is easy')
blog.save() # blog.pk == 1
blog.pk = None
blog.save() # blog.pk == 2
Entry.objects.filter(pub_date__year=2007).update(
headline='Everything is the same')
e = Entry.objects.get(id=2)
e.blog = some_blog
e.save()
If a model has a ForeignKey, instances of that model will have access to the related (foreign) object via a simple attribute of the model.
e = Entry.objects.select_related().get(id=2)
print(e.blog) # Doesn't hit the database; uses cached version.
print(e.blog) # Doesn't hit the database; uses cached version.
ed = EntryDetail.objects.get(id=2)
ed.entry # Returns the related Entry object.
Book.objects.all().aggregate(Avg('price'))
#{'price__avg': 34.35}
Book.objects.aggregate(average_price=Avg('price'))
#{'average_price': 34.35}
Book.objects.aggregate(Avg('price'),Max('price'),Min('price'))
{'price__avg': 34.35, 'price__max': Decimal('81.20'),
'price__min': Decimal('12.99')}
aggregate() is used to calculate summary values over the objects
q = Book.objects.annotate(Count('authors'))
q = Book.objects.annotate(Count('authors'), Count('store'))
Book.objects.filter(name__startswith="Django").annotate(
num_authors=Count('authors'))
Author.objects.annotate(average_rating=Avg('book__rating'))
.values('name', 'average_rating')
Author.objects.filter(name__contains='Terry')
A common task for web applications is to search some data in the database with user input.
Basic Example
Author.objects.filter(name__unaccent__icontains='Helen')
Ahthor.objects.filter(name__search='author')
A Manager is the interface through which database query operations are provided to Django models. At least one Manager exists for every model in a Django application.
By default, Django adds a Manager with the name objects to every Django model class. However, if you want to use objects as a field name, or if you want to use a name other than objects for the Manager, you can rename it on a per-model basis
from django.db import models
class Person(models.Model):
#...
people = models.Manager()
Person.people.all()
Adding extra Manager methods is the preferred way to add “table-level” functionality to your models.
class DahlBookManager(models.Manager):
def get_queryset(self):
return super(DahlBookManager, self).
get_queryset().filter(author='Roald Dahl')
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.CharField(max_length=50)
objects = models.Manager() # The default manager.
# The Dahl-specific manager.
dahl_objects = DahlBookManager()
Book.objects.all()
Book.dahl_objects.all()
Adding custom queryset methods.
class PersonQuerySet(models.QuerySet):
def authors(self):
return self.filter(role='A')
def editors(self):
return self.filter(role='E')
class Student(models.Model):
'''person'''
name = models.CharField(max_length=50)
objects = PersonQuerySet.as_manager()
Person.objects.authors()
Person.objects.raw('''SELECT id, first_name, last_name,
birth_date FROM myapp_person''')
Person.objects.raw('''SELECT first AS first_name,
last AS last_name,
bd AS birth_date,
pk AS id,
FROM some_other_table''')
name_map = {'first': 'first_name', 'last': 'last_name',
'bd': 'birth_date', 'pk': 'id'}
Person.objects.raw('SELECT * FROM some_other_table',
translations=name_map)
lname = 'Doe'
Person.objects.raw(
'SELECT * FROM myapp_person WHERE last_name = %s',
[lname])
from django.db import connection
def my_custom_sql(self):
with connection.cursor() as cursor:
cursor.execute("SELECT foo FROM bar WHERE baz = %s",
[self.baz])
row = cursor.fetchone()
return row
from django.db import transaction
@transaction.atomic
def viewfunc(request):
# This code executes inside a transaction.
do_stuff()
Under the hood, Django’s transaction management code:
from django.db import transaction
def do_something():
pass # send a mail, invalidate a cache, fire off a Celery task, etc.
transaction.on_commit(do_something)
DATABASES = {
'default': {
'NAME': 'user_data',
'ENGINE': 'django.db.backends.mysql',
'USER': 'mysql_user',
'PASSWORD': 'superS3cret'
},
'customers': {
'NAME': 'customer_data',
'ENGINE': 'django.db.backends.mysql',
'USER': 'mysql_cust',
'PASSWORD': 'veryPriv@ate'
}
}
class AuthRouter(object):
"""
A router to control all database operations on models in the
auth application.
"""
def db_for_read(self, model, **hints):
"""
Attempts to read auth models go to auth_db.
"""
if model._meta.app_label == 'auth':
return 'auth_db'
return None
def db_for_write(self, model, **hints):
"""
Attempts to write auth models go to auth_db.
"""
if model._meta.app_label == 'auth':
return 'auth_db'
return None
p = Person(name='Fred')
p.save(using='first') # (statement 1)
p.save(using='second')