The django book - Chap10 : Advanced Models
Upcoming SlideShare
Loading in...5
×
 

The django book - Chap10 : Advanced Models

on

  • 1,432 views

 

Statistics

Views

Total Views
1,432
Views on SlideShare
1,432
Embed Views
0

Actions

Likes
3
Downloads
23
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

The django book - Chap10 : Advanced Models The django book - Chap10 : Advanced Models Presentation Transcript

  • Advanced Models 「The Django Book」 Chapter 10 Spin Lai July 23, 2013 2013年7月24日星期三
  • 賴司平 (Spin) 資拓宏宇 氣象科技事業處 PHP、Javascript、Python About me 2013年7月24日星期三
  • Related objects Update database schema Model methods Managers Execute raw SQL queries More about Managers Today’s topics 2013年7月24日星期三 View slide
  • Related objects 2013年7月24日星期三 View slide
  • Recalling the Chapter 5 ... 2013年7月24日星期三
  • Publisher id name address city state_province country website AutoField CharField CharField CharField CharField CharField URLField Book id title authors publisher publication_date AutoField CharField ManyToManyField ForeignKey DateField Author id first_name last_name email AutoField CharField CharField EmailField N:1N:M 2013年7月24日星期三
  • class Publisher(models.Model): name = models.CharField(max_length=30) address = models.CharField(max_length=50) city = models.CharField(max_length=60) state_province = models.CharField(max_length=30) country = models.CharField(max_length=50) website = models.URLField() def __unicode__(self): return self.name 2013年7月24日星期三
  • class Author(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=40) email = models.EmailField() def __unicode__(self): return u'%s %s' % (self.first_name, self.last_name) 2013年7月24日星期三
  • class Book(models.Model): title = models.CharField(max_length=100) authors = models.ManyToManyField(Author) publisher = models.ForeignKey(Publisher) publication_date = models.DateField() def __unicode__(self): return self.title 2013年7月24日星期三
  • class Book(models.Model): title = models.CharField(max_length=100) authors = models.ManyToManyField(Author) publisher = models.ForeignKey(Publisher) publication_date = models.DateField() def __unicode__(self): return self.title 2013年7月24日星期三
  • Foreign Key Value Publisher id name address city state_province country website AutoField CharField CharField CharField CharField CharField URLField Book id title authors publisher AutoField CharField ManyToManyField ForeignKey >>> b = Book.objects.get(id=50) >>> b.publisher <Publisher: Apress Publishing> >>> b.publisher.website u'http://www.apress.com/' <Publisher: Apress Publishing> 2013年7月24日星期三
  • Foreign Key Value Publisher id name address city state_province country website AutoField CharField CharField CharField CharField CharField URLField Book id title authors publisher AutoField CharField ManyToManyField ForeignKey >>> p = Publisher.objects.get(name='Apress Publishing') >>> p.book_set.all() [<Book: The Django Book>, <Book: Dive Into Python>, ...] >>> p.book_set.filter(name__icontains='django') [<Book: The Django Book>, <Book: Pro Django>] 2013年7月24日星期三
  • Foreign Key Value Publisher id name address city state_province country website AutoField CharField CharField CharField CharField CharField URLField Book id title authors publisher AutoField CharField ManyToManyField ForeignKey >>> p = Publisher.objects.get(name='Apress Publishing') >>> p.book_set.all() [<Book: The Django Book>, <Book: Dive Into Python>, ...] >>> p.book_set.filter(name__icontains='django') [<Book: The Django Book>, <Book: Pro Django>] 2013年7月24日星期三
  • class Book(models.Model): title = models.CharField(max_length=100) authors = models.ManyToManyField(Author) publisher = models.ForeignKey(Publisher) publication_date = models.DateField() def __unicode__(self): return self.title 2013年7月24日星期三
  • class Book(models.Model): title = models.CharField(max_length=100) authors = models.ManyToManyField(Author) publisher = models.ForeignKey(Publisher) publication_date = models.DateField() def __unicode__(self): return self.title 2013年7月24日星期三
  • Many-to-Many Values Author id first_name last_name email AutoField CharField CharField EmailField Book id title authors publisher AutoField CharField ManyToManyField ForeignKey >>> b = Book.objects.get(id=50) >>> b.authors.all() [<Author: Adrian Holovaty>, <Author: Jacob Kaplan-Moss>] >>> b.authors.filter (first_name='Adrian') [<Author: Adrian Holovaty>] >>> b.authors.filter (first_name='Adam') [] 2013年7月24日星期三
  • Many-to-Many Values Author id first_name last_name email AutoField CharField CharField EmailField Book id title authors publisher AutoField CharField ManyToManyField ForeignKey >>> a = Author.objects.get(first_name='Adrian', last_name='Holovaty') >>> a.book_set.all() [<Book: The Django Book>, <Book: Adrian's Other Book>]' 2013年7月24日星期三
  • Many-to-Many Values Author id first_name last_name email AutoField CharField CharField EmailField Book id title authors publisher AutoField CharField ManyToManyField ForeignKey >>> a = Author.objects.get(first_name='Adrian', last_name='Holovaty') >>> a.book_set.all() [<Book: The Django Book>, <Book: Adrian's Other Book>]' 2013年7月24日星期三
  • Update database schema 2013年7月24日星期三
  • First of all 2013年7月24日星期三
  • Does not care extra DB table columns Does not care extra DB tables Complains if model contains fields that has not yet been created in the DB table Django 2013年7月24日星期三
  • `syncdb` only create tables for models which have not yet been installed. 2013年7月24日星期三
  • Add model fields Remove model fields Remove models Update database schema 2013年7月24日星期三
  • Add model fields 2013年7月24日星期三
  • Add model fields Add fields to the model Check the column definitions for new fields Add new columns to the DB table Verify new fields was added properly In development environments ... 2013年7月24日星期三
  • Add model fields Add fields to the model Check the column definitions for new fields Add new columns to the DB table Verify new fields was added properly In development environments ... class Book(models.Model): title = models.CharField(max_length=100) authors = models.ManyToManyField(Author) publisher = models.ForeignKey(Publisher) publication_date = models.DateField() num_pages = models.IntegerField(blank=True, null=True) def __unicode__(self): return self.title 2013年7月24日星期三
  • Add model fields Add fields to the model Check the column definitions for new fields Add new columns to the DB table Verify new fields was added properly In development environments ... CREATE TABLE "books_book" ( "id" serial NOT NULL PRIMARY KEY, "title" varchar(100) NOT NULL, "publisher_id" integer NOT NULL REFERENCES "books_publisher" ("id"), "publication_date" date NOT NULL, "num_pages" integer NULL ); $ python manage.py sqlall books 2013年7月24日星期三
  • Add model fields Add fields to the model Check the column definitions for new fields Add new columns to the DB table Verify new fields was added properly In development environments ... ALTER TABLE books_book ADD COLUMN num_pages integer; 2013年7月24日星期三
  • Add model fields Add fields to the model Check the column definitions for new fields Add new columns to the DB table Verify new fields was added properly In development environments ... >>> from mysite.books.models import Book >>> Book.objects.all()[:5] 2013年7月24日星期三
  • Add model fields Add new columns to the DB table Add fields to the model Restart the web server In production environments ... 2013年7月24日星期三
  • Remove model fields 2013年7月24日星期三
  • Add model fields Remove fields from the model Restart the web server Remove columns from the DB table Remove Normal fields ... 2013年7月24日星期三
  • Add model fields Remove fields from the model Restart the web server Remove columns from the DB table Remove Normal fields ... ALTER TABLE books_book DROP COLUMN num_pages; 2013年7月24日星期三
  • Add model fields Remove Many-to-Many fields from the model Restart the web server Remove Many-to-Many table from the DB Remove Many-to-Many fields ... 2013年7月24日星期三
  • Add model fields Remove Many-to-Many fields from the model Restart the web server Remove Many-to-Many table from the DB Remove Many-to-Many fields ... DROP TABLE books_book_authors; 2013年7月24日星期三
  • Remove models 2013年7月24日星期三
  • Remove model from the models.py Restart the web server Remove dependent tables from the DB Remove the target table from the DB Remove models 2013年7月24日星期三
  • Remove model from the `models.py` Restart the web server Remove dependent tables from the DB Remove the target table from the DB Remove models DROP TABLE books_book; 2013年7月24日星期三
  • Model methods 2013年7月24日星期三
  • class Person(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) birth_date = models.DateField() address = models.CharField(max_length=100) city = models.CharField(max_length=50) state = USStateField() # Yes, this is U.S.-centric... def baby_boomer_status(self): "Returns the person's baby-boomer status." import datetime if datetime.date(1945, 8, 1) <= self.birth_date <= datetime.date(1964, 12, 31): return "Baby boomer" if self.birth_date < datetime.date(1945, 8, 1): return "Pre-boomer" return "Post-boomer" def is_midwestern(self): "Returns True if this person is from the Midwest." return self.state in ('IL', 'WI', 'MI', 'IN', 'OH', 'IA', 'MO') def _get_full_name(self): "Returns the person's full name." return u'%s %s' % (self.first_name, self.last_name) full_name = property(_get_full_name) 2013年7月24日星期三
  • class Person(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) birth_date = models.DateField() address = models.CharField(max_length=100) city = models.CharField(max_length=50) state = USStateField() # Yes, this is U.S.-centric... def baby_boomer_status(self): "Returns the person's baby-boomer status." import datetime if datetime.date(1945, 8, 1) <= self.birth_date <= datetime.date(1964, 12, 31): return "Baby boomer" if self.birth_date < datetime.date(1945, 8, 1): return "Pre-boomer" return "Post-boomer" def is_midwestern(self): "Returns True if this person is from the Midwest." return self.state in ('IL', 'WI', 'MI', 'IN', 'OH', 'IA', 'MO') def _get_full_name(self): "Returns the person's full name." return u'%s %s' % (self.first_name, self.last_name) full_name = property(_get_full_name) 2013年7月24日星期三
  • Model methods >>> p = Person.objects.get(first_name='Barack', last_name='Obama') >>> p.birth_date datetime.date(1961, 8, 4) >>> p.baby_boomer_status() 'Baby boomer' >>> p.is_midwestern() True 2013年7月24日星期三
  • class Person(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) birth_date = models.DateField() address = models.CharField(max_length=100) city = models.CharField(max_length=50) state = USStateField() # Yes, this is U.S.-centric... def baby_boomer_status(self): "Returns the person's baby-boomer status." import datetime if datetime.date(1945, 8, 1) <= self.birth_date <= datetime.date(1964, 12, 31): return "Baby boomer" if self.birth_date < datetime.date(1945, 8, 1): return "Pre-boomer" return "Post-boomer" def is_midwestern(self): "Returns True if this person is from the Midwest." return self.state in ('IL', 'WI', 'MI', 'IN', 'OH', 'IA', 'MO') def _get_full_name(self): "Returns the person's full name." return u'%s %s' % (self.first_name, self.last_name) full_name = property(_get_full_name) 2013年7月24日星期三
  • Property methods >>> p = Person.objects.get(first_name='Barack', last_name='Obama') >>> p.full_name # Note this isn't a method u'Barack Obama' 2013年7月24日星期三
  • Managers 2013年7月24日星期三
  • What is Manager? 2013年7月24日星期三
  • Manager Book.objects.all() 2013年7月24日星期三
  • Manager Book.objects.all() 2013年7月24日星期三
  • Manager “ The interface through which database query operations are provided to Django models. ” 2013年7月24日星期三
  • Why do we need a custom Manager? 2013年7月24日星期三
  • Add extra Manager methods Modify initial Manager QuerySets Custom Mangers 2013年7月24日星期三
  • Add extra Manager methods 2013年7月24日星期三
  • Add extra Manager methods # Get the number of books that have a title ‘Django’ >>> Book.objects.filter(title__icontains='Django') # Get the number of books that have a title ‘Python’ >>> Book.objects.filter(title__icontains='Python') # Get the number of books that have a title ‘xxx’ .... # Get the number of books that have a title ‘yyy’ .... ..... ....... 2013年7月24日星期三
  • Add extra Manager methods # takes a keyword and returns the number of books >>> Book.objects.title_count('django') >>> Book.objects.title_count('python') 2013年7月24日星期三
  • # models.py from django.db import models # ... Author and Publisher models here ... class BookManager(models.Manager): def title_count(self, keyword): return self.filter(title__icontains=keyword).count() class Book(models.Model): title = models.CharField(max_length=100) authors = models.ManyToManyField(Author) publisher = models.ForeignKey(Publisher) publication_date = models.DateField() num_pages = models.IntegerField(blank=True, null=True) objects = BookManager() def __unicode__(self): return self.title 2013年7月24日星期三
  • # models.py from django.db import models # ... Author and Publisher models here ... class BookManager(models.Manager): def title_count(self, keyword): return self.filter(title__icontains=keyword).count() class Book(models.Model): title = models.CharField(max_length=100) authors = models.ManyToManyField(Author) publisher = models.ForeignKey(Publisher) publication_date = models.DateField() num_pages = models.IntegerField(blank=True, null=True) objects = BookManager() def __unicode__(self): return self.title 2013年7月24日星期三
  • Modify initial Manager QuerySets 2013年7月24日星期三
  • Modify initial Manager QuerySets Default Manager return all the records Override Manager’s base QuerySets 2013年7月24日星期三
  • Modify initial Manager QuerySets Default Manager return all the records Override Manager’s base QuerySets # returns all books in the book database >>> Book.objects.all() 2013年7月24日星期三
  • Modify initial Manager QuerySets Default Manager return all the records Override Manager’s base QuerySets By overriding the Manager.get_query_set() 2013年7月24日星期三
  • Modify initial Manager QuerySets from django.db import models # First, define the Manager subclass. class DahlBookManager(models.Manager): def get_query_set(self): return super(DahlBookManager, self).get_query_set() .filter(author='Roald Dahl') # Then hook it into the Book model explicitly. class Book(models.Model): title = models.CharField(max_length=100) author = models.CharField(max_length=50) # ... objects = models.Manager() # The default manager. dahl_objects = DahlBookManager() # The Dahl-specific manager. 2013年7月24日星期三
  • Modify initial Manager QuerySets from django.db import models # First, define the Manager subclass. class DahlBookManager(models.Manager): def get_query_set(self): return super(DahlBookManager, self).get_query_set() .filter(author='Roald Dahl') # Then hook it into the Book model explicitly. class Book(models.Model): title = models.CharField(max_length=100) author = models.CharField(max_length=50) # ... objects = models.Manager() # The default manager. dahl_objects = DahlBookManager() # The Dahl-specific manager. 2013年7月24日星期三
  • Modify initial Manager QuerySets >>> Book.dahl_objects.all() >>> Book.dahl_objects.filter(title='Matilda') >>> Book.dahl_objects.count() 2013年7月24日星期三
  • Another example class MaleManager(models.Manager): def get_query_set(self): return super(MaleManager, self).get_query_set().filter(sex='M') class FemaleManager(models.Manager): def get_query_set(self): return super(FemaleManager, self).get_query_set().filter(sex='F') class Person(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) sex = models.CharField(max_length=1, choices=(('M', 'Male'), ('F', 'Female'))) people = models.Manager() men = MaleManager() women = FemaleManager() 2013年7月24日星期三
  • Another example class MaleManager(models.Manager): def get_query_set(self): return super(MaleManager, self).get_query_set().filter(sex='M') class FemaleManager(models.Manager): def get_query_set(self): return super(FemaleManager, self).get_query_set().filter(sex='F') class Person(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) sex = models.CharField(max_length=1, choices=(('M', 'Male'), ('F', 'Female'))) people = models.Manager() men = MaleManager() women = FemaleManager() 2013年7月24日星期三
  • Modify initial Manager QuerySets >>> Person.men.all() >>> Person.women.all() >>> Person.people.all() 2013年7月24日星期三
  • Execute raw SQL queries 2013年7月24日星期三
  • Django DB objects 2013年7月24日星期三
  • connection object cursor object cursor.execute() cursor.fetchone() / cursor.fetchall() Implement the Python DB-API (PEP-0249) Django DB objects 2013年7月24日星期三
  • Execute raw SQL queries >>> from django.db import connection >>> cursor = connection.cursor() >>> cursor.execute(""" ... SELECT DISTINCT first_name ... FROM people_person ... WHERE last_name = %s""", ['Lennon']) >>> row = cursor.fetchone() >>> print row ['John'] 2013年7月24日星期三
  • Execute raw SQL queries class PersonManager(models.Manager): def first_names(self, last_name): cursor = connection.cursor() cursor.execute(""" SELECT DISTINCT first_name FROM people_person WHERE last_name = %s""", [last_name]) return [row[0] for row in cursor.fetchone()] class Person(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) objects = PersonManager() 2013年7月24日星期三
  • Execute raw SQL queries class PersonManager(models.Manager): def first_names(self, last_name): cursor = connection.cursor() cursor.execute(""" SELECT DISTINCT first_name FROM people_person WHERE last_name = %s""", [last_name]) return [row[0] for row in cursor.fetchone()] class Person(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) objects = PersonManager() 2013年7月24日星期三
  • Execute raw SQL queries class PersonManager(models.Manager): def first_names(self, last_name): cursor = connection.cursor() cursor.execute(""" SELECT DISTINCT first_name FROM people_person WHERE last_name = %s""", [last_name]) return [row[0] for row in cursor.fetchone()] class Person(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) objects = PersonManager() 2013年7月24日星期三
  • Execute raw SQL queries >>> Person.objects.first_names('Lennon') ['John', 'Cynthia'] 2013年7月24日星期三
  • More about Managers 2013年7月24日星期三
  • As mentioned previously... 2013年7月24日星期三
  • Business logic encapsulation Add custom Managers Override default Manager with custom methods 2013年7月24日星期三
  • Add custom Managers class IncompleteTodoManager(models.Manager): def get_query_set(self): return super(TodoManager, self).get_query_set().filter(is_done=False) class HighPriorityTodoManager(models.Manager): def get_query_set(self): return super(TodoManager, self).get_query_set().filter(priority=1) class Todo(models.Model): content = models.CharField(max_length=100) # other fields go here.. objects = models.Manager() # the default manager # attach our custom managers: incomplete = models.IncompleteTodoManager() high_priority = models.HighPriorityTodoManager() 2013年7月24日星期三
  • Add custom Managers class IncompleteTodoManager(models.Manager): def get_query_set(self): return super(TodoManager, self).get_query_set().filter(is_done=False) class HighPriorityTodoManager(models.Manager): def get_query_set(self): return super(TodoManager, self).get_query_set().filter(priority=1) class Todo(models.Model): content = models.CharField(max_length=100) # other fields go here.. objects = models.Manager() # the default manager # attach our custom managers: incomplete = models.IncompleteTodoManager() high_priority = models.HighPriorityTodoManager() 2013年7月24日星期三
  • Add custom Managers >>> Todo.incomplete.all() >>> Todo.high_priority.all() 2013年7月24日星期三
  • But 2013年7月24日星期三
  • Drawbacks Verbose Managers Cluttered model namespace Not chainable 2013年7月24日星期三
  • Custom Manager methods 2013年7月24日星期三
  • Custom Manager methods class TodoManager(models.Manager): def incomplete(self): return self.filter(is_done=False) def high_priority(self): return self.filter(priority=1) class Todo(models.Model): content = models.CharField(max_length=100) # other fields go here.. objects = TodoManager() 2013年7月24日星期三
  • Custom Manager methods >>> Todo.objects.incomplete() >>> Todo.objects.high_priority() 2013年7月24日星期三
  • But 2013年7月24日星期三
  • Drawbacks Not chainable between custom methods. # It didn’t work ! >>> Todo.objects.incomplete().high_priority() 2013年7月24日星期三
  • Custom QuerySets 2013年7月24日星期三
  • Custom QuerySets class TodoQuerySet(models.query.QuerySet): def incomplete(self): return self.filter(is_done=False) def high_priority(self): return self.filter(priority=1) class TodoManager(models.Manager): def get_query_set(self): return TodoQuerySet(self.model, using=self._db) class Todo(models.Model): content = models.CharField(max_length=100) # other fields go here.. objects = TodoManager() 2013年7月24日星期三
  • Custom QuerySets class TodoQuerySet(models.query.QuerySet): def incomplete(self): return self.filter(is_done=False) def high_priority(self): return self.filter(priority=1) class TodoManager(models.Manager): def get_query_set(self): return TodoQuerySet(self.model, using=self._db) class Todo(models.Model): content = models.CharField(max_length=100) # other fields go here.. objects = TodoManager() 2013年7月24日星期三
  • Custom QuerySets >>> Todo.objects.get_query_set().incomplete() >>> Todo.objects.get_query_set().high_priority() >>> # (or) >>> Todo.objects.all().incomplete() >>> Todo.objects.all().high_priority() >>> # Chainable !!! >>> Todo.objects.all().incomplete().high_priority() 2013年7月24日星期三
  • But 2013年7月24日星期三
  • Custom QuerySets >>> Todo.objects.get_query_set().incomplete() >>> Todo.objects.get_query_set().high_priority() >>> # (or) >>> Todo.objects.all().incomplete() >>> Todo.objects.all().high_priority() >>> # Chainable !!! >>> Todo.objects.all().incomplete().high_priority() 2013年7月24日星期三
  • Custom QuerySets >>> Todo.objects.get_query_set().incomplete() >>> Todo.objects.get_query_set().high_priority() >>> # (or) >>> Todo.objects.all().incomplete() >>> Todo.objects.all().high_priority() >>> # Chainable !!! >>> Todo.objects.all().incomplete().high_priority() Ug==Ugly !! 2013年7月24日星期三
  • Proxy everything !! 2013年7月24日星期三
  • Proxy everything !! class TodoQuerySet(models.query.QuerySet): def incomplete(self): return self.filter(is_done=False) def high_priority(self): return self.filter(priority=1) class TodoManager(models.Manager): def get_query_set(self): return TodoQuerySet(self.model, using=self._db) def incomplete(self): return self.get_query_set().incomplete() def high_priority(self): return self.get_query_set().high_priority() 2013年7月24日星期三
  • Proxy everything !! class TodoQuerySet(models.query.QuerySet): def incomplete(self): return self.filter(is_done=False) def high_priority(self): return self.filter(priority=1) class TodoManager(models.Manager): def get_query_set(self): return TodoQuerySet(self.model, using=self._db) def incomplete(self): return self.get_query_set().incomplete() def high_priority(self): return self.get_query_set().high_priority() 2013年7月24日星期三
  • Proxy everything !! >>> Todo.objects.incomplete().high_priority() # Perfect !! 2013年7月24日星期三
  • Thank you 2013年7月24日星期三