Django笔记 —— 模型

时间:2023-01-27 07:04:10

  最近在学习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的数据输入和管理界面。