文档章节

Django学习笔记之——Models

临峰不畏
 临峰不畏
发布于 2015/03/06 00:18
字数 1390
阅读 10867
收藏 3

Django里的模型是对数据库对表的一次封装,是应用业务与数据之间的桥梁。


1. 模型的Fields

在上一节,我们在mysite/blog/models.py中创建了BlogPost这个Model。

from django.db import models
class BlogPost(models.Model):
    title = models.CharField(max_length=150)
    body = models.TextField()
    timestamp = models.DateTimeField()

BlogPost里用了CharField,TextField, TextField域。难道就只有这三种,不可能!

如下,我列出了其它的Field,并表明了它们的继承关系:

Field
|--AutoField
|--BooleanField
|--CharField
|  |--EmailField
|  |--SlugField
|  `--URLField
|--DateField
|  `--DateTimeField
|--DecimalField
|--FilePathField
|--FloatField
|--IntegerField
|  |--BigIntegerField
|  |--PositiveIntegerField
|  `--PositiveSmallIntegerField
|--IPAddressField
|--GenericIPAddressField
|--NullBooleanField
|--TextField
|--TimeField
`--BinaryField

别问我是怎么知道的。看源码呀~在 django/db/models/fields/__init__.py 中定义。

如果你是去看了这个文件,那么不难知道 Field类的__init__(self)函数带了很多参数吧。

Field类在构造的时候可以指定以下参数:
verbose_name=None   #显示名
name=None           #域名
primary_key=False   #是否为主键
max_length=None     #在CharFiled中用到
unique=False        #是否唯一
blank=False
null=False          #是否允许为空
db_index=False
rel=None
default=NOT_PROVIDED
editable=True       #是否可编辑
serialize=True
unique_for_date=None
unique_for_month=None
unique_for_year=None
choices=None
help_text=''
db_column=None
db_tablespace=None
auto_created=False
validators=[]
error_messages=None

models.ForeignKey
~~~~~~~~~~~~~~~~~
可以用models.ForeignKey()指定外键,如在models.py中:
_______________________________________________
class Author(models.Model):
    name = models.CharField(max_length=100)

class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.ForeignKey(Author) #定义外键
-----------------------------------------------
注:Author必须在Book之前定义。如果不想有这样的限制,那么在ForeignKey()中以
"Author"字符串对象作为参数传入。
_______________________________________________
class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.ForeignKey('Author') # 注意,这里用的是类名称,而不是类
                                         # 本身
class Author(models.Model):
    name = models.CharField(max_length=100)
-----------------------------------------------

在外键的支持下,可以实现数据库中多表查询的功能。比如查到与该书作者的所有书:
________________________________________________
book_title = "C++程序设计"
this_book = Book.objects.get(title=book_title)  # 找到title为"C++程序设计"
                                                # 的book对象this_book
author = this_book.author   # 由this_book获得作者对象author
books = author.book_set.all()   # 根据author获得所有的书,得到books数组
               ^^^^^^^^
for book in books: # 打印每一本书
    print(book.title)
------------------------------------------------
在Book中加入了ForeignKey('Author')之后,Django会在Author对象中添加一个属性
叫:book_set。
但是,如果用的是ForeignKey('Author', related_name="books"),也就是告诉django
在Author端对应的属性名叫"books",而不再是django默认的"book_set"了。

models.ManyToManyField
~~~~~~~~~~~~~~~~~~~~~~
顾名思意,就是多对多域。当两个表存在多对多的关系时,这就很有用。
比如:一名作者可能写了多本书,一本书也可能由多名作者共同编写。
_______________________________________________
class Author(models.Model):
    name = models.CharField(max_length=100)

class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.ManyToManyField(Author)
-----------------------------------------------
其实,Django为我们建了另一个book_book_author的表。

如下为book_book_author的创建明细:
__________________________________________________________________________
sqlite> .schema book_book_author
CREATE TABLE "book_book_author" (
    "id" integer NOT NULL PRIMARY KEY,
    "book_id" varchar(50) NOT NULL,
    "author_id" integer NOT NULL REFERENCES "book_author" ("id"),
    UNIQUE ("book_id", "author_id")
    );
