Upgrade to Pro — share decks privately, control downloads, hide ads and more …

The django book - Chap10 : Advanced Models

Spin
July 23, 2013

The django book - Chap10 : Advanced Models

Spin

July 23, 2013
Tweet

More Decks by Spin

Other Decks in Programming

Transcript

  1. 3FMBUFE PCKFDUT 6QEBUF EBUBCBTF TDIFNB .PEFM NFUIPET .BOBHFST &YFDVUF SBX

    42- RVFSJFT .PSF BCPVU .BOBHFST Today’s topics ϋ˜˚݋ಂɧ
  2. 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:1 N:M ϋ˜˚݋ಂɧ
  3. 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 ϋ˜˚݋ಂɧ
  4. 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) ϋ˜˚݋ಂɧ
  5. 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 ϋ˜˚݋ಂɧ
  6. 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 ϋ˜˚݋ಂɧ
  7. 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> ϋ˜˚݋ಂɧ
  8. 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>] ϋ˜˚݋ಂɧ
  9. 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>] ϋ˜˚݋ಂɧ
  10. 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 ϋ˜˚݋ಂɧ
  11. 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 ϋ˜˚݋ಂɧ
  12. 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') [] ϋ˜˚݋ಂɧ
  13. 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>]' ϋ˜˚݋ಂɧ
  14. 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>]' ϋ˜˚݋ಂɧ
  15. 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 ϋ˜˚݋ಂɧ
  16. `syncdb` only create tables for models which have not yet

    been installed. ϋ˜˚݋ಂɧ
  17. 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 ... ϋ˜˚݋ಂɧ
  18. 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 ϋ˜˚݋ಂɧ
  19. 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 ϋ˜˚݋ಂɧ
  20. 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; ϋ˜˚݋ಂɧ
  21. 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] ϋ˜˚݋ಂɧ
  22. Add model fields Add new columns to the DB table

    Add fields to the model Restart the web server In production environments ... ϋ˜˚݋ಂɧ
  23. Add model fields Remove fields from the model Restart the

    web server Remove columns from the DB table Remove Normal fields ... ϋ˜˚݋ಂɧ
  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; ϋ˜˚݋ಂɧ
  25. 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 ... ϋ˜˚݋ಂɧ
  26. 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; ϋ˜˚݋ಂɧ
  27. 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 ϋ˜˚݋ಂɧ
  28. 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; ϋ˜˚݋ಂɧ
  29. 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) ϋ˜˚݋ಂɧ
  30. 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) ϋ˜˚݋ಂɧ
  31. 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 ϋ˜˚݋ಂɧ
  32. 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) ϋ˜˚݋ಂɧ
  33. Manager “ The interface through which database query operations are

    provided to Django models. ” ϋ˜˚݋ಂɧ
  34. 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’ .... ..... ....... ϋ˜˚݋ಂɧ
  35. Add extra Manager methods # takes a keyword and returns

    the number of books >>> Book.objects.title_count('django') >>> Book.objects.title_count('python') ϋ˜˚݋ಂɧ
  36. # 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 ϋ˜˚݋ಂɧ
  37. # 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 ϋ˜˚݋ಂɧ
  38. Modify initial Manager QuerySets Default Manager return all the records

    Override Manager’s base QuerySets ϋ˜˚݋ಂɧ
  39. 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() ϋ˜˚݋ಂɧ
  40. Modify initial Manager QuerySets Default Manager return all the records

    Override Manager’s base QuerySets By overriding the Manager.get_query_set() ϋ˜˚݋ಂɧ
  41. 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. ϋ˜˚݋ಂɧ
  42. 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. ϋ˜˚݋ಂɧ
  43. 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() ϋ˜˚݋ಂɧ
  44. 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() ϋ˜˚݋ಂɧ
  45. 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'] ϋ˜˚݋ಂɧ
  46. 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() ϋ˜˚݋ಂɧ
  47. 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() ϋ˜˚݋ಂɧ
  48. 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() ϋ˜˚݋ಂɧ
  49. 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() ϋ˜˚݋ಂɧ
  50. 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() ϋ˜˚݋ಂɧ
  51. 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() ϋ˜˚݋ಂɧ
  52. Drawbacks Not chainable between custom methods. # It didn’t work

    ! >>> Todo.objects.incomplete().high_priority() ϋ˜˚݋ಂɧ
  53. 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() ϋ˜˚݋ಂɧ
  54. 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() ϋ˜˚݋ಂɧ
  55. 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() ϋ˜˚݋ಂɧ
  56. 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() ϋ˜˚݋ಂɧ
  57. 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 !! ϋ˜˚݋ಂɧ
  58. 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() ϋ˜˚݋ಂɧ
  59. 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() ϋ˜˚݋ಂɧ