一、MTV开发模式
M:模型(model),数据存取层,处理与数据相关的所有事务。
T:模板(Template),表现层,处理与表现相关的决定。
V:视图(views),业务逻辑层,该层包含存取模型及调取恰当模板的相关逻辑。 你可以把它看作模型与模板之间的桥梁。
二、数据库配置
打开setting.py 配置文件,找到:
DATABASE_ENGINE = '' DATABASE_NAME = '' DATABASE_USER = '' DATABASE_PASSWORD = '' DATABASE_HOST = '' DATABASE_PORT = ''DATABASE_ENGINE:是数据库引擎,设置如下:
设置 | 数据库 | 数据库引擎 |
postgresql | PostgreSQL | psycopg 1.x版, http://www.djangoproject.com/r/python-pgsql/1/ |
postgresql_psycopg2 | PostgreSQL | psycopg 2.x版, http://www.djangoproject.com/r/python-pgsql/ |
mysql | MySQL | MySQLdb , http://www.djangoproject.com/r/python-mysql/ |
sqlite3 | SQLite | 如果使用Python 2.5+则不需要适配器。 否则就使用 pysqlite , http://www.djangoproject.com/r/python-sqlite/ |
oracle | Oracle | cx_Oracle , http://www.djangoproject.com/r/python-oracle/ |
python2.5以上的版本中已经集成了sqlite,所以不需要安装数据库引擎。
DATABASE_NAME:数据库名称
如果使用sqlite,则指定将数据文件的完整地址。例如:DATABASE_NAME = 'E:/django/mysite/db/data.db'
DATABASE_USER:使用哪个用户连接数据库,如果是sqlite,则留空。
DATABASE_PASSWORD:数据库密码,如果使用sqlite,留空。
DATABASE_HOST:连接哪一台主机的数据库服务器。如果数据库与django安装在同一台机器上留空。如果使用的是sqlite数据库,留空。
此处的 MySQL 是一个特例。 如果使用的是 MySQL 且该项设置值由斜杠( '/' )开头,MySQL 将通过 Unix socket 来连接指定的套接字,例如:
DATABASE_HOST = '/var/run/mysql'.
测试数据库配置:
进入mysite的目录,运行:python manage.py shell
>>> from django.db import connection >>> cursor = connection.cursor()如果没有出现错误信息提示,说明数据库配置成功!
常见的数据库配置错误信息如下:
错误信息 | 解决办法 |
You haven’t set the DATABASE_ENGINE setting yet. | 不要以空字符串配置`` DATABASE_ENGINE`` 的值。 |
Environment variable DJANGO_SETTINGS_MODULE is undefined. | 使用`` python manager.py shell`` 命令启动交互解释器,不要以`` python`` 命令直接启动交互解释器。 |
Error loading _____ module: No module named _____. | 未安装合适的数据库适配器 (例如, psycopg 或 MySQLdb )。Django 并不自带适配器,所以你得自己下载安装。 |
_____ isn’t an available database backend. | 把DATABASE_ENGINE 配置成前面提到的合法的数据库引擎。 |
database _____ does not exist | 设置`` DATABASE_NAME`` 指向存在的数据库,或者先在数据库客户端中执行合适的`` CREATE DATABASE`` 语句创建数据库。 |
role _____ does not exist | 设置`` DATABASE_USER`` 指向存在的用户,或者先在数据库 客户端中执创建用户。 |
could not connect to server | 查看DATABASE_HOST和DATABASE_PORT是否已正确配置, 并确认数据库服务器是否已正常运行 |
1、project和project app的区别
一个project可以包含多个project app 以及对他们的配置,技术上讲,project是提供配置文件,project app是一套django功能的合集,通常包括模型和视图,按照python包结构的形式存在。系统对app有个约定,如果如果使用了django的数据库模型,就必须创建一个django app,模型必须放在app中。
创建方法:
在mysite目录下输入命令:
python manage.py startapp books创建了一个app:books。此时mysite目录下生成了一个books的目录,文档结构为:
books/
__init__.py
models.py
tests.py
views.py
我们需要在python里定义模型,即实现类似于SQL语句的方式,但是如果你修改了模型,也必须修改数据库来保持和模型的同步。
2、第一个模型
我们假定一些概念和关系:
一个作者有姓,有名及email地址。
出版商有名称,地址,所在城市、省,国家,网站。
书籍有书名和出版日期。 它有一个或多个作者(和作者是多对多的关联关系[many-to-many]), 只有一个出版商(和出版商是一对多的关联关系[one-to-many],也被称作外键[foreign key])
下面来创建模型。打开books目录下的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() 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包含了所有必要的和数据库交互的方法。
每个模型相当于一个数据库表,每个属性代表表中的一个字段,属性名就是字段名,他的类型(如CharField)就相当于数据库的字段类型(例如varchar)。例如,Publisher模块就相当于以下这张表:
CREATE TABLE "books_publisher" ( "id" serial 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 );每个数据库表对应着一个类,例外情况是多对多的关系。例如,上表中的Book有个多对多的字段:authors,表明一本书有一个或者多个作者,但是在数据库表中却没有生产authors字段,而是创建了一个额外的表(多对多连接表)来处理书籍和作者之间多对多的关系。
Django还拥有描述URL和Email的字段类型:URLField、EmailField。最后,我们没有显式的为表定义主键,除非你单独指明,,否则django默认会为每一个数据表创建一个自增长的整数主键字段:id
3、模型的安装
1)激活模型
完成以上代码后,我们要在数据库中创建这些表,首先就需要在django项目中激活这些模型。将app添加到配置文件中已安装应用列表中即可实现。
编辑setting.py 文件,找到:INSTALLED_APPS.它是告诉django哪些app处于激活状态。缺省状态如下:
INSTALLED_APPS = ( 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.sites', 'django.contrib.messages', 'django.contrib.staticfiles', # Uncomment the next line to enable the admin: # 'django.contrib.admin', # Uncomment the next line to enable admin documentation: # 'django.contrib.admindocs', )先把前5个用#注释掉(这5个是经常用到的),同时,注释掉MIDDLEWARE_CLASSES的默认设置条目,因为这些条目是依赖于刚才我们刚在INSTALLED_APPS注释掉的apps。然后,添加`` ‘mysite.books’`` 到`` INSTALLED_APPS`` 的末尾,此时设置的内容应该这样:
MIDDLEWARE_CLASSES = ( #'django.middleware.common.CommonMiddleware', #'django.contrib.sessions.middleware.SessionMiddleware', #'django.middleware.csrf.CsrfViewMiddleware', #'django.contrib.auth.middleware.AuthenticationMiddleware', #'django.contrib.messages.middleware.MessageMiddleware', ) INSTALLED_APPS = ( #'django.contrib.auth', #'django.contrib.contenttypes', #'django.contrib.sessions', #'django.contrib.sites', #'django.contrib.messages', #'django.contrib.staticfiles', # Uncomment the next line to enable the admin: # 'django.contrib.admin', # Uncomment the next line to enable admin documentation: # 'django.contrib.admindocs', 'mysite.books', )2)验证模型的有效性
python manage.py validate没有错误,说明模型正常有效。
3)生成CREATE TABLE语句
python manage.py sqlall books其中,books是app的名称。
得到输出结果如下:
BEGIN; CREATE TABLE "books_publisher" ( "id" integer 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 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 NOT NULL PRIMARY KEY, "book_id" integer NOT NULL, "author_id" integer NOT NULL REFERENCES "books_author" ("id"), UNIQUE ("book_id", "author_id") ) ; CREATE TABLE "books_book" ( "id" integer NOT NULL PRIMARY KEY, "title" varchar(100) NOT NULL, "publisher_id" integer NOT NULL REFERENCES "books_publisher" ("id"), "publication_date" date NOT NULL ) ; CREATE INDEX "books_book_22dd9c39" ON "books_book" ("publisher_id"); COMMIT;注意:
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是同步你的模型到数据库的一个简洁的方法。他会根据INSTALLDE_APPS中设置的apps检查数据库,如果数据库不存在就会创建它。但是syncdb命令不会将模型的修改或者删除更新到数据库,如果你删除了一个模型,想把他提交到数据库,syncdb不会做任何操作。即,它只能创建数据库,不会对模型的修改或者删除更新。
运行python manage.py shell 并输入以下内容:
>>> 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>]
如果想一步就写入到数据库中,可以使用下面这种方式:
>>> 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_list5、添加模块的字符表现
我们上一段的代码在输出publisher_list时并没有输有用的信息,要想解决这个问题,只需要为Publisher对象添加一个__unicode__()方法。__unicode__()方法将告诉python如何将对象以unicode的方式显示出来。为以上3个模型都添加__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 __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
Publisher返回的是出版社的名称,Book返回的是书名,Author返回的是first_name和last_name以空格连接后的字符串。我们可以使用__unicode__()方法进行任何处理来返回一个对象的字符串表示。以后要确保每一个模型都要有__unicode__()方法。
关闭shell打开的窗口,重新打开:python manage.py shell执行:
>>> from books.models import Publisher >>> publish_list = Publisher.objects.all() >>> publish_list [<Publisher: Apress>, <Publisher: O'Reilly>]这时,输出的是出版社的名称。
注意:在书写def __unicode__()的方法的时候,一定不要用tab键将def和上边的字段对齐,而是使用空格,一个空格一个空格的去对齐,否则运行:python manage.py shell总是报错!!
6、插入更新数据
插入数据的过程就是创建模型对象实例的过程。
>>> p = Publisher(name = 'xyw', ... address = '2855 Telegraph Avenue', ... city = 'China', ... state_province = 'SD', ... country = 'C.N', ... website = 'www.baidu.com')再使用save()方法将数据插入到数据库。
p.save()
其实在插入数据的同时,django会计算id的值,并将其赋值给新创建的对象。
>>> p.id 3更新数据:
>>> p.name = 'scy' >>> p.save()目前p指向的是刚刚插入的数据,如果想更改该对象的name属性值由xyw改为scy,可以使用上边的方法。但是,值得注意的是,这种修改方法等价于:
UPDATE books_publisher SET name = 'scy', address = '2855 Telegraph Ave.', city = 'China', state_province = 'SD', country = 'C.N', website = 'http://www.baidu.com' WHERE id = 3;即,程序不仅仅修改name,而是更新了全部的字段,这可能引起竞态条件(从多进程间通信的角度来讲,是指两个或多个进程对共享的数据进行读或写的操作时,最终的结果取决于这些进程的执行顺序),而我们想实现的状态是:
UPDATE books_publisher SET name = 'scy', WHERE id = 3;为了避免这种更新全部字段的方法,我们使用如下这种方式:
>>> Publisher.objects.filter(id = '3').update(name = 'xyw') 1返回的是受影响的行数。
7、选择对象
即查询表中所有的数据
Publisher.objects.all()Publisher:即要查询的模型的名称;
objects:称为“管理器”,它管理着所有数据包含、数据查询的表格级操作,每个模型都自动有一个objects管理器。
all:all()方法返回数据表中所有记录,是一个QuerySet对象。
它相当于:
SELECT id, name, address, city, state_province, country, website FROM books_publisher;它没有使用SELECT * ,而是显示的列出来了所有字段。因为SELECT * 会更慢,而且这遵循了python届的一个信条:明言胜于暗示
>>> p = Publisher.objects.all() >>> p [<Publisher: Apress>, <Publisher: O'Reilly>, <Publisher: xyw>] >>> p[0] <Publisher: Apress> >>> p[0].id 1 >>> p[0].name u'Apress' >>> p[0].address u'2855 Telegraph Avenue'8、数据过滤
即选择性查询
使用filter方法进行过滤
>>> Publisher.objects.filter(address = '2855 Telegraph Avenue') [<Publisher: Apress>, <Publisher: xyw>]相当于:
SELECT id, name, address, city, state_province, country, website FROM books_publisher; WHERE address = '2855 Telegraph Avenue'2)传递多个过滤参数
>>> Publisher.objects.filter(address = '2855 Telegraph Avenue', country = 'U.S.A') [] >>>在SQL中相当于使用AND连接查询条件:
SELECT id, name, address, city, state_province, country, website FROM books_publisher; WHERE address = '2855 Telegraph Avenue' AND country = 'U.S.A'3)模糊查询
“=”是精确匹配的,要实现模糊查询可以使用:属性名__contains =
注意:是双下划线
>>> Publisher.objects.filter(website__contains = 'http') [<Publisher: Apress>, <Publisher: O'Reilly>] >>>相当于:
SELECT id, name, address, city, state_province, country, website FROM books_publisher; WHERE website LIKE '%http%';其他的一些查找类型有:icontains(大小写无关的LIKE),startswith和endswith, 还有range(相当于SQL中BETWEEN查询)。
>>> Publisher.objects.filter(website__startswith = 'http') [<Publisher: Apress>, <Publisher: O'Reilly>] >>> Publisher.objects.filter(website__endswith = 'com') [<Publisher: xyw>]9、获取单个对象
上边的filter返回的是一个记录集,这个记录集是一个列表,有时候我们需要获得单个对象,使用get方法:
>>> Publisher.objects.get(name = 'xyw') <Publisher: xyw>如果结果是多个对象或者没有返回结果,都会抛出异常 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."10、排序
可以对任意的字段使用order_by方法进行排序(按字母顺序):
>>> Publisher.objects.order_by('city') [<Publisher: Apress>, <Publisher: O'Reilly>, <Publisher: xyw>] >>> Publisher.objects.order_by('address') [<Publisher: O'Reilly>, <Publisher: Apress>, <Publisher: xyw>]2)多字段排序
第二个字段会在第一个字段的值相同的情况下被使用到。
>>> Publisher.objects.order_by('country', 'address') [<Publisher: xyw>, <Publisher: O'Reilly>, <Publisher: Apress>]3)逆向排序
在字段名前加一个减号-
>>> Publisher.objects.order_by('-address') [<Publisher: Apress>, <Publisher: xyw>, <Publisher: O'Reilly>]4)在model文件中指定缺省排序方式
我们建立模型的时候可以指定默认的排序方式,当使用django的数据库API去检索时,除非指定order_by排序,否则都会按照缺省的排序方式返回结果。
修改books下的models文件:
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 Meta: ordering = ['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 Meta: ordering = ['first_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 class Meta: ordering = ['title']注意:如果 class Publisher 是顶格的,那么 class Meta 在它之下要缩进4个空格--按 Python 的传统 。保存完毕后,重启shell。
11、连锁查询
即同时进行查询和排序
>>> Publisher.objects.filter(country = 'U.S.A.').order_by('-name') [<Publisher: O'Reilly>, <Publisher: Apress>]相当于:
SELECT id, name, address, city, state_province, country, website FROM books_publisher WHERE country = 'U.S.A' ORDER BY name DESC;12、限制返回数据条数
即,取出固定数目的记录。
>>> Publisher.objects.all().order_by('name')[0:2] [<Publisher: Apress>, <Publisher: O'Reilly>]相当于:
SELECT id, name, address, city, state_province, country, website FROM books_publisher ORDER BY name LIMIT 0, 2;注意:不支持负索引。如果想查询倒数后几条数据,可以配合order_by添加减号-使用
>>> Publisher.objects.order_by('-name')[0:2]13、更新多个对象
在第6条讲过更新数据的问题。可以实现对单条数据的更新。
update()方法对于任何结果集(QuerySet)均有效,这意味着你可以同时更新多条记录。以下示例演示如何将所有Publisher的country字段值由’U.S.A’更改为’USA’
>>> Publisher.objects.all().update(country = 'U.S.A.') 314、删除对象
只需调用对象的delete()方法即可。
>>> p = Publisher.objects.get(name = 'xyw') >>> p.delete() >>> Publisher.objects.all() [<Publisher: Apress>, <Publisher: O'Reilly>]也可以在结果集上调用delete()方法,同时删除多条记录:
>>> Publisher.objects.all().delete() >>> Publisher.objects.all() []这删除的是全部记录。