模型

我们注意到 syncdb仅仅创建数据库里还没有的表,它并不对你数据模型的修改进行同步,也不处理数据模型的删除。如果你新增或修改数据模型里的字段,或是删除了一个数据模型,你需要手动在数据库里进行相应的修改。

  1. 如果模型包含一个未曾在数据库里建立的字段,Django会报出错信息。当你第一次用Django的数据库API请求表中不存在的字段时会导致错误(就是说,它会在运行时出错,而不是编译时)。
  2. Django不关心数据库表中是否存在未在模型中定义的列。
  3. Django不关心数据库中是否存在未被模型表示的表格。

增加字段

  1. 在你的模型里添加字段。
  2. 运行

    manage.py sqlall [yourapp]

来测试模型新的 CREATE TABLE 语句。 注意为新字段的列定义。

  1. 开启你的数据库的交互命令界面(比如, psql 或mysql , 或者可以使用

    manage.py dbshell

)。 执行 ALTER TABLE 语句来添加新列。

  1. 使用Python的

    manage.py shell

,通过导入模型和选中表单(例如,

    MyModel.objects.all()[:5]

)来验证新的字段是否被正确的添加 ,如果一切顺利,所有的语句都不会报错。

删除字段

  1. 直接删除字段,然后重启你的 web 服务
  2. 从数据库中删除表的字段

删除 SQL:

ALTER TABLE books_book DROP COLUMN num_pages;


如果是

ManyToManyField

,这需要删除的是表,而不是字段。

DROP TABLE books_book_authors;


Managers

在语句 Book.objects.all() 中,objects 是一个特殊的属性,需要通过它查询数据库,其实这就是模块的 manager

模块 manager 是一个对象,Django 模块通过它进行数据库查询。 每个 Django 模块至少有一个 manager,你可以创建自定义 manager 以定制数据库访问。

下面是你创建自定义 manager 的两个原因:

  1. 增加额外的 manager 方法,
  2. 修改 manager 返回的初始 QuerySet

增加额外的Manager方法

增加额外的manager方法是为模块添加表级功能的首选办法。

例如,我们为Book模型定义了一个title_count()方法,它需要一个关键字,返回包含这个关键字的书的数量。

# models.py
from django.db import models

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


有了这个manager,我们现在可以这样做:

>>> Book.objects.title_count('django')
4
>>> Book.objects.title_count('python')
18


修改初始Manager QuerySets

manager的基本QuerySet返回系统中的所有对象。 例如,

Book.objects.all()

返回数据库book中的所有书本。

我们可以通过覆盖 Manager.get_query_set() 方法来重写 manager 的基本QuerySet。 get_query_set()按照你的要求返回一个QuerySet。

!注意:这里重写 get_query_set() 其实就是重写了 all() 函数。

示例:
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.


注意我们明确地将objects设置成manager的实例,因为如果我们不这么做,那么唯一可用的manager就将是dah1_objects。

如果你使用自定义的Manager对象,请注意,Django 遇到的第一个 Manager (以它在模型中被定义的位置为准)会有一个特殊状态。 Django 将会把第一个 Manager 定义为默认Manager ,Django 的许多部分(但是不包括admin应用)将会明确地为模型使用这个 manager。 结论是,你应该小心地选择你的默认 manager。因为覆盖 get_query_set() 了,你可能接受到一个无用的返回对像,你必须避免这种情况。

执行原始SQL查询

有时候你会发现Django数据库API带给你的也只有这么多,那你可以为你的数据库写一些自定义SQL查询。你可以通过导入 django.db.connection 对像来轻松实现,它代表当前数据库连接。 要使用它,需要通过 connection.cursor() 得到一个游标对像。 然后,使用 cursor.execute(sql, [params]) 来执行SQL语句,使用 cursor.fetchone() 或者 cursor.fetchall() 来返回记录集。

from django.db import connection, models

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()