CREATE INDEX "book_book_author_36c249d7" ON "book_book_author" ("book_id");
CREATE INDEX "book_book_author_e969df21" ON "book_book_author" ("author_id");
--------------------------------------------------------------------------

那么,这种多对多的关系在view中怎么使用呢?

models.OneToOneField一对一关系
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


模型继承关系
~~~~~~~~~~~~
在模型类中定义Meta内部类,并指定Meta.abstract = True时,表示该模型为抽象模型
,即只用来被子模型类派生而不生成实际的模型。
这时,Django在./manage.py syncdb时就不会为该模型创建表。比如:Person为人的模
型,里面定义了人的基本属性。Student与Teacher继承于它。在同步数据库时,我们不
能为Person创建一张表吧。如下:
________________________________________________
class Person(models.Model):
    name = models.CharField(max_length=50)
    gender = models.PositiveSmallIntegerField()
    birthday = models.DateField()

    def __unicode__(self):
        return self.name

    class Meta:
        abstract = True

class Teacher(Person):
    pass

class Student(Person):
    pass
------------------------------------------------
对了,记得给模型定义__unicode__方法。这用利于让admin知道模型对象该怎么显示。

Meta嵌套类
~~~~~~~~~~

在前面有两处提到了Meta类,一处是在blog排序时,另一处就是上面的虚继承。
Meta的用法是嵌套在Model类里面,用于说明附加的信息。

数据查询
~~~~~~~~
每个Model都有一个objects属性,而这个objects属性具有以下方法:
Model.objects.all()       # 获取所有对象的QuerySet
Model.objects.filter()    # 获取满足条件的对象的QuerySet
Model.objects.exclude()   # 获取不满足条件的对象的QuerySet
Model.objects.get()       # 获取单个符合条件的对象的QuerySet

QuerySet会将查询条件转换成SQL语句,并获得执行结果。
示例:
____________________________________________________________
# 找出John Doe
Person.objects.filter(last="Doe").filter(first="John")

# 找出逾期不还的书
today = datetime.now()
overdue_books = book_queryset.filter(due_date__lt = today)
                                             ^^^^
                                 意恩是:due_date < today
# 注:除了__lt,还有:__gt

# 查询结果排序,并提取前5个
all_sorted_first = Person.objects.all().order_by('first')[:5]

# 使用select_related执行简单的join操作
Person.objects.all().select_related('address', depth=1)
-------------------------------------------------------------

用Q()让条件灵活组合
~~~~~~~~~~~~~~~~~~~
使用Q()来封装查询条件,与 & | ~ 配合,形成组合条件。
_______________________________________________________________________
Person.objects.filter(
    Q(last="Doe") |
    (Q(last="Smith") & Q(first="John") & ~Q(middle__startswith="W"))
)

first_names = ['John', 'Jane', 'Jeremy']
first_name_keywords = Q()
for name in first_names:
    first_name_keywords = first_name_keywords | Q(first=name)
specific_does = Person.objects.filter(last="Doe").filter(first_name_keywords)
----------------------------------------------------------------------

用extra()提供其它的功能
~~~~~~~~~~~~~~~~~~~~~~~

## select提供简单数据
# SELECT age, (age > 18) as is_adult FROM myapp_person;
Person.objects.all().extra(select={'is_adult': "age > 18"})

## where提供查询条件
# SELECT * FROM myapp_person WHERE first||last ILIKE 'jeffrey%';
Person.objects.all().extra(where=["first||last ILIKE 'jeffrey%'"])

## table连接其它表
# SELECT * FROM myapp_book, myapp_person WHERE last = author_last
Book.objects.all().extra(table=['myapp_person'], where=['last = author_last'])

## params添参数
# !! 错误的方式 !!
first_name = 'Joe'  # 如果first_name中有SQL特定字符就会出现漏洞
Person.objects.all().extra(where=["first = '%s'" % first_name])
# 正确方式
Person.objects.all().extra(where=["first = '%s'"], params=[first_name])
#                                                ^^^^^^^^^^^^^^^^^^^^^

