Django项目实践3 - Django模型(字段、数据库操作及模型继承)

Django小记 同时被 2 个专栏收录
14 篇文章 1 订阅
13 篇文章 23 订阅

http://blog.csdn.net/pipisorry/article/details/45725953

Django数据库字段类型(Field types)

AutoField

class  AutoField( **options)

它是一个根据 ID 自增长的 IntegerField 字段。通常,你不必直接使用该字段。如果你没在别的字段上指定主键,Django 就会自动添加主键字段。详见 自增主键字段(Automatic primary key fields)

BooleanField

class  BooleanField( **options)

一个布尔值(true/false)字段。Django 的管理后台用checkbox来表现该字段类型。

MySQL 用户请注意:

布尔字段在 MySQL 中被存储为 TINYINT 列。它的值只能是 0 或 1 (其他大多数据库都有适用的 BOOLEAN 类型)。所以仅在使用 MySQL 的情况下,从数据库中检索 BooleanField 并保存为 model 的属性,这时属性值是 1 或是 0 ,而不是 True 或 False 。正常情况下,这不会引起问题,因为 Python 保证令 1 == True 和 0 == False 都是有效的。只是在你编写类似 obj isTrue 语句时,如果 obj 正是 model 的一个布尔属性值,那你就要留心注意了。因为在使用 mysql 数据库时,"is" 操作是无效的。在这种场合下,使用相等判断更好(使用 "==")。

CharField

class  CharField( max_length=None [**options ]) 它是一个字符串字段,对小字符串和大字符串都适用。对于更大的文本,应该使用  TextField 。

Django 的管理后台用 <input type="text"> (单行输入框) 来表示这种字段。

CharField 有一个必须传入的参数,字段的最大字符数。它作用于数据库层级和 Django 的数据验证层级。

注意:如果你正在编写的应用要求满足多种数据库,那么你就要注意不同数据库对 max_length 有不同的限制。详见 数据库 (database backend notes) 。

MySQL 用户请注意:

如果你使用 MySQLdb 1.2.2 和 utf8_bin 字符集(非默认设置),有几点注意事项要格外留意。详见 MySQL 数据库 (MySQL database notes) 。

CommaSeparatedIntegerField

class  CommaSeparatedIntegerField( max_length=None [**options ])

它用来存放以逗号间隔的整数序列。和 CharField 一样,必须为它提供 max_length 参数。而且要注意不同数据库对 max_length 的限制。

时间字段

DateTimeField和DateField和TimeField存储的内容分别对应着datetime(),date(),time()三个对象。
auto_now=Ture,字段保存时会自动保存当前时间,但要注意每次对其实例执行save()的时候都会将当前时间保存,也就是不能再手动给它存非当前时间的值。
auto_now_add=True,字段在实例第一次保存的时候会保存当前时间,不管你在这里是否对其赋值。但是之后的save()是可以手动赋值的。也就是新实例化一个model,想手动存其他时间,就需要对该实例save()之后赋值然后再save()。

Note:两者默认值都为False。

Django自动添加当前日期时间到数据库

models.DateTimeField(auto_now_add=True)
DateField
class  DateField( [ auto_now=Falseauto_now_add=False**options ])

该字段利用 Python 的 datetime.date 实例来表示日期。下面是它额外的可选参数:

DateField. auto_now
每一次保存对象时,Django 都会自动将该字段的值设置为当前时间。一般用来表示  "最后修改" 时间。要注意使用的是 当前日期,而并非默认值,所以你不能通过重写默认值的办法来改变保存时间。
DateField. auto_now_add
在第一次创建对象时,Django 自动将该字段的值设置为当前时间,一般用来表示对象创建时间。它使用的同样是 当前日期,而非默认值。

Django 管理后台使用一个带有 Javascript 日历的 <input type="text"> 来表示该字段,它带有一个当前日期的快捷选择。那个 JavaScript 日历总是以星期天做为一个星期的第一天。

DateTimeField

class  DateTimeField( [ auto_now=Falseauto_now_add=False**options ])

该字段利用 datetime.datetime 实例表示日期和时间。该字段所按受的参数和 DateField 一样。

Django 的管理后台使用两个 <input type="text"> 分别表示日期和时间,同样也带有 JavaScript 快捷选项。

TimeField

class  TimeField( [ auto_now=Falseauto_now_add=False**options ])

该字段使用 Python 的 datetime.time 实例来表示时间。它和 DateField 接受同样的自动填充的参数。Django 管理后台使用一个带 Javascript 快捷链接 的 <input type="text"> 表示该字段。

DurationField

New in Django 1.8.

DecimalField

这部分是在 Django 1.0 中新增的:  请查看版本文档
class  DecimalField( max_digits=Nonedecimal_places=None [**options ])

它是使用 Decimal 实例表示固定精度的十进制数的字段。它有两个必须的参数:

DecimalField. max_digits
数字允许的最大位数
DecimalField. decimal_places
小数的最大位数

例如,要存储的数字最大值是999,而带有两个小数位,你可以使用:

models.DecimalField(..., max_digits=5, decimal_places=2)

要存储大约是十亿级且带有10个小数位的数字,就这样写:

models.DecimalField(..., max_digits=19, decimal_places=10)

Django 管理后台使用 <input type="text"> (单行输入框) 表示该字段。

EmailField

class  EmailField( [ max_length=75**options ]),它是带有 email 合法性检测的A  CharField 。

FileField

class  FileField( upload_to=None [max_length=100**options ])

文件上传字段

注意:该字段不支持 primary_key 和 unique 参数,否则会抛出 TypeError 异常。

它有一个必须的参数:FileField.upload_to

用于保存文件的本地文件系统。它根据 MEDIA_ROOT 设置确定该文件的 url 属性。

该路径可以包含 时间格式串 (strftime formatting),可以在上传文件的时候替换成当时日期/时间(这样,就不会出现在上传文件把某个目录塞满的情况了)。

在 Django 1.0 已改动:  请查看版本文档

该参数也可以是一个可调用项,比如是一个函式,可以调用函式获得包含文件名的上传路径。这个可调用项必须要接受两个参数,并且返回一个保存文件用的 Unix-Style 的路径(用 / 斜杠)。两个参数分别是:

参数描述
instance

定义了当前 FileField 的 model 实例。更准确地说,就是以该文件为附件的 model 实例。

