Django学习总结之五-模型

一、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;
注意:

  • 自动生成的表名是app名称( books )和模型的小写名称 ( publisher , book , author )的组合。
  • 我们前面已经提到,Django为每个表格自动添加加了一个 id 主键,你可以重新设置它。
  • 按约定,Django添加 "_id" 后缀到外键字段名。 
  • 外键是用 REFERENCES 语句明确定义的。
  • 这些 CREATE TABLE 语句会根据你的数据库而作调整,这样象数据库特定的一些字段例如:(MySQL),auto_increment(PostgreSQL),serial(SQLite),都会自动生成。integer primary key 同样的,字段名称也是自动处理(例如单引号还好是双引号)。 
sqlall命令并没有在数据库中创建数据表,它只是将CREATE TABLE 命令打印出来,你可以将打印出来的命令复制到数据库客户端执行,但是django提供了更为简洁的提交SQL语句至数据库中的方法:syncdb命令。

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不会做任何操作。即,它只能创建数据库,不会对模型的修改或者删除更新。
4、基本数据访问

运行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>]

  • 首先,导入Publisher模型类, 通过这个类我们可以与包含 出版社 的数据表进行交互。
  • 接着,创建一个`` Publisher`` 类的实例并设置了字段`` name, address`` 等的值。
  • 调用该对象的 save() 方法,将对象保存到数据库中。 Django 会在后台执行一条 INSERT 语句。
  • 最后,使用`` Publisher.objects`` 属性从数据库取出出版商的信息,这个属性可以认为是包含出版商的记录集。 这个属性有许多方法, 这里先介绍调用`` Publisher.objects.all()`` 方法获取数据库中`` Publisher`` 类的所有对象。这个操作的幕后,Django执行了一条SQL `` SELECT`` 语句。
只有在调用save方法之后,才会把数据写入数据库。

如果想一步就写入到数据库中,可以使用下面这种方式:

>>> 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
5、添加模块的字符表现

我们上一段的代码在输出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.')
3
14、删除对象

只需调用对象的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()
[]
这删除的是全部记录。


本文为Eliot原创,转载请注明出处: http://blog.csdn.net/xyw_eliot/article/details/8921991

你可能感兴趣的:(django,python,模型)