数据库导入导出
~~~~~~~~~~~~~~
# 将book应用的数据导出到book.json文件中去
./manage.py dumpdata --indent=4 book > book.json

自定义SQL查询
~~~~~~~~~~~~~
如果前面的QuerySet无法满足特殊的查询要求,那就让我们自己来指定select语句吧。
如下:
_______________________________________________________________________
from django.db import connection
cursor = connection.cursor()
cursor.execute("SELECT first, last FROM myapp_person WHERE last='Doe'")
doe_rows = cursor.fetchall()
for row in doe_rows:
    print("%s %s" % (row[0], row[1]))
-----------------------------------------------------------------------


© 著作权归作者所有

共有 人打赏支持
临峰不畏
粉丝 214
博文 187
码字总数 98583
作品 0
深圳
架构师
私信 提问
Django学习笔记之——Start

安装 下载源码文件: Django-1.6.10.tar.gz 解压后生成目录:Django-1.6.10 进入目录 $ sudo python setup.py install 就完成安装了。 2. 创建工程 执行: django-admin.py startproject <工程...

临峰不畏
2015/03/02
0
1
Django学习笔记(2)

Django官方文档里有一个投票Web应用的例子。建立好的目录如下: mysite是project的名字,polls是这个应用。 接下来梳理一下这个应用的数据库和实现。 表结构 在Sqlite3中建立两个表,是投票信...

兔之
2015/09/05
44
0
《Django By Example》笔记(1)

学习网站链接 http://www.jianshu.com/u/390b6edb26a8 第一章 创建一个blog应用 在这本书中,你将学习如何创建完整的Django项目,可以在生产环境中使用。假如你还没有安装Django,在本章的第...

thinkando
2017/11/24
0
0
和lock一起学beego 博客系统开发为例(三)

mongodb: MongoDB(二):基础知识 Django学习笔记:为Model添加Action 和lock一起学beego 博客系统开发为例(三) 深入Go语言 - 1 django captcha imagintft: 关于captcha使用The _imagingft C ...

d_watson
2016/06/16
18
0
python资料全集

python: 微信公众号开发小记——2.80端口上的服务 python: 微信公众号开发小记——3.接入三方登录 使用python编写一个壁纸网站的简单爬虫 python: python List 用法 Python 中各个时间复杂度...

d_watson
2016/04/15
175
0

没有更多内容

加载失败,请刷新页面

加载更多

SRE的含义及与 DevOps 如何关联?

虽然站点可靠性工程师(site reliability engineer SRE)角色在近几年变得流行起来,但是很多人 —— 甚至是软件行业里的 —— 还不知道 SRE 是什么或者 SRE 都干些什么。为了搞清楚这些问题...

linuxCool
5分钟前
0
0
月入3万之一个程序员的转行坎坷历程

陈年往事 “我月入3万,怎么会少少了你一个鸡蛋啊?” 这是2017年9月左右的一个新闻,一位煎饼摊大妈因和顾客争执时脱口而出这样一句话而走红。当时还上了各大新闻的头条。 互联网兴起今天,...

苏南-首席填坑官
27分钟前
1
1
OSChina 周一乱弹 —— 眼看着这颗陨石砸了下来

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @莱布妮子:分享Nachtblut的单曲《Antik》 《Antik》- Nachtblut 手机党少年们想听歌,请使劲儿戳(这里) @mr_chip :上海的初雪之后有点冷 ...

小小编辑
52分钟前
215
7
Confluence 6 修改导航显示选项

选择 子页面(Child pages)来在边栏中查看当前页面的子页面。 选择 页面树(Page tree)来查看整个空间的页面树,扩展当前的页面。 你也可以选择是否完全隐藏导航显示选项或者添加你希望可见...

honeymose
今天
2
0
Ubuntu18.04 安装MySQL

1.安装MySQL sudo apt-get install mysql-server 2.配置MySQL sudo mysql_secure_installation 3.设置MySQL非root用户 设置原因:配置过程为系统root权限,在构建MySQL连接时出现错误:ERROR...

AI_SKI
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部