美文网首页我爱编程
The Django Book 第十章

The Django Book 第十章

作者: Alex_Honnold | 来源:发表于2018-04-10 17:42 被阅读0次

    本书网站链接
    数据库模型:

    from django.db import models
    
    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
    
    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)
    
    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
    

    访问外键(Foreign Key)值:

    >>> b = Book.objects.get(id=50)
    >>> b.publisher
    <Publisher: Apress Publishing>
    >>> b.publisher.website
    u'http://www.apress.com/'
    

    对于用ForeignKey 来定义的关系来说,在关系的另一端也能反向的追溯回来,只不过由于不对称性的关系而稍有不同。 通过一个publisher 对象,直接获取 books ,用 publisher.book_set.all() ,如下:

    >>> p = Publisher.objects.get(name='Apress Publishing')
    >>> p.book_set.all()
    [<Book: The Django Book>, <Book: Dive Into Python>, ...]
    

    实际上,book_set 只是一个 QuerySet(参考第5章的介绍),所以它可以像QuerySet一样,能实现数据过滤和分切,例如:

    >>> p = Publisher.objects.get(name='Apress Publishing')
    >>> p.book_set.filter(name__icontains='django')
    [<Book: The Django Book>, <Book: Pro Django>]
    

    属性名称book_set是由模型名称的小写(如book)加_set组成的。

    访问多对多值(Many-to-Many Values):

    >>> 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')
    []
    
    # 反向查询(QuerySet)也可以。 要查看一个作者的所有书籍,使用author.book_set ,就如这样:
    >>> a = Author.objects.get(first_name='Adrian', last_name='Holovaty')
    >>> a.book_set.all()
    [<Book: The Django Book>, <Book: Adrian's Other Book>]
    

    更改数据库模式(Database Schema):

    添加字段步骤:

    1. 在你的模型里添加字段。
    2. 运行 manage.py sqlall [yourapp] 来测试模型新的 CREATE TABLE 语句。 注意为新字段的列定义。
    3. 开启你的数据库的交互命令界面(比如, psql 或mysql , 或者可以使用 manage.py dbshell )。 执行ALTER TABLE 语句来添加新列。
    4. 使用Python的manage.py shell,通过导入模型和选中表单(例如, MyModel.objects.all()[:5] )来验证新的字段是否被正确的添加 ,如果一切顺利,所有的语句都不会报错。
    5. 重新启动Web server,使修改生效。

    示例:

    # 比如添加一个num_pages字段到第五章中Book模型
    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
    

    运行命令manage.py sqlall books来查看CREATE TABLE语句。

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

    新加的字段被这样表示:

    "num_pages" integer NULL
    

    接下来,我们要在开发环境上运行数据库客户端,如果是PostgreSQL,运行 psql,,然后,我执行如下语句。

    ALTER TABLE books_book ADD COLUMN num_pages integer;
    

    然而,想要添加不能含有空值的字段也是可以的。 要想实现这样的效果,你必须先创建 NULL 型的字段,然后将该字段的值填充为某个默认值,然后再将该字段改为 NOT NULL 型。 例如:

    BEGIN;
    ALTER TABLE books_book ADD COLUMN num_pages integer;
    UPDATE books_book SET num_pages=0;
    ALTER TABLE books_book ALTER COLUMN num_pages SET NOT NULL;
    COMMIT;
    

    删除字段:
    从Model中删除一个字段要比添加容易得多。 删除字段,仅仅只要以下几个步骤:

    1. 删除字段,然后重新启动你的web服务器。
    2. 用以下命令从数据库中删除字段:
      ALTER TABLE books_book DROP COLUMN num_pages;

    请保证操作的顺序正确。 如果你先从数据库中删除字段,Django将会立即抛出异常。

    删除多对多关联字段:

    1. 从你的模型中删除ManyToManyField,然后重启web服务器。
    2. 用下面的命令从数据库删除关联表:
      DROP TABLE books_book_authors;

    删除模型:

    1. 从文件中删除你想要删除的模型,然后重启web 服务器models.py
    2. 然后用以下命令从数据库中删除表:
      DROP TABLE books_book;

    managers:

    示例:

    # 为Book模型定义了一个title_count()方法,它需要一个关键字,返回包含这个关键字的书的数量。
    
    # 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
    
    有了这个manager,我们现在可以这样做:
    >>> Book.objects.title_count('django')
    4
    >>> Book.objects.title_count('python')
    18
    

    下面是编码该注意的一些地方:

    我们建立了一个BookManager类,它继承了django.db.models.Manager。这个类只有一个title_count()方法,用来做统计。 注意,这个方法使用了self.filter(),此处self指manager本身。

    我们把BookManager()赋值给模型的objects属性。 它将取代模型的默认manager(objects)如果我们没有特别定义,它将会被自动创建。 我们把它命名为objects,这是为了与自动创建的manager保持一致。

    修改初始Manager QuerySets:
    manager的基本QuerySet返回系统中的所有对象。 例如,Book.objects.all() 返回数据库book中的所有书本。
    我们可以通过覆盖Manager.get_query_set()方法来重写manager的基本QuerySet。 get_query_set()按照你的要求返回一个QuerySet。
    例如,下面的模型有* 两个* manager。一个返回所有对像,另一个只返回作者是Roald Dahl的书。

    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.**
    
    # 调用方式
    Book.dahl_objects.all()
    Book.dahl_objects.filter(title='Matilda')
    Book.dahl_objects.count()
    

    为模型添加多个manager()实例。 这是一个为模型添加通用滤器的简单方法。

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

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

    模型方法:
    为了给你的对像添加一个行级功能,那就定义一个自定义方法。 有鉴于manager经常被用来用一些整表操作(table-wide),模型方法应该只对特殊模型实例起作用。

    执行原始SQL查询:

    相关文章

      网友评论

        本文标题:The Django Book 第十章

        本文链接:https://www.haomeiwen.com/subject/kthzyxtx.html