django模型
用django时,只要用到数据库就得用到模型。
一、数据库的MTV开发模式
从MVC到MTV
所谓软件架构的MVC模式将数据的存取逻辑(Module),表现逻辑(View)和业务逻辑(Controller)分开,降低耦合。
Module代表数据库的存取,View代表系统中选择显示什么和怎样显示,Controller指系统根据用户输入访问模型以决定使用哪个视图。
django设计同样鼓励松耦合。
django中的MTV模式也是一种MVC框架。
M:django中模型,负责数据存取。
V:由django视图和模板控制那些数据要显示已经怎样显示。
C:由django框架根据URLconf控制URL调用python函数,由框架自行处理。
所以对开发人员来说更关注模型,模板和视图,就演变成了M(Model)T(Template) V(Views)。
二、数据库连接
首先在settings.py文件进行数据库的配置。
DATABASES = {
'default': {
'ENGINE': 'mysql', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
'NAME': 'dbname', # Or path to database file if using sqlite3.
'USER': 'stack', # Not used with sqlite3.
'PASSWORD': 'password', # Not used with sqlite3.
'HOST': 'x.x.x.x', # Set to empty string for localhost. Not used with sqlite3.
'PORT': '', # Set to empty string for default. Not used with sqlite3.
'OPTIONS': {
'charset': 'utf8',
'use_unicode': True, },
}
}
配置好数据库,可以使用python manage.py shell进行测试,不报错说明配置可用。
>>> from django.db import connection
>>> cursor=connection.cursor()
>>>
三、创建数据库模型APP
django中一个项目可以包含多个app,项目中对这些app进行配置,配置数据库连接,app列表,模板路径等。
一个app包括独立的功能,可复用,它包括独立的模型,视图。
现在在mysite这个项目里创建一个books模型。
liuxiaoyan@development:~/mysite$ python manage.py startapp books
liuxiaoyan@development:~/mysite$ ls
books __init__.py __init__.pyc manage.py settings.py settings.pyc urls.py urls.pyc views.py views.pyc
Django有专用的字段类型来描述Email地址、URL。好处就是高级的数据类型带来更高的效率和更好的代码复用。
Django有工具从现有数据库表自动生成模型。
先提醒一点,要非常注意模型和数据库的同步问题。修改了一个Django模型,要手动修改数据库来保证和模型同步。
四、从模型生成数据库
接下来使用django的模型。从一个例子开始,例子如下:
- 一个作者有姓、名和Email地址。
- 出版商有名称、地址,所在城市、省,国家,网站
- 书籍有书名和出版日期。书和作者是多对多的关联关系[many-to-many],出版商和书是一对多的关联关系[one-to-many],也被称作外键[foreign key]
1、建好模型
liuxiaoyan@development:~/mysite/books$ cat models.py
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()
解释:每个数据模型都是django.db.models.Model的子类。它的父类Model包含了所有必要的和数据库交互的方法,并提供了一个简洁的定义数据库字段的语法。
*python在类名后用一对圆括号表示继承关系, 括号中的类表示父类
模型和表一一对应,属性和表的字段一一对应。属性名就是字段名,类型是数据库的字段类型。
2、模型安装
第一步,在settings.py文件的INSTALLED_APPS加入该APP。
MIDDLEWARE_CLASSES中的中间件依赖于INSTALLED_APPS的条目。
在INSTALLED_APPS中增加'mysite.books'元组。
INSTALLED_APPS = (
# 'django.contrib.auth',
# 'django.contrib.contenttypes',
# 'django.contrib.sessions',
# 'django.contrib.sites',
'books', #注意加上引号和这个逗号
)
第二步,创建数据库表
首先检测模型有效性
liuxiaoyan@development:~/mysite$ python manage.py validate
0 errors found
打印创建数据库表的语句
liuxiaoyan@development:~/mysite$ python manage.py sqlall books
BEGIN;
CREATE TABLE `books_publisher` (
`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
`name` varchar(30) NOT NULL,
`address` varchar(50) NOT NULL,
`city` varchar(60) NOT NULL,
`state_province` varchar(30) NOT NULL,
`country` varchar(50) NOT NULL,
`website` varchar(200) NOT NULL
)
;
CREATE TABLE `books_author` (
`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
`first_name` varchar(30) NOT NULL,
`last_name` varchar(40) NOT NULL,
`email` varchar(75) NOT NULL
)
;
CREATE TABLE `books_book_authors` (
`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
`book_id` integer NOT NULL,
`author_id` integer NOT NULL,
UNIQUE (`book_id`, `author_id`)
)
;
ALTER TABLE `books_book_authors` ADD CONSTRAINT `author_id_refs_id_9e7e386` FOREIGN KEY (`author_id`) REFERENCES `books_author` (`id`);
CREATE TABLE `books_book` (
`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
`title` varchar(100) NOT NULL,
`publisher_id` integer NOT NULL,
`publication_date` date NOT NULL
)
;
ALTER TABLE `books_book` ADD CONSTRAINT `publisher_id_refs_id_c5b274bb` FOREIGN KEY (`publisher_id`) REFERENCES `books_publisher` (`id`);
ALTER TABLE `books_book_authors` ADD CONSTRAINT `book_id_refs_id_cfbcf262` FOREIGN KEY (`book_id`) REFERENCES `books_book` (`id`);
CREATE INDEX `books_book_22dd9c39` ON `books_book` (`publisher_id`);
COMMIT;
sqlall只是打印出SQL语句,没有在数据库创建表。
创建表
liuxiaoyan@development:~/mysite$ python manage.py syncdb
Creating tables ...
Creating table books_publisher
Creating table books_author
Creating table books_book_authors
Creating table books_book
Installing custom SQL ...
Installing indexes ...
No fixtures found.
syncdb同步INSTALLED_APPS的模型到数据库,这个同步是指检查表是否存在,不存在就创建,但是不能将模型的修改或删除同步到数据库。
所以再次提醒修改了一个Django模型,要手动修改数据库来保证和模型同步。
五、基本数据访问
1、增
liuxiaoyan@development:~/mysite$ python manage.py shell
Python 2.7.3 (default, Feb 27 2014, 19:58:35)
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from books.models import Publisher
>>> p1 = Publisher(name='Apress', address='2855 Telegraph Avenue',city='Berkeley', state_province='CA', country='U.S.A.',website='http://www.apress.com/')
>>> p1.save()
>>>
调用django model API创建的对象必须通过save()插入数据库。
如果要一步完成对象的创建和存储到数据库,就使用管理器的creae方法,即“object.creae()”。
>>> from books.models import Publisher
>>> 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_list = Publisher.objects.all()
>>> publisher_list
[<Publisher: Publisher object>, <Publisher: Publisher object>]
>>>
2、删
在对象上调用delete()方法
删除一条数据
>>> p = Publisher.objects.get(name="O'Reilly")
>>> p.delete()
删除一部分数据
找到某几个要删除的结果集,然后delete
>>> Publisher.objects.filter(country='USA').delete()
全部删除
为预防错误,全部删除需要显示调用all()然后调用delete()
>>> Publisher.objects.all().delete()
3、改
赋新值然后调用save()就是更新了,而且是全部字段都更新。
liuxiaoyan@development:~/mysite$ python manage.py shell
Python 2.7.3 (default, Feb 27 2014, 19:58:35)
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from books.models import Publisher
>>> p = Publisher(name='Apress',address='2855 Telegraph Ave.', city='Berkeley',state_province='CA',country='U.S.A.',website='http://www.starof.com/')
>>> p.save()
>>> p.id
5L
>>> p.name = 'lxy'
>>> p.save()
>>> p.id
5L
过程如下:
第一次调用save()方法插入一条记录对应一个主键,把该主键值赋给对象实例p,再次调用save()方法不会创建新记录,而是去更新全部列。这会导致一个问题,比如我要修改name列, 其他进程同时要修改name之外的列,可能会有冲突。所以局部更新比较明智。
局部更新
调用管理器的update方法。相当于updte SQL,即update table set propertie='xxx' where name='xxx'。
>>> Publisher.objects.filter(name='lxy').update(city='wuxi')
1L
>>>
update()可以同时更新多条记录
比如把所有的城市都换成shanghai
>>> Publisher.objects.all().update(city='shanghai')
3L
>>>
4、查
数据库的查询操作都是通过绑定在该模型上的管理器(objects)的相应方法(如all)。
全部查询,返回结果集
用Publisher.objects.all()来取出所有记录,但是并不是select * from table,而是显示列出所有字段。
liuxiaoyan@development:~/mysite$ python manage.py shell
Python 2.7.3 (default, Feb 27 2014, 19:58:35)
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from books.models import Publisher
>>> 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_list = Publisher.objects.all()
>>> publisher_list
[<Publisher: Publisher object>, <Publisher: Publisher object>]
>>>
Note:
模型,这里就是Publisher,通过模型来获得数据。
objects:属性,被称为管理器,所有模型自动拥有管理器属性,管理数据。
部分查询,返回结果集
使用管理器的filter()方法。
>>> Publisher.objects.filter(name="Apress")
[<Publisher: Apress>]
相当where SQL ,即于select * from table where propertie=“xxx”。
给定多个参数相当于and SQL,即select * from table where propertie1="xxx" and propertie2="xxx"
>>> Publisher.objects.filter(country="U.S.A.", state_province="CA")
[<Publisher: Apress>, <Publisher: lxy>]
filter方法还可以使用其他类型查询,用__contains相当于like SQL,即select * from table where name like '%xxx%'
>>> Publisher.objects.filter(name__contains='lx')
[<Publisher: lxy>]
返回单个对象,而非结果集
使用管理器的get()方法。
>>> Publisher.objects.get(name='lxy')
<Publisher: lxy>
要注意的是返回结果集和和没有查询结果都会抛异常。
返回结果集
>>> Publisher.objects.get(city="Berkeley")
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/usr/lib/python2.7/dist-packages/django/db/models/manager.py", line 132, in get
return self.get_query_set().get(*args, **kwargs)
File "/usr/lib/python2.7/dist-packages/django/db/models/query.py", line 367, in get
% (self.model._meta.object_name, num, kwargs))
MultipleObjectsReturned: get() returned more than one Publisher -- it returned 2! Lookup parameters were {'city': 'Berkeley'}
查询没有结果
>>> Publisher.objects.get(name='lxx')
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/usr/lib/python2.7/dist-packages/django/db/models/manager.py", line 132, in get
return self.get_query_set().get(*args, **kwargs)
File "/usr/lib/python2.7/dist-packages/django/db/models/query.py", line 365, in get
% self.model._meta.object_name)
DoesNotExist: Publisher matching query does not exist.
查询结果排序
使用管理器的order_by()方法。相当于order by SQL,即selsect * from table order by properties。
>>> Publisher.objects.all()
[<Publisher: Apress>, <Publisher: O'Reilly>, <Publisher: lxy>]
>>> Publisher.objects.all().order_by("name")
[<Publisher: Apress>, <Publisher: lxy>, <Publisher: O'Reilly>]
>>> Publisher.objects.order_by("name")
如果是根据名字逆向排序就加个减号前缀。
>>> Publisher.objects.order_by("-name")
[<Publisher: O'Reilly>, <Publisher: lxy>, <Publisher: Apress>]
如果不想每次都写order_by,可以在模型里添加Meta类的ordering选项。
class Meta:
ordering=['name']
连接查询
过滤和排序查询,用“链式”操作。类似where和order by的组合,即select * from table where properite='xxx' order by xxx。
>>> Publisher.objects.filter(country="U.S.A.").order_by("-name")
[<Publisher: O'Reilly>, <Publisher: lxy>, <Publisher: Apress>]
>>>
限制查询结果数量
以下[0]取得第一个结果,相当于limit 1,即selsect * from table order by xxx limit 1。
>>> Publisher.objects.filter(country="U.S.A.").order_by("-name")[0]
<Publisher: O'Reilly>
以下返回两个对象,相当于offset 0 limit 2,即没隔0个的取,总共取2个。
>>> Publisher.objects.filter(country="U.S.A.").order_by("-name")[0:2]
[<Publisher: O'Reilly>, <Publisher: lxy>]
不管是使用get(),filter(),还是all(),不管得到的是单个记录,还是记录集,得到后,就是类似在之前的模型中定义的类的实例对象,此时,就可以进行取出实例的其他字段的数据,或者进行在模型类中定义的其他逻辑函数的操作了。
5、按我们的需要显示查询信息
普通情况下list结果都是类似:
>>> publisher_list
[<Publisher: Publisher object>, <Publisher: Publisher object>]
>>>
我们想看点详细的信息,或者特定的信息,就给模型对象添加一个方法__unicode__(),类似java中的toString()方法。
liuxiaoyan@development:~/mysite/books$ cat models.py
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
要使__unicode__()方法生效,退出python shell,然后再次运行python manage.py shell进入即可,不需要同步数据库,现在就可以看到想看的内容了。
liuxiaoyan@development:~/mysite$ python manage.py shell
Python 2.7.3 (default, Feb 27 2014, 19:58:35)
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from books.models import Publisher
>>> publisher_list = Publisher.objects.all()
>>> publisher_list
[<Publisher: Apress>, <Publisher: O'Reilly>]
>>>
6、添加行为到模型
和添加__unicode__()一样。
Django模型不只为对象定义了数据库表的结果,还定义了对象的行为。新添加的__unicode__()方法就是告诉模型怎样显示自己。
六、访问外键值
前面提到出版商和书是一对多的关系,即一本书只有一个出版商。在Book模型定义中可以看出
publisher = models.ForeignKey(Publisher)
出版社是以书的外键存在的。
1、通过多端访问一端
可以通过书来访问出版社,间接访问出版社的名字,地址,网站等各种属性。
liuxiaoyan@development:~/mysite$ python manage.py shell
Python 2.7.3 (default, Feb 27 2014, 19:58:35)
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from books.models import Book
>>> b=Book.objects.get(id=1)
>>> b.publisher
<Publisher: Apress>
>>> b.publisher.website
u'http://www.apress.com/'
>>> b.publisher.address
u'2855 Telegraph Avenue'
>>>
2、通过一端访问多端
通过一个出版社可以获取该出版社出版的所有书,或者可以通过关键字查询该出版社出版的符合某条件的书。
>>> from books.models import Publisher
>>> p=Publisher.objects.get(name="Apress")
>>> p.book_set.all()
[<Book: 《平凡的世界》>, <Book: 《说话之道》>]
>>> p.book_set.filter(title__icontains='平凡')
[<Book: 《平凡的世界》>]
>>>
这里用到一个book_set,通过一个“publisher”对象,直接获取books,用publisher.book_set.all()。这里的book_set是一个QuerySet,所以可以进行数据过滤。而book_set这个属性则是由模型名称的小写加_set组成的。
七、访问多对多值
多对多和外键的工作方式相同,但是处理的都是QuerySet而不是模型实例。
1、通过Book访问作者
查看一本书的所有作者,
liuxiaoyan@development:~/mysite$ python manage.py shell
Python 2.7.3 (default, Feb 27 2014, 19:58:35)
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from books.models import Book
>>> b=Book.objects.get(id='')
>>> b.authors.all()
[<Author: xiaoyan liu>, <Author: yao lu>]
>>> b.authors.filter(first_name="yao")
[<Author: yao lu>]
>>>
2、通过Author访问Book
查看一个作者的所有书,使用author.book_set
>>> from books.models import Author
>>> a=Author.objects.get(first_name='yao',last_name='lu')
>>> a.book_set.all()
[<Book: 童年>, <Book: 《平凡的世界》>]
>>>
和外键一样,这里属性名book_set,是在数据模型后面追加_set。
资源链接:
http://djangobook.py3k.cn/2.0/chapter05/
http://djangobook.py3k.cn/2.0/chapter10/
django模型的更多相关文章
- Django模型层Meta内部类详解
Django 模型类的Meta是一个内部类,它用于定义一些Django模型类的行为特性.以下对此作一总结: abstract 这个属性是定义当前的模型类是不是一个抽象类.所谓抽象类是不会对应 ...
- 【Python】django模型models的外键关联使用
Python 2.7.10,django 1.8.6 外键关联:http://www.bubuko.com/infodetail-618303.html 字段属性:http://www.cnblogs ...
- django模型中的抽象类(abstract)
首先介绍下django的模型有哪些属性:先看例子: Django 模型类的Meta是一个内部类,它用于定义一些Django模型类的行为特性.以下对此作一总结: abstract 这个属性是定义当前的模 ...
- Django模型之Meta选项详解
Django模型类的Meta是一个内部类,它用于定义一些Django模型类的行为特性.而可用的选项大致包含以下几类 abstract 这个属性是定义当前的模型是不是一个抽象类.所谓抽象类是不会对应数据 ...
- Django模型-数据库操作
前言 前边记录的URLconf和Django模板全都是介绍页面展示的东西,也就是表现层的内容.由于Python先天具备简单而强大的数据库查询执行方法,Django 非常适合开发数据库驱动网站. 这篇开 ...
- python django模型内部类meta详细解释
Django 模型类的Meta是一个内部类,它用于定义一些Django模型类的行为特性.下面对此作一总结: abstract 这个属性是定义当前的模型类是不是一个抽象类.所谓抽象类是不会相应 ...
- 第四章:Django 模型 —— 设计系统表
1. Django框架提供了完善的模型(Model )层来创建和存储数据,每一个模型对应数据库中的唯一的一张表. 2. Django 模型基础知识: .每一本模型是一个Python类,继承了djang ...
- Django 模型中自定义Manager和模型方法
1.自定义管理器(Manager) 在语句Book.objects.all()中,objects是一个特殊的属性,通过它来查询数据库,它就是模型的一个Manager. 每个Django模型至少有一个m ...
- 一 Django模型层简介(一)
模型 django提供了一个强大的orm(关系映射模型)系统. 模型包含了你要在数据库中创建的字段信息及对数据表的一些操作 使用模型 定义好模型后,要告诉django使用这些模型,你要做的就是在配置文 ...
随机推荐
- 【循序渐进学Python】6.Python中的函数
1. 创建函数 一个函数代表一个行为并且返回一个结果(包括None),在Python中使用def关键字来定义一个函数,如下: def hello(name): print 'hello,' + nam ...
- R语言-简单线性回归图-方法
目标:利用R语言统计描绘50组实验对比结果 第一步:导入.csv文件 X <- read.table("D:abc11.csv",header = TRUE, sep = & ...
- knockout.js的简介和简单使用
1.knockout简介knockout是一个轻量级的UI类库,通过MVVM模式使JavaScript前端UI简单化knockout有四大重要概念:1)声明式绑定:使用简明移读的语法很容易地将模型(m ...
- 隐藏android系统标题栏和状态栏
//隐藏系统title requestWindowFeature(Window.FEATURE_NO_TITLE); //隐藏状态栏 getWindow().addFlags(WindowManage ...
- Maven创建servlet项目演示(三)
上一节用Maven新建了web项目成功后,本文演示在此基础上应用servlet. 从对tomcat服务器进行配置可的过程中可以知道,tomcat作为servlet容器运行,负责处理客户请求,把请求传送 ...
- Python基础(一),Day1
python的安装 python2.x与3.x的部分区别 第一个python程序 变量 字符编码 注释 格式化字符串 用户输入 常用的模块初始 if判断 循环语句 作业 1.python的安装 可以在 ...
- TeamCity配置笔记
1.编译sln 2.发布网站 3.重复代码检测 4.代码分析 5.单元测试&覆盖率测试 查看代码覆盖率 7.代码签入时自动触发编译 8.通知 1.在teamcity安装目录中找到TrayNot ...
- Linux 学习手记(3):Linux基本的文件管理操作
复制文件和目录 在Linux中使用命令cp来复制文件或者目录,使用方式: cp 源文件(文件夹) 目标文件(文件夹) cp命令常用参数: -r 递归复制整个目录 -v 显示详细信息 移动.重命名一个文 ...
- thinkPHP学习笔记(1)
现在对前端的要求越来越高了 基本上身为一个前端人员需要会一种后台语言,于是选择了当下流行的php.因为是自学对我这个不怎么懂代码的人来说还是有点难度的. 1.先看看thinkphp的目录结构 ├─T ...
- SharePoint Tricks - Survey
1. SharePoint 2010中,在Survey的问题框中输入HTML代码可以用于插入图片或者链接,具体方法为: 1.1 在问题框中输入html, 1.2 在New Form和Edit Form ...