大多数情况下,在保存该文件时, model 实例对象还并没有保存到数据库,这是因为它很有可能使用默认的 AutoField,而此时它还没有从数据库中获得主键值。(用法见oteam的http://oteam.cn/2008/10/4/dynamic-upload-paths-in-django/)

filename上传文件的原始名称。在生成最终路径的时候,有可能会用到它。

还有一个可选的参数:

FileField. storage
这部分是在 Django 1.0 中新增的:  请查看版本文档

负责保存和获取文件的对象。详见 Managing files

Django 管理后台使用 <input type="file"> (一个文件上传的部件) 来表示这个对象。

在 model 中使用 FileField 或 ImageField (稍后提到) 要按照以下的步骤:

  1. 在项目配置文件中,你要定义 MEDIA_ROOT ,将它的值设为用来存放上传文件的目录的完整路径。(基于性能的考虑,Django 没有将文件保存在数据库中。) ,然后定义 MEDIA_URL ,将它的值设为表示该目录的网址。要确保 web 服务器所用的帐号拥有对该目录的写权限。
  2. 在 model 里面添加 FileField 或 ImageField ,并且确认已定义了 upload_to 项,让 Django 知道应该用 MEDIA_ROOT 的哪个子目录来保存文件。
  3. 存储在数据库当中的仅仅只是文件的路径(而且是相对于 MEDIA_ROOT 的相对路径)。你可能已经想到利用 Django 提供的 url 这个方便的函式。举个例子,如果你的 ImageField 名称是mug_shot,那么你可以在模板中使用 {{ object.mug_shot.url }} ,就能得到图片的完整网址。

例如,假设你的 MEDIA_ROOT 被设为 '/home/media'upload_to 被设为 'photos/%Y/%m/%d'。 upload_to 中的 '%Y/%m/%d' 是一个 时间格式字符串 (strftime formatting); '%Y' 是四位的年分,'%m' 是两位的月分, '%d' 是两位的日子。如果你在2007年01月15号上传了一个文件,那么这个文件就保存在 /home/media/photos/2007/01/15 目录下。

如果你想得到上传文件的本地文件名称,文件网址,或是文件的大小,你可以使用 nameurl 和 size 属性;详见 管理文件 (Managing files)

注意:在上传文件时,要警惕保存文件的位置和文件的类型,这么做的原因是为了避免安全漏洞。对每一个上传文件都要验证,这样你才能确保上传的文件是你想要的文件。举个例子,如果你盲目地让别人上传文件,而没有对上传文件进行验证,如果保存文件的目录处于 web 服务器的根目录下,万一有人上传了一个 CGI 或是 PHP 脚本,然后通过访问脚本网址来运行上传的脚本,那可就太危险了。千万不要让这样的事情发生!

这部分是在 Django 1.0 中新增的: 在这个版本中,新加了  max_length 参数。

默认情况下,FileField 实例在数据库中的对应列是 varchar(100) ,和其他字段一样,你可以利用 max_length 参数改变字段的最大长度。

FilePathField

class  FilePathField( path=None [match=Nonerecursive=Falsemax_length=100**options ])

它是一个 CharField ,它用来选择文件系统下某个目录里面的某些文件。它有三个专有的参数,只有第一个参数是必须的:

FilePathField. path
这个参数是必需的。它是一个目录的绝对路径,而这个目录就是  FilePathField 用来选择文件的那个目录。比如:  "/home/images".
FilePathField. match
可选参数。它是一个正则表达式字符串,  FilePathField 用它来过滤文件名称,只有符合条件的文件才出现在文件选择列表中。要注意正则表达式只匹配文件名,而不是匹配文件路径。例如:  "foo.*\.txt$" 只匹配名为  foo23.txt 而不匹配  bar.txt 和  foo23.gif
FilePathField. recursive
可选参数。它的值是  True 或  False。默认值是  False。它指定是否包含  path 下的子目录。

当然,这三个参数可以同时使用。

前面已经提到了 match 只匹配文件名称,而不是文件路径。所以下面这个例子:

FilePathField(path="/home/images", match="foo.*", recursive=True)

将匹配 /home/images/foo.gif ,而不匹配 /home/images/foo/bar.gif。这是因为 match 只匹配文件名 (foo.gif 和 bar.gif).

这部分是在 Django 1.0 中新增的: 在这个版本中,新加了  max_length 参数。

默认情况下, FilePathField 实例在数据库中的对应列是s varchar(100) 。和其他字段一样,你可以利用 max_length 参数改变字段的最大升序。

FloatField

class  FloatField( [ **options ])

在 Django 1.0 在已改动:  请查看版本文档

该字段在 Python 中使用by a float 实例来表示一个浮点数。

Django 管理后台用 <input type="text"> (一个单行输入框) 表示该字段。

ImageField

class  ImageField( upload_to=None [height_field=Nonewidth_field=Nonemax_length=100**options ])

和 FileField 一样,只是会验证上传对象是不是一个合法的图象文件。它有两个可选参数:

ImageField. height_field:保存图片高度的字段名称。在保存对象时,会根据该字段设定的高度,对图片文件进行缩放转换。
ImageField. width_field:保存图片宽度的字段名称。在保存对象时,会根据该字段设定的宽度,对图片文件进行缩放转换。

除了那些在 FileField 中有效的参数之外, ImageField 还可以使用 File.height and File.width 两个属性。详见管理文件 (Managing files)(但并没有找到这两个参数的介绍)。使用该字段要求安装 Python Imaging Library(PIL).

这部分是在 Django 1.0 中新增的: 在新版本中新加了 max_length 参数。默认情况下, ImageField 实例对应着数据库中的 created as varchar(100) 列。和其他字段一样,你可以使用 max_length 参数来改变字段的最大长度。

IntegerField

class  IntegerField( [ **options ])

整数字段。Django 管理后台用 <input type="text"> (一个单行输入框) 表示该字段。

IPAddressField

class  IPAddressField( [ **options ])

以字符串形式(比如 192.0.2.30)表示 IP 地址字段。Django 管理后台使用 <input type="text"> (一个单行输入框) 表示该字段。

NullBooleanField

class  NullBooleanField( [ **options ])

与 BooleanField 相似,但多了一个 NULL 选项。建议用该字段代替使用 null=True 选项的 BooleanField 。Django 管理后台使用 <select> 选择框来表示该字段,选择框有三个选项,分别是 "Unknown", "Yes" 和 "No" 。

PositiveIntegerField

class  PositiveIntegerField( [ **options ]),和  IntegerField 相似,但字段值必须是非负数。

PositiveSmallIntegerField

class  PositiveSmallIntegerField( [ **options ]),和  PositiveIntegerField 类似,但数值的取值范围较小,受限于数据库设置。

SlugField

class  SlugField( [ max_length=50**options ])

Slug 是一个新闻术语,是指某个事件的短标签。它只能由字母,数字,下划线或连字符组成。通赏情况下,它被用做网址的一部分。

和 CharField 类似,你可以指定 max_length (要注意数据库兼容性和本节提到的 max_length )。如果没有指定 max_length ,Django 会默认字段长度为50。该字段会自动设置 Field.db_index to True。基于其他字段的值来自动填充 Slug 字段是很有用的。你可以在 Django 的管理后台中使用 prepopulated_fields 来做到这一点。

SmallIntegerField

class  SmallIntegerField( [ **options ]),和  IntegerField 类似,但数值的取值范围较小,受限于数据库的限制。

文本字段TextField

class  TextField( [ **options ])

大文本字段。Django 的管理后台使用 <textarea> (一个多行文本框) 表示该字段。

MySQL 用户请注意:如果你正在使用 MySQLdb 1.2.1p2 和 utf8_bin 字符集(非默认设置),有几点注意事项要格外留意,详见 MySQL database notes 。

TextField中输入换行出现问题:

1. 在TextField中输入带换行的文字,存到数据库后发现是\r\n。但是我的django是在linux上运行的,其他程序都是默认换行是\n的。我如何指定TextField中输入的换行是\n而不是两个?

2.

方法1. 使用模版内部内置的filter: linebreaks

Replaces line breaks in plain text with appropriate HTML; a single newline becomes an HTML line break (<br />) and a new line followed by a blank line becomes a paragraph break (</p>).

{% for news in newss %}
    <p>{{ news.content|linebreaks }}</p>
方法2. 修改model代码

suggest you to override the save method of your model,replacing new line characters to the preferred format:

class MyModel(models.Model):

    body_text = models.TextField()

     ...

      def save(self):

                 self.body_text = self.body_text.replace("\r\n", "\n")

                 self.body_text = self.body_text.replace("\r", "\n")

                super(MyModel, self).save()

[http://markmail.org/message/pro4hiqv3s6v6eb6]

方法3. template rendering 自动 escape HTML tag,需要关掉,比如 |safe  试试

[Django的TextField怎么才能处理空格和回车换行?]

[http://markmail.org/message/ovti7o33qfonsj3c]


URLField

class  URLField( [ verify_exists=Truemax_length=200**options ]),保存 URL 的  CharField 。它有一个额外的可选参数:
URLField. verify_exists
如果为  True (默认值),Django 在保存对象时会检测该 URL 是否可访问(比如,网址可以正常访问,不返回404错误)。值得注意的是,如果你使用的是一个单线程开发服务器,那么验证网址会挂起当前线程。当然,对于生产用的多线程服务器来说,这就不是一个问题了。

Django 管理后台使用 <input type="text"> (一个单行输入框) 表示该字段。

和所有 CharField 子类一样,URLField 接受可选的 max_length 参数,该参数默认值是200。

UUIDField

New in Django 1.8.

XMLField

class  XMLField( schema_path=None [**options ])

这是一个根据给定的 schema 验证所输文本是否是合法 XML 的 TextField 字段。它有一个必需的参数:

schema_path:用来验证 XML 的  RelaxNG schema 的文件路径。

关联关系字段 (Relationship fields)

Django 也定义了一组用来表示关联关系的字段。

ForeignKey

class  ForeignKey( othermodel [**options ])

这是一个多对一关系。必须为它提供一个位置参数:被关联的 model 类。

Note:外键:如果公共关键字在一个关系中是主关键字,那么这个公共关键字被称为另一个关系的外键。由此可见,外键表示了两个关系之间的相关联系。以另一个关系的外键作主关键字的表被称为主表,具有此外键的表被称为主表的从表。外键又称作外关键字。

要创建递归关联时--与对象自己做多对一关系,那就使用 models.ForeignKey('self') 。

如果你要与某个尚未定义的 model 建立关联 ,就使用 model 的名称,而不是使用 model 对象本身:

class Car(models.Model):
    manufacturer = models.ForeignKey('Manufacturer')
    # ...

class Manufacturer(models.Model):
    # ...
这部分是在 Django 1.0 中新建的:  请查看版本文档

要与其他应用中的 model 相关联,你要用完整的应用标签来显式地定义关联。例如,如果上面的 Manufacturer model 定义在另外一个名为 production 的应用中,你只要用:

class Car(models.Model):
    manufacturer = models.ForeignKey('production.Manufacturer')

在解决两个应用双向依赖时,这种引用方法非常有用。

数据库表现 (Database Representation)

Django 使用该字段名称+ "_id" 做为数据库中的列名称。在上面的例子中, Car model 对应的数据表中会有一个 manufacturer_id 列。(你可以通过显式地指定 db_column 来改变该字段的列名称)。不过,除非你想自定义 SQL ,否则没必要更改数据库的列名称。

参数 (Arguments)

ForeignKey 接受下列这些可选参数,这些参数定义了关系是如何运行的。

ForeignKey.limit_choices_to

它是一个包含筛选条件和对应值的字典 (详见see 制作查询(Making queries)),用来在 Django 管理后台筛选关联对象。例如,利用 Python 的 datetime 模块,过滤掉不符合筛选条件关联对象:

limit_choices_to = {'pub_date__lte': datetime.now}

只有 pub_date 在当前日期之前的关联对象才允许被选。

也可以使用 Q 对象来代替字典,从而实现更复杂的筛选,详见 复杂查询 (complex queries)

limit_choices_to 对于在管理后台显示为 inline 的关联对象不起作用。

ForeignKey.related_name
反向名称,用来从被关联字段指向关联字段。在  被关联对象文档 (related objects documentation) 中有详细介绍和范例。注意,在你定义  抽象 model (abstract models) 时,你必须显式指定反向名称; 只有在你这么做了之后,  某些特别语法 (some special syntax) 才能正常使用。
ForeignKey.to_field
指定当前关系与被关联对象中的哪个字段关联。默认情况下,to_field 指向被关联对象的主键。
[ Django中ForeignKey参数的使用 ]
[ ForeignKey选项]

ManyToManyField

class  ManyToManyField( othermodel [**options ])

用来定义多对多关系。必须给它一个位置参数:被关联的 model 类。工作方式和 ForeignKey 一样, 连 递归关联 (recursive) and 延后关联 (lazy) 都一样。

数据库表示 (Database Representation)

Django 创建一个中间表来表示多对多关系。默认情况下,中间表的名称由两个关系表名结合而成。由于某些数据库对表名的长度有限制,所以中间表的名称会自动限制在64个字符以内,并包含一个不重复的哈希字符串。这意味着,你可能看到类似 author_books_9cdf4 这样的表名称;这是很正常的。你可以使用 db_table 选项手动指定中间表名称。

参数 (Arguments)

ManyToManyField 接受下列可选参数,这些参数定义了关系是如何运行的。

ManyToManyField. related_name
和  ForeignKey.related_name 用法一样。
ManyToManyField. limit_choices_to

和 ForeignKey.limit_choices_to 用法一样。

limit_choices_to 对于通过 through 参数指定了中介表的 ManyToManyField 不起作用。

ManyToManyField. symmetrical

只要定义递归的多对多关系时起作用。假调有下面这样一个 model :

class Person(models.Model):
    friends = models.ManyToManyField("self")

Django 处理该 model 时,Django 会发现这个一个关联自己的递归 ManyToManyField ,所以 Django 不会给该字段添加一个指向 Person 类的 person_set 属性,而是把 ManyToManyField视为对称的--也就是说,如果我是你的朋友,那么你自然也就是我的朋友。

如果不想将递归的多对多关系设为对称的,那你就指定 symmetrical 为 False。这样就会强迫 Django 添加反向名称,从而将该 ManyToManyField 关联改为非对称的。

ManyToManyField. through

Django 会自动生成一张表来管理多对多关系。但是,如果你想手动指定中间表,你可以用 through 选项来指定 model 使用另外某个 model 来管理多对多关系。而这个 model 就是中间表所对应的 model 。(我将through所指定的中间表称为中介表)。

当你想使用 多对多关系中的其他数据 (extra data with a many-to-many relationship) 时,一般要用到这个选项。

ManyToManyField. db_table
指定数据库中保存多对多关系数据的表名称。如果没有提供该选项,Django 就会根据两个关系表的名称生成一个新的表名,做为中间表的名称。

OneToOneField

class  OneToOneField( othermodel [parent_link=False**options ])

用来定义一对一关系。笼统地讲,它与声明了 unique=True 的 ForeignKey 非常相似,不同的是使用反向关联的时候,得到的不是一个对象列表,而是一个单独的对象。

在某个 model 扩展自另一个 model 时,这个字段是非常有用的;例如: 多表继承 (Multi-table inheritance) 就是通过在子 model 中添加一个指向父 model 的一对一关联而实现的。

必须给该字段一个参数:被关联的 model 类。工作方式和 ForeignKey 一样,连 递归关联 (recursive) 和 延后关联 (lazy) 都一样。

此外,OneToOneField 接受 ForeignKey 可接受的参数,只有一个参数是 OnetoOneField 专有的:

OneToOneField. parent_link
如果为  True ,并且作用于继承自某个父 model 的子 model 上(这里不能是延后继承,父 model 必须真实存在),那么该字段就会变成指向父类实例的引用(或者叫链接),而不是象其他  OneToOneField 那样用于扩展父类并继承父类属性。

[Model 字段参考 (Model field reference)]

[Model field reference]

[DjangoModels模块]

编写自定义 model 字段(Writing custom model fields)

[ http://wrongwaycn.github.io/django11/howto/custom-model-fields/index.html]

http://blog.csdn.net/pipisorry/article/details/45725953



Django数据库字段选项(Field options)

下列参数对所有字段类型都是有效的,同时这些参数也是可选的。

null

如果为 True ,Django 就会将空值(empty)存储为数据库中的 NULL 。默认值是 False

要注意空字符串(empty string)总是被存储为空字符串,而不是 NULL。 null=True 只对非字符串字段有意义,比如整数(integer),布尔值(boolean),日期(dates)。如果你允许表单提交空值,无论是哪种字段,你还要再设置 blank=True ,这是因为 null 仅仅影响数据库存储 (详见 blank)。

除非你有很充分的理由,否则不要在字符串字段(比如CharField 和 TextField)上使用 null 。在字符串字段上声明 null=True ,就意味着有两种意义的空值:NULL,和空字符串(empty string)。大多数情况下,存在两种空值是多余的。Django 按惯例是使用空字符串,而非 NULL 。

注意:在使用 Oracle 数据库时,null=True 选项将被强加到有可能是空值的字符串字段,而且会在数据库中保存 NULL ,来表示空字符串。

blank

如果为  True,字段允许不填。默认为  False 。

要注意该选项与 null 不同。 null 纯粹是数据库范畴的概念,而 blank 是数据验证范畴的。如果某个字段声明了 blank=True,那么 Django 的管理后台就允许该字段填写空值;否则,如果声明为 blank=False,该字段就是必填的。

choices

它是一个可迭代的二元组(比如,列表或是元组),用来给字段提供选择项。
实现Django后台管理的下拉框选择。如果设置了 choices ,Django 的管理后台就会显示选择框,而不是标准的文本框,而且这个选择框的选项就是 choices 中的元组。‘choices' must  be an iterable containing (actual value, human readable name) tuples.每个元组中的第一个元素,是存储在数据库中的值;第二个元素是该选项更易理解的描述。
choices 列表可以定义为 model 类的一部分,也可以定义在 model 类之外:
class Foo(models.Model):
    GENDER_CHOICES = (
        ('M', 'Male'),
        ('F', 'Female'),
    )
    gender = models.CharField(max_length=1, choices=GENDER_CHOICES)
你也可以将 choices 整理成命名组,这样代码更有条理,结构更清晰:
MEDIA_CHOICES = (
    ('Audio', (
            ('vinyl', 'Vinyl'),
            ('cd', 'CD'),
        )
    ),
    ('Video', (
            ('vhs', 'VHS Tape'),
            ('dvd', 'DVD'),
        )
    ),
    ('unknown', 'Unknown'),
)

每个元组中的第一个元素会用做组的命名。第二个元素是一个可迭代的二元组,每个二元组都包含一个一个值和一个易于理解的描述。分组选项可以和未分组选项组合在一个单独的列表当中(比如上例中的 unknown 项)。

Djanog 会对设置了 choices 的字段添加一个方法。这个方法根据该字段的当前值获取它易于理解的描述。详见数据库 API 文档中的 get_FOO_display() 。

最后注意一点,choices 可以是任何可迭代的对象,并不仅仅只是列表或是元组。这意味着你可以构造动态的 choices ,不过你最好通过 ForeignKey 使用一张适合的数据表来构造动态 choices。毕竟 choices 适用于变动不大的静态数据。

db_column

该字段在数据库中所使用的列名称。如果没有声明,Django 就会以该字段的名称做为列名。

列名称可以是 SQL 保留字,也可以包含不允许出现在 Python 变量名的特殊字符,比如连字符。这是因为 Django 会在幕后给列名和表名加上引号。

db_index

如果为 True,运行 django-admin.py sqlindexes <sqlindexes> 会为该字段输出一条 CREATE INDEX 语句。

db_tablespace

这部分是在 Django 1.0 新增的:  请查看版本文档

如果该字段是索引字段,db_tablespace 就表示该索引所在的数据库表空间的名称。如果项目配置文件中设定了 DEFAULT_INDEX_TABLESPACE ,那么默认值就是配置项的值;如果你指定了该 model 中 Meta 内嵌类的 db_tablespace ,那么默认值就是 Meta 中 db_tablespace 的值。如果数据库不支持表空间,就会忽略该选项。

default

该字段的默认值。它可以是一个值,也可以是一个可调用的对象(这里称之为对象C)。若是后者,那么每次创建一个新对象时,对象C都将被调用。

editable

如果为 False ,那么在 Django 管理后台中就不会编辑该字段;同样,在 Django 自动生成的表单中也不会编辑该字段。默认值是 True 。

help_text

附加的提示信息。在管理后台编辑该对象的表单中,它显示在该字段下面。即使你的对象无须在后台管理,对于文档化也是很用的。

注意,在管理后台显示该提示信息时,并不会对其转义。所以你可以在 help_text 中包含 HTML 。例如:

help_text="Please use the following format: <em>YYYY-MM-DD</em>."

你也可以使用纯文本,还可以用 django.utils.html.escape() 转义任何 HTML 字符。

primary_key

如果为 True,那么该字段就是 model 的主键。

如果你没有指定任何一个字段的 primary_key=True ,Django 就会自动添加一个 IntegerField 做为主键字段。所以除非你想重写默认的主键行为,否则没必要在任何字段上设置primary_key=True 。详见 自增主键字段 (Automatic primary key fields) 。

primary_key=True 意味着 null=False 和 unique=True 。一个对象只能有一个主键。

unique

如果为 True,该字段值就必须是全表唯一的。

它同时作用于数据库层级以及 Django 的管理后台和表单层级。如果你保存 model 时,某个 unique 字段的值是重复的,那么 save() 方法就会抛出 django.db.IntegrityError 异常。

这个选项在所有的字段上都是可用的,除了 ManyToManyField 和 FileField 以外。

unique_for_date

如果要求在某个日期内,该字段值在数据表中是唯一的(就不存在时期和字段值都相同的记录),那就可以将 unique_for_date 设置为某个 DateField 或 DateTimeField 的名称。

例如,假设你有一个声明了 unique_for_date="pub_date" 的 title 字段,那么 Django 就不会允许出现 title 和 pub_date 相同的两条记录。

它作用于 Django 的管理后台和表单层级,而非数据库层级。

unique_for_monthunique_for_year

verbose_name

该字段易于理解的名称。如果没有提供自述名,Django 会根据字段的属性名自动创建自述名--就是将属性名称中的空格替换成下划线。详见 字段的自述名(Verbose field names).

[ Model 字段参考 (Model field reference)]

http://blog.csdn.net/pipisorry/article/details/45725953



模型元编程——元属性

class People(models.Model):
    name = models.CharField(max_length=150, verbose_name='姓名')
    #... ...
    class Meta:
        abstract = True
        db_table = 'People'
Note:

1. Meta中设置abstract = Ture后,类People就是一个抽象类,不会在数据库中建立表?,并且也不能添加到admin后台管理中

2. Meta中设置db_talbe = ‘People’后,类People在数据库中建表后,表名为‘People'而不是默认的appname_people



Django站点管理(后台管理员)-自定义管理工具-自定义模块表现

http://blog.csdn.net/pipisorry/article/details/45725953


Django上进行数据库操作
Django自动为建立的模型提供了高级的Python API,来进行数据库操作

测试数据库的python API

E:\mine\python_workspace\VoteSite>python manage.py shell
...
>>> from books.models import Publisher
>>> Publisher.objects.all()
[]
>>> p1 = Publisher(name='Apress', address='2855 Telegraph Avenue', city='Berkeley', state_province='CA', country='U.S.A.', website='http://www.apress.com/')
>>> p1.save()
>>> p2 = Publisher(name="O'Reilly", address='10 Fawcett St.', city='Cambridge', state_province='MA', country='U.S.A.', website='http://www.oreilly.com/')
>>> p2.save()
>>> Publisher.objects.all()
[<Publisher: Publisher object>, <Publisher: Publisher object>]
>>>
Note:
1. 通过调用该对象的 save() 方法,将对象保存到数据库中。 Django 会在后台执行一条 INSERT 语句。当你使用Django modle API创建对象时Django并未将对象保存至数据库内,除非你调用`` save()`` 方法。
2. 使用`` Publisher.objects`` 属性从数据库取出出版商的信息,这个属性可以认为是包含出版商的记录集。 这个属性有许多方法, 这里先介绍调用`` Publisher.objects.all()`` 方法获取数据库中`` Publisher`` 类的所有对象。这个操作的幕后,Django执行了一条SQL `` SELECT`` 语句。

3. 如果需要一步完成对象的创建与存储至数据库,就使用`` objects.create()`` 方法。 下面的例子与之前的例子等价:

p1 = Publisher.objects.create(name='Apress', address='2855 Telegraph Avenue', city='Berkeley', state_province='CA', country='U.S.A.', website='http://www.apress.com/')
p2 = Publisher.objects.create(name="O'Reilly", address='10 Fawcett St.', city='Cambridge', state_province='MA', country='U.S.A.', website='http://www.oreilly.com/')
Publisher.objects.all()

4. 如果你有用到后面要讲到的admin管理界面,会发现save()之后admin会自动更新列表。如果在管理界面删除某个p3, 那就相当于没有这个操作:p3 = Publisher(name="O'yy", address='10 Fawcett St.', city='Cambridge', state_province='MA', country='U.S.A.', website='http://www.oreilly.com/'),Publisher.objects.all()也会从3个p变成两个p.

添加模块的字符串表现

当我们打印整个Publisher.objects.all()列表时,我们没有得到想要的有用信息,无法把````对象区分开来

解决这个问题,只需要为Publisher 对象添加一个方法__unicode__(){python3换成__str__()!!!} 。__unicode__() 方法告诉Python如何将对象以unicode的方式显示出来。 为以上三个模型添加__unicode__()方法后,就可以看到效果了:

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 __str__(self):
        return self.name


class Author(models.Model):
    '''
    作者有姓,有名及email地址
    '''
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=40)
    email = models.EmailField()

    def __str__(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 __str__(self):
        return self.title

Note:

1.__unicode__() 方法可以进行任何处理来返回对一个对象的字符串表示。

2. 对__unicode__()的唯一要求就是它要返回一个unicode对象 如果`` __unicode__()`` 方法未返回一个Unicode对象,而返回比如说一个整型数字,那么Python将抛出一个`` TypeError`` 错误,并提示:”coercing to Unicode: need string or buffer, int found” 。

3. Django 在其内部的各个方面都使用到了 Unicode 对象。 模型 对象中,检索匹配方面的操作使用的是 Unicode 对象,视图 函数之间的交互使用的是 Unicode 对象,模板的渲染也是用的 Unicode 对象。 通常,我们不必担心编码是否正确,后台会处理的很好。[ 字符编码ASCII,Unicode和UTF-8]

为了让我们的修改生效,先退出Python Shell,然后再次运行 python manage.py shell 进入:

from books.models import Publisher
Publisher.objects.all()
[<Publisher: Apress>, <Publisher: O'Reilly>]

Note:

1. 确保你的每一个模型里都包含 __unicode__() 方法,这不只是为了交互时方便,也是因为 Django会在其他一些地方用__unicode__() 来显示对象。

2.  __unicode__() 也是一个很好的例子来演示我们怎么添加行为 到模型里。 Django的模型不只是为对象定义了数据库表的结构,还定义了对象的行为。

插入和更新数据

在SQL里,这大致可以转换成这样:
INSERT INTO books_publisher
    (name, address, city, state_province, country, website)
VALUES
    ('Apress', '2855 Telegraph Ave.', 'Berkeley', 'CA', 'U.S.A.', 'http://www.apress.com/');

因为 Publisher 模型有一个自动增加的主键id ,所以第一次调用save() 还多做了一件事: 计算这个主键的值并把它赋值给这个对象实例:

>>> p.id
52    # this will differ based on your own data

接下来再调用 save() 将不会创建新的记录,而只是修改记录内容(也就是 执行UPDATE SQL语句,而不是INSERT 语句):

>>> p.name = 'Apress Publishing'
>>> p.save()

前面执行的 save() 相当于下面的SQL语句:

UPDATE books_publisher SET
    name = 'Apress Publishing',
    address = '2855 Telegraph Ave.',
    city = 'Berkeley',
    state_province = 'CA',
    country = 'U.S.A.',
    website = 'http://www.apress.com'
WHERE id = 52;

Note:并不是只更新修改过的那个字段,所有的字段都会被更新。这个操作有可能引起竞态条件,这取决于你的应用程序。 参阅下面讲到的[只更改某一指定的列]

UPDATE books_publisher SET
    name = 'Apress Publishing'
WHERE id=52;

选择对象

对于 Web 应用程序来说,更多的时候是在检索查询数据库。从一个给定的模型中取出所有记录:

>>> Publisher.objects.all()
[<Publisher: Apress>, <Publisher: O'Reilly>]

这相当于这个SQL语句:

SELECT id, name, address, city, state_province, country, website
FROM books_publisher;
Note:
1. Django在选择所有数据时并没有使用 SELECT* ,而是显式列出了所有字段。 SELECT* 会更慢,而且最重要的是列出所有字段遵循了Python 界的一个信条: 明言胜于暗示。
2. objects
属性。 它被称为管理器。 目前,我们只需了解管理器管理着所有针对数据包含、还有最重要的数据查询的表格级操作。所有的模型都自动拥有一个 objects 管理器;你可以在想要查找数据时使用它。
3. all() 方法。这个方法返回返回数据库中所有的记录。 尽管这个对象 看起来 象一个列表(list),它实际是一个 QuerySet 对象, 这个对象是数据库中一些记录的集合。 [ 详细描述QuerySet]
数据过滤

我们很少会一次性从数据库中取出所有的数据;通常都只针对一部分数据进行操作。 在Django API中,我们可以使用`` filter()`` 方法对数据进行过滤:

>>> Publisher.objects.filter(name='Apress')
[<Publisher: Apress>]

filter() 根据关键字参数来转换成WHERE SQL语句。相当于:

SELECT id, name, address, city, state_province, country, website
FROM books_publisher
WHERE name = 'Apress';

你可以传递多个参数到 filter() 来缩小选取范围:

>>> Publisher.objects.filter(country="U.S.A.", state_province="CA")
[<Publisher: Apress>]

多个参数会被转换成 AND SQL从句:

SELECT id, name, address, city, state_province, country, website
FROM books_publisher
WHERE country = 'U.S.A.'
AND state_province = 'CA';

Note:SQL缺省的= 操作符是精确匹配的, 其他类型的查找也可以使用:

>>> Publisher.objects.filter(name__contains="press")
[<Publisher: Apress>]

namecontains 之间有双下划线。和Python一样,Django也使用双下划线来表明会进行一些魔术般的操作。这里,contains部分会被Django翻译成LIKE语句:

SELECT id, name, address, city, state_province, country, website
FROM books_publisher
WHERE name LIKE '%press%';

其他的一些查找类型有:icontains(大小写无关的LIKE),startswithendswith, 还有range(SQLBETWEEN查询)。[详细描述所有的查找类型]

获取单个对象

上面的例子中`` filter()`` 函数返回一个记录集。获取单个的对象get()方法

>>> Publisher.objects.get(name="Apress")
<Publisher: Apress>

这样,就返回了单个对象,而不是列表(更准确的说,QuerySet)。 所以,如果结果是多个对象,会导致抛出异常;如果查询没有返回结果也会抛出异常,这个DoesNotExist 异常 是 Publisher 这个 model 类的一个属性,即Publisher.DoesNotExist

在你的应用中,你可以捕获并处理这个异常,像这样:

try:
    p = Publisher.objects.get(name='Apress')
except Publisher.DoesNotExist:
    print "Apress isn't in the database yet."
else:
    print "Apress is in the database."

数据排序

在运行前面的例子中返回的结果是无序的。 Django 应用中,使用 order_by() 这个方法根据某字段的值对检索结果排序。

>>> Publisher.objects.order_by("name")
[<Publisher: Apress>, <Publisher: O'Reilly>]

跟以前的 all() 例子差不多,SQL语句里多了指定排序的部分:

SELECT id, name, address, city, state_province, country, website
FROM books_publisher
ORDER BY name;

我们可以对任意字段进行排序:

>>> Publisher.objects.order_by("address")
[<Publisher: O'Reilly>, <Publisher: Apress>]

>>> Publisher.objects.order_by("state_province")
[<Publisher: Apress>, <Publisher: O'Reilly>]

如果需要以多个字段为标准进行排序(第二个字段会在第一个字段的值相同的情况下被使用到),使用多个参数就可以了,如下:

>>> Publisher.objects.order_by("state_province", "address")
 [<Publisher: Apress>, <Publisher: O'Reilly>]

我们还可以指定逆向排序,在前面加一个减号 - 前缀:

>>> Publisher.objects.order_by("-name")
[<Publisher: O'Reilly>, <Publisher: Apress>]

但是每次都要用 order_by() 显得有点啰嗦。 大多数时间你通常只会对某些 字段进行排序。

Django指定模型的缺省排序方式:

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 __str__(self):
        return self.name

    class Meta:
        ordering = ['name']

Note:

1. classMeta,内嵌于Publisher 这个类的定义中。你可以在任意一个 模型类中使用Meta 类,来设置一些与特定模型相关的选项。 [Meta 中所有可选项的完整参考]。

2. 如果你设置了这个选项,那么除非你检索时特意额外地使用了order_by(),否则,当你使用 Django 的数据库 API 去检索时,Publisher对象的相关返回值默认地都会按name 字段排序。

连锁查询

通常我们需要同时进行过滤和排序查询的操作。 “链式”形式:

>>> Publisher.objects.filter(country="U.S.A.").order_by("-name")
[<Publisher: O'Reilly>, <Publisher: Apress>]

转换成SQL查询就是 WHEREORDERBY 的组合:

SELECT id, name, address, city, state_province, country, website
FROM books_publisher
WHERE country = 'U.S.A'
ORDER BY name DESC;

限制返回的数据

另一个常用的需求就是取出固定数目的记录。 可以使用标准的Python列表裁剪语句:

>>> Publisher.objects.order_by('name')[0]
<Publisher: Apress>

这相当于:

SELECT id, name, address, city, state_province, country, website
FROM books_publisher
ORDER BY name
LIMIT 1;

类似的,你可以用Python的range-slicing语法来取出数据的特定子集:

>>> Publisher.objects.order_by('name')[0:2]

这个例子返回两个对象,等同于以下的SQL语句:

SELECT id, name, address, city, state_province, country, website
FROM books_publisher
ORDER BY name
OFFSET 0 LIMIT 2;

Note: 不支持Python的负索引(negative slicing),但是我们可以使用其他的方法。 稍微修改 order_by() 语句来实现:

>>> Publisher.objects.order_by('-name')[0]

更改某一指定的列-update()方法

save()方法会更新一行里的所有列。 而某些情况下,我们只需要更新行里的某几列。例如说我们现在想要将Apress Publisher的名称由原来的”Apress”更改为”Apress Publishing”。若使用save()方法,如:

>>> p = Publisher.objects.get(name='Apress')
>>> p.name = 'Apress Publishing'
>>> p.save()

这等同于如下SQL语句:

SELECT id, name, address, city, state_province, country, website
FROM books_publisher
WHERE name = 'Apress';

UPDATE books_publisher SET
    name = 'Apress Publishing',
    address = '2855 Telegraph Ave.',
    city = 'Berkeley',
    state_province = 'CA',
    country = 'U.S.A.',
    website = 'http://www.apress.com'
WHERE id = 52;

在这个例子里我们可以看到Django的save()方法更新了不仅仅是name列的值,还有更新了所有的列。 若name以外的列有可能会被其他的进程所改动的情况下,只更改name列显然是更加明智的。

我们可以调用结果集(QuerySet)对象的update()方法:

>>> Publisher.objects.filter(id=52).update(name='Apress Publishing')

与之等同的SQL语句变得更高效,并且不会引起竞态条件。

UPDATE books_publisher
SET name = 'Apress Publishing'
WHERE id = 52;

更新多个对象

update()方法对于任何结果集(QuerySet)均有效,这意味着你可以同时更新多条记录。

以下将所有Publisher的country字段值由’U.S.A’更改为’USA’:

>>> Publisher.objects.all().update(country='USA')
2

update()方法会返回一个整型数值,表示受影响的记录条数。

删除对象

删除数据库中的对象只需调用该对象的delete()方法:

# 删除id=1的数据
test1 = Test.objects.get(id=1)
test1.delete()

# 另外一种方式
# Test.objects.filter(id=1).delete() 

同样我们可以在结果集上调用delete()方法同时删除所有记录

>>> Publisher.objects.all().delete()
>>> Publisher.objects.all()
[]

删除数据时要谨慎! 为了预防误删除掉某一个表内的所有数据,Django要求在删除表内所有数据时显示使用all()。而一旦使用all()方法,所有数据将会被删除:

>>> Publisher.objects.all().delete()

如果只需要删除部分的数据,就不需要调用all()方法。

>>> Publisher.objects.filter(country='USA').delete()



模型继承

django中的继承有三类;

1.抽象继承

2.多表继承

3.proxy model(代理模型)

抽象继承

第1种情况表示你的父类仅仅是包含了多个子类的相同的字段,是为了重用,不会建表,我们只需要在抽象父类的Meta中设置abstract=True就行。

class Base(models.Model):
    '''
    基类
    '''
    # title = models.CharField(max_length=150, default='')
    title = models.CharField(max_length=150, null=True)
    content = models.TextField(null=True)
    time_stamp = models.DateTimeField(auto_now_add=True, default=timezone.now())
    link = models.URLField(blank=True, verbose_name='url_link')

    class Meta:
        abstract = True
Note:如果在抽象父类和子类中出现相同的字段名字,django会引发异常。


对于内联的Meta类的继承,一般的,父类的Meta类的属性会继承给子类,子类也可以在自己的Meta中重写或者拓展父类的Meta,拓展的话主要是继承父类的Meta:

[python] view plain copy 在CODE上查看代码片 派生到我的代码片
  1. class CommonInfo(models.Model):  
  2.     ...  
  3.     class Meta:  
  4.         abstract = True  
  5.         ordering = ['name']  
  6.   
  7. class Student(CommonInfo):  
  8.     ...  
  9.     class Meta(CommonInfo.Meta):  
  10.         db_table = 'student_info'  
这个时候,父类Meta中的abstract=True是不会传递给子类的,django会将子类的abstract设置为False.除了abstract之外,父类Meta中的db_table也不会继承给子类

在抽象类中使用关系(如外键,多对多关系,一对一关系)时候,肯定会设置related_name,但是子类继承抽象父类的时候,由于父类中的字段会继承给子类,则具有related_name的字段会被多个子类共享的。这样每一个子类的related_name就都一样了,其他模型通过related_name就不能找到正确的子类。

所以要正确设置related_name,related_name中必须包含%(app_label)s 和 %(class)s。如

%(app_label)s表示小写形式的,当前模型所在的,并且已经安装的app的名字

%(class)s表示小写形式的,当前子类的类名字。

在common/models.py,有

[python] view plain copy 在CODE上查看代码片 派生到我的代码片
  1. class Base(models.Model):  
  2.     m2m = models.ManyToManyField(OtherModel, related_name="%(app_label)s_%(class)s_related")  
  3.   
  4.     class Meta:  
  5.         abstract = True  
  6.   
  7. class ChildA(Base):  
  8.     pass  
  9.   
  10. class ChildB(Base):  
  11.     pass  
在rare/models.py,有
[python] view plain copy 在CODE上查看代码片 派生到我的代码片
  1. from common.models import Base  
  2.   
  3. class ChildB(Base):  
  4.     pass  
所以,上面的related_name就是 common_childa_related和 common_childb_related

多表继承

其中父类也是一个django模型,并且也会创建一个数据表,多表继承是django中隐式的一对一关系。例如

[python] view plain copy 在CODE上查看代码片 派生到我的代码片
  1. class Place(models.Model):  
  2.     name = models.CharField(max_length=50)  
  3.     address = models.CharField(max_length=80)  
  4.   
  5. class Restaurant(Place):  
  6.     serves_hot_dogs = models.BooleanField()  
  7.     serves_pizza = models.BooleanField()  
其中虽然 name和address存储在模型Place的表中,但是name和address对于Restaurant也是有效字段
[python] view plain copy 在CODE上查看代码片 派生到我的代码片
  1. >>> Place.objects.filter(name="Bob's Cafe")  
  2. >>> Restaurant.objects.filter(name="Bob's Cafe")  

Restaurant和Place的关系,可以这么说:一个Restaurant一定是一个Place,而一个Place不一定是Restaurant

多表继承中,一般,父类的Meta属性不会继承到子类中,但是,ordering和 get_latest_by是继承的,如果子类不想继承父类的ordering的Meta,则可以手动显式的指定ordering=[]或者任何自己想要的值

多表继承的时候,是隐式的在父类和子类之间建立一个一对一关系,所以有时候,父类与其他类的关系会从父类下移到子类中。如果有多个子类,且子类不在关系中显式地指定related_name字段,django会引发验证错误

[python] view plain copy 在CODE上查看代码片 派生到我的代码片
  1. class Supplier(Place):  
  2.     # Must specify related_name on all relations.  
  3.     customers = models.ManyToManyField(Restaurant, related_name='provider')  

所以,继承父类,一旦子类中有关系,就加上related_name吧

django自动在子类和非抽象父类之间创建一个一对一关系,如果你想控制由子类连接回父类的属性的名字,你可以创建一个一对一关系,然后设置parent_link=True

代理模型
在多表继承中,子类模型会创建一个数据表来存储不在父类模型中的额外字段,但是,如果我们只想改变某个模型的行为方法,而不是添加额外的字段,我们就可以使用

proxy model。代理modelproxy model)会继承父类的属性,并且只是添加一些对属性的操作的自定义方法而已。

[python] view plain copy 在CODE上查看代码片 派生到我的代码片
  1. class MyPerson(Person):  
  2.     class Meta:  
  3.         proxy = True  
  4.   
  5.     def do_something(self):  
  6.         ...zh  

这里,MyPerson没有多创建数据表,MyPerson也是对Person的数据表进行操作,一般的,我们可以把MyPerson当做Person来使用,只是在do_something这个方法略有不同,比如

[python] view plain copy 在CODE上查看代码片 派生到我的代码片
  1. >>> p = Person.objects.create(first_name="foobar")  
  2. >>> MyPerson.objects.get(first_name="foobar")  
  3. <MyPerson: foobar>  

代理模型和原模型的区别如下面:

[python] view plain copy 在CODE上查看代码片 派生到我的代码片
  1. class OrderedPerson(Person):  
  2.     class Meta:  
  3.         ordering = ["last_name"]  
  4.         proxy = True  
这里,OrderedPerson 并不是创建了一个表,而是代理排序方法。也就是说,使用 Person 的检索方法并不会按 last_name 排序,而使用 OrderedPerson 检索出来的结果是按 last_name 排序的。 OrderedPerson 使用与 Person 类一样的检索方法。

OrderPerson返回的queryset自然是Person的,这是当然的。我们不能要求django返回OrderedPerson类的queryset,因为OrderedPerson只是代理而已,又不是真实的数据库表类。

注意的是,proxy model不能继承于抽象类,这是因为代理model是操作连接数据库的,也不能多重继承~因为你多重继承了,代理model就不知道去哪个父类找属性了

如果不指定代理 model manage ,则代理 model 会自动继承父类的 manage 。我们也可以手动设置代理 model manage ,这样,代理模型和父类模型的manage就分开了

为代理模型添加manage有两种方法:

一是直接在代理模型中直接指定manage

[python] view plain copy 在CODE上查看代码片 派生到我的代码片
  1. class NewManager(models.Manager):  
  2.     ...  
  3.   
  4. class MyPerson(Person):  
  5.     objects = NewManager()  
  6.   
  7.     class Meta:  
  8.         proxy = True  
另外一种是当你不想覆盖父类模型中的manage但又想添加额外的manage,我们可以新建一个抽象模型,然后定义其manage,之后继承该抽象模型,如:
[python] view plain copy 在CODE上查看代码片 派生到我的代码片
  1. # Create an abstract class for the new manager.  
  2. class ExtraManagers(models.Model):  
  3.     secondary = NewManager()  
  4.   
  5.     class Meta:  
  6.         abstract = True  
  7.   
  8. class MyPerson(Person, ExtraManagers):  
  9.     class Meta:  
  10.         proxy = True 

[django学习记录-模型继承]

from:http://blog.csdn.net/pipisorry/article/details/45725953


  • 2
    点赞
  • 1
    评论
  • 1
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值