最近在学习Django,打算玩玩网页后台方面的东西,因为一直很好奇但却没怎么接触过。Django对我来说是一个全新的内容,思路想来也是全新的,或许并不能写得很明白,所以大家就凑合着看吧~
本篇笔记(其实我的所有笔记都是),并不会过于详细的讲解。因此如果有大家看不明白的地方,欢迎在我正版博客下留言,有时间的时候我很愿意来这里与大家探讨问题。(当然,不能是简简单单就可以百度到的问题-.-)
我所选用的教材是《The Django Book 2.0》,本节是模型部分,对应书中第五章。
------------------------------------------------------------------------------------------------------------------------------------------------
-2、数据库安装
要学习这一章,必须要安装数据库。
我选用的数据库是MySQL,关于其安装,我专门写了一篇博文:Django笔记 —— MySQL安装。
-1、数据库入门
你还需要掌握数据库的基本使用。
本来想也写篇简介的,不过临近期末比较忙,拖了好几天了,就先暂时不写了。
先推荐一个同学的博客,有机会我再补上自己的吧:mysql数据库安装及使用
0、代码示例
本节无需开篇给出代码 ^.^
1、MTV开发模式
前面介绍过MVC开发模式,这里回顾一下:
Model,模型,数据存取部分,由Django数据库层处理,本章要讲述的内容。
View,视图,选择哪些数据要显示以及怎样显示的部分,由视图和模板处理。
Controller,控制器,根据用户输入调用视图的部分,由Django根据URLconf设置,对给定URL调用适当的Python函数。
Django遵循MVC开发模式,因此Django可以被成为MVC框架。你可以和并不懂Django的同事说:“我们用MVC模式开发吧~”,以便交流。
对于Django内行来说,Django也被称为MTV模式:
Model,模型,即数据存取层。该层处理所有与数据相关的事:如何存取、如何验证有效性、包含哪些行为、数据之间的关系……
Template,模板,即表现层。该层处理与表现相关的决定:如何在页面或其它类型文档中进行显示。
View,视图,即业务逻辑层。该层处理前两层:包含存取模型及调取恰当模板的相关逻辑。
显然,这种描述是为Django量身定做的,模型处理数据、模板处理显示,而视图则作为两者的桥梁。
2、什么是模型
之前我们学过模板,知道它是如何处理网页内容显示的;也学过视图中调用模板的部分。那么,什么是模型呢?
简单说,就是在Python中搞了个库,库里有很多专门的类和操作函数。我们可以通过这个库,去操作数据库。这个库我们称之为模型。
对数据库有一些了解的同学会知道,每个数据库都有其自己的一些语句去操作。在数据库中直接使用其语言操作,这才是最直接的方式。而所谓用模型去操作数据库,说白了,就是模型自动用你提供的用户登录,找到你要操作的数据库,把你写的模型中定义的一套语言,转换为对应的数据库语言并运行,从而操作数据库。
很显然,这样绕了个圈子。不仅操作数据库多了一步,还要注意维护数据的同步。模型里面数据有变化,必须得注意同步到数据库里才行。
既然我们绕这么个圈子,就肯定说明这个圈子绕得有好处。好处在哪儿呢?
好处 |
省去扫描数据库时严重的系统过载; 省去编程时Python与SQL两种代码不断切换的繁琐; 可以拓展出数据库中没有的高级数据结构,带来更高的效率和更好的代码复用; 没有不同数据库平台(如MySQL、PostgreSQL、SQLite……)的兼容问题。 |
坏处 | 数据同步存在两处,需要随时同步且会生成大量冗余数据。 |
备注 | Django提供了从现有数据库表中自动扫描生成模型的工具,这对现成的数据库很实用,第十八章会讨论。 |
表中说得很清楚了,这里只再解释一点,关于“扫描数据库时严重的系统过载”:
在数据库中执行存取等操作,都需要扫描数据库,这是很费时间的。而直接对数据库操作时,显然我们每次操作都需要扫描数据库,这对于网站来说,根本无法接受。
而通过模型,我们可以在Python代码里面存取修改,然后只在需要的时候接触数据库,做存取等操作;至于平时,则完全可以只在Python代码里搞数据,这样就把严重的系统过载省去了。
3、模型代码示例
下面来看一段代码:
from django.db import models # Create your models here. 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() class Author(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=40)
email = models.EmailField() class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
publication_date = models.DateField()
以上代码是对一个数据库的设置,下面一一解释:
1. 三个类(Class),创建了三个SQL表格(Table),一个类叫做一个模型
2. 以Publisher模型为例,创建了6个属性(即表格中的字段,也就是列),属性名就是字段名,属性类型就是字段类型,括号中参数则是对字段的设置
3. 例如CharField,就对应MySQL中的varchar;而这里的属性数据类型比MySQL中要多,很多是扩充的,例如这里Publisher中的网址类型、Author中的邮箱类型、Book中的日期类型
4. Book模型中有一个ForeignKey类型,和Publisher类连起来了,表示Publisher是Book的外键,外键是一对一的关系,即一本书只有一个出版社,一个出版社也只能出版一本书
5. Book模型中还有一个ManyToMany类型,和Author连起来了,建立了多对多的关系,一本书可以有多个作者,一个作者也可以写很多书
6. 外键很特殊,后面会详细解释
7. 这里要实现一组多对多的关系,Django会偷偷创建一个class(即表格),专门存这组关系
8. 每个模型必须有单独的主键,我们这三个模型都没定义主键,因此Django会自动为每个模型生成一个自增长的整数主键字段,名叫 id
这,就是一个模型的定义。
你可以看到,这就相当于对一个数据库完全定义出来了;后面,就只剩下对它的使用了。
注:附录B中列出了所有的字段类型和模板语法选项。
4、模型安装
这里先给出安装模型的步骤,后面再详细解释。
大家跟我来做:
1. 创建一个project,名叫five:django-admin.py startproject five
2. 创建一个app,名叫books:python manage.py startapp books
3. 在settings.py中设置好数据库:见开头 “-2 数据库安装” 那篇博文里面的 “5 在Django中设置”
4. 在settings.py中设置好app:把 INSTALLED_APPS 和 MIDDLEWARE_CLASSES 中所有内容注释掉,然后在 INSTALLED_APPS 中加入 'books'
5. 至此,设置已经完毕。下面写app中模型内容:写好models.py,代码如前面 “模型示例” 中所示
5+. 写好之后,你可以用这个命令检查一下语法(可略):python manage.py check
5++. 然后,你可以试试写入这个命令(这命令现在没用,只是让你试试看而已):python manage.py migrate
6. 现在你应该知道,我们缺少migration,所以用刚才咱们写的models.py来生成:python manage.py makemigrations books
6+. 现在,你可以试试写入这个命令(也没用,只是打印出来models.py对应的数据库内容,供你检查):python manage.py sqlmigrate books 0001
7. 生成了migration,现在再运行 5++ 的命令就有用了:python manage.py migrate
至此,模型已经生成并与数据库连接完毕,可以使用了。
5、模型常用API
模型的API有很多,这里仅仅列出常用的。
每个模型都有一个objects属性,被称为管理器,里面包含了所有对数据库的表格级操作。这里给出objects的一些用法:
代码(模型名为MM) | 解释 | 备注 |
from AppName.models import MM | 从app中导入MM模型(本篇文章中app的名字是'books') | |
MM.objects.all() | 返回MM中所有的记录 |
返回类型是QuerySet, 是Django定义的一个类似列表的类 |
MM.objects.filter(name='A', country='ZG') | 返回MM中所有 name=='A' && country=='ZG' 的记录 | |
MM.objects.filter(name__contains='press') |
返回MM中所有 name中含有press子串 的记录 类似的双下划线“魔术”操作还有: icontains(不区分大小写的contains) startswith、endswith range(自己猜猜呗~对应SQL的between查询) 附录C描述了所有查找类型 |
|
MM.objects.get(name='A') | 返回MM中 name=='A' 的那个对象 |
返回单独一个对象 如果满足条件的对象数不为1 则报错,错误信息有两种 MM.MultipleObjectsReturned MM.DoesNotExist 当然,你可以捕获这个异常, 捕获的名字就是上面写的那样 |
MM.objects.order_by("name", "address", "-country") |
对MM中所有记录排序,排序方式如下: 第一关键字:name 升序 第二关键字:address 升序 第三关键字:country 降序 |
返回类型是QuerySet,类似列表 |
MM.objects.filter(country='ZG').order_by('name') |
链式语法,含义显而易见: 找到MM中所有country=='ZG'的记录, 按照name升序排列 |
|
MM.objects.order_by('name')[0] MM.objects.order_by('name')[0:2] |
显示部分数据: 把MM中所有记录按name升序排列, 第一句仅返回其第1个;第二句仅返回其前两个。 |
并不支持负索引。 当然,你可以通过'-name'来实现~ |
MM.objects.filter(name='A').update(name='App') MM.objects.all().update(country='China') |
仅更新某个字段: 第一句,把MM中name=='A'的所有记录改为name=='App'; 第二句,把MM中所有记录改为country=='China'。 |
注意,update()会返回一个整数值 表示更新的记录条数 |
MM.objects.get(name='B').delete() MM.objects.all().delete() |
删除记录: 第一句,把MM中name=='B'的那一条删掉; 第二句,把MM中所有记录删掉。 |
注意,第二句慎用! |
另外,在模型内部还有一些可以设置的属性,举出两例:
代码(在models.py中MM类内书写) | 解释 |
__unicode__(self): return self.name |
设定被查看时默认输出的信息: name属性的值 |
class Meta: ordering = ['name'] |
设定检索返回值的默认排序方式: 按照name升序排列 附录B中有Meta中所有参数 |
5+、API使用示例
我们是在学习,因此让我们在交互界面中使用模型:
0. 打开shell:python manage.py shell
1. 导入Publisher模型,创建两条数据并保存:
>>> from books.models import Publisher
>>> p1 = Publisher(name='A', address='Aaddr',
... city='Acity', state_province='Asp', country='ZG',
... website='http://www.aweb.com/')
>>> p1.save()
>>> p2 = Publisher.objects.create(name='B', address='Baddr',
... city='Bcity', state_province='Bsp', country='ZG',
... website='http://www.bweb.com/')
>>> list = Publisher.objects.all()
>>> list
[<Publisher: Publisher object>, <Publisher: Publisher object>]
代码很清晰,p1是创建然后保存进数据库的,p2则是直接创建并保存至数据库。
但最后输入list无法看到内容,这是因为模型中没写如何输出。
2. 在models.py中三个模型内添加__unicode__()函数:
# add to class Publisher
def __unicode__(self):
return self.name # add to class Author
def __unicode__(self):
return u'%s %s' % (self.first_name, self.last_name) # add to class Book
def __unicode__(self):
return self.title
这时候,重新打开shell(python manage.py shell)再查看list,就能看到友好的输出了:
>>> from books.models import Publisher
>>> list = Publisher.objects.all()
>>> list
[<Publisher: A>, <Publisher: B>]
这里顺带提一句,python中编码统一采用unicode,虽然慢点,但作为脚本语言,这样省去很多麻烦,绝对值得。
关于unicode的知识,原书中做了简单介绍,并且推荐了一个很好的网站供大家深入学习。我简单看了看,这个网站挺不错的,在这里同样推荐给大家。
后面,再写示例也是不断使用上面的一条条语句了,这里就不再赘述。
故此,示例部分到此结束。
6、存疑与致歉
这里存下一个小疑问:app中有一个admin.py,里面的备注写着让我在这里注册模型。而我并未注册,却仍可以正常使用模型,那么这个文件有何用处呢?
另外,就是我在这里向关注我博客的同学说声抱歉!最近临近期末,这篇博文拖了很长时间,而且写得并不完善,有失水准,大家凑活着看吧。
------------------------------------------------------------------------------------------------------------------------------------------------
至此,模型部分介绍完毕。
下一篇介绍Django的管理界面——一个基于Web的数据输入和管理界面。