Django模型开发 --python数据库连接
在这一篇博文中,我们将以MySQL数据库为例,先看看不使用Django模型的数据库查询方法,然后开始学习Django的模型。
1. 不使用模型的数据库查询方法
假如我们不采用Django的模型,如何从数据库中获取数据呢?通常的做法就是在视图(View)层中连接数据库,写SQL语句查询数据库,然后把数据渲染给浏览器。在本例的视图中,我们使用了MySQLdb类库(可以从这里获得)来连接MySQL数据库,取回一些记录,将它们提供给模板以显示一个网页代码看起来像下面这样:
# view.py
from django.http import HttpResponse
import MySQLdb
def book_list_view(request):
db = MySQLdb.connect(user=‘me‘, db=‘mydb‘, passwd=‘secret‘, host=‘localhost‘)
cursor = db.cursor()
cursor.execute(‘SELECT name FROM books ORDER BY name‘)
names = [row[0] for row in cursor.fetchall()]
db.close()
return HttpResponse(names)
这个方法可以达成目标,但存在着一些问题:将数据库连接参数硬编码于代码之中。 理想情况下,这些参数应当保存在 Django 配置中;我们不得不重复同样的代码:创建数据库连接、创建数据库游标、执行某个语句、然后关闭数据库;它把我们栓死在MySQL之上。如果过段时间,我们要从MySQL换到PostgreSQL,就不得不使用不同的数据库适配器(例如psycopg而不是MySQLdb),改变连接参数,根据SQL语句的类型可能还要修改SQL。理想情况下,应对所使用的数据库服务器进行抽象,这样一来只在一处修改即可变换数据库服务器。
接下来我们将开始学习Django中的模型,它提供了一种优雅的方法来抽象数据库层面的操作。
2. Django的模型
2.1 数据库配置
假定你已经完成了数据库服务器的安装,并且已经在其中创建了数据库(我是直接装了WAMP,然后启动MySQL服务)。那么只需要在settings.py文件里面设置连接数据库的参数即可,下面是以MySQL为例。
DATABASE_ENGINE = ‘mysql‘
DATABASE_NAME = ‘db_my_database‘
DATABASE_USER = ‘root‘
DATABASE_PASSWORD = ‘123456‘
DATABASE_HOST = ‘127.0.0.1‘
DATABASE_PORT = ‘3306‘
输入下面这些命令来测试你的数据库配置:
from django.db import connection
cursor = connection.cursor()
如果没有显示什么错误信息,那么你的数据库配置是正确的。否则,你就得查看错误信息来纠正错误。详情可参考这里的表5-2。
2.2 创建一个app
Django规定,如果要使用模型,必须要创建一个app。在上一篇中我们创建的是project,project和app的区别就是:一个project包含很多个Django app以及对它们的配置,一个app是一套Django功能的集合,通常包括模型和视图,按Python的包结构的方式存在。下面的语句创建了一个名为books的app,这个目录包含了这个app的模型models.py和视图views.py,它们都是空的。
python manage.py startapp books
2.3 定义模型
下面我们围绕一个关于书的例子来设计数据库。想象一下这样一个最简化的保存书籍信息的数据库:书有“书名”“作者”“出版社”“出版日期”,作者有“名字”“年龄”“Email”,出版社有“名字”“地址”,其中书可以有多个作者(多对多关系),但只能有一个出版社(一对多关系)。
如果你之前接触过数据库,对这些一定不陌生。首先你应该会设计3个表分别表示书、作者、出版社,然后开始着手写创建表的SQL语句(如果你要像我一样偷懒,甚至直接开个Navicat就开始创建表了),接下来就是常见的增删查改,你在你的网站的逻辑中写各种“INSERT INTO”“DELETE”“SELECT”“UPDATE”SQL语句来操作数据库。当网站的规模增长到一定程度,你可能会觉得不断重复写各种SQL语句会显得特别繁琐。下面我们来看看Django是如何定义模型的。
# models.py
from django.db import models
class Publisher(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=50, blank = True) # blank为True表明可空
class Author(models.Model):
name = models.CharField(max_length=30)
age = models.IntegerField()
email = models.EmailField()
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
publication_date = models.DateField()
看着这段代码,你可以这样理解:这里定义的每个类都继承了models.Model,代表数据库中的表;类里面的字段代表数据表中的字段,数据类型则由CharField(相当于varchar)、DateField(相当于datetime)这样显而易见的类加上属性(如max_length限定长度)来定义;表与表之间的关系则由ManyToManyField(多对多)、ForeignKey(外键,一对多)和OneToOneFiled(一对一)来限定。
接下来在settings.py中找到INSTALLED_APPS这一项,如下:
INSTALLED_APPS = (
‘django.contrib.auth‘,
‘django.contrib.contenttypes‘,
‘django.contrib.sessions‘,
‘django.contrib.sites‘,
‘mysite.books‘, # 加上这一句,mysite是project,books是app
)
在命令行中运行python manage.py syncdb
,看到几行“Creating table...”的字样,你的数据表就创建好了。只要你定义了模型的类和字段,Django将全部自动帮你创建好数据库。
syncdb命令是同步你的模型到数据库的一个简单方法。它会根据INSTALLED_APPS里设置的app来检查数据库,如果表不存在,它就会创建它。需要注意的是,syncdb并不能将模型的修改或删除同步到数据库;如果你修改或删除了一个模型,并想把它提交到数据库,syncdb并不会做出任何处理。如果你觉得这很不方便,可以使用一个Django的第三方的app——South——来同步数据库,使用方法可参考这篇文章
3. 常用的数据库操作
下面直接在代码里面注释说明,Django设计的简洁可以让你一看代码就知道怎么通过模型去访问数据库。
from books.models import Publisher
# 先创建对象,然后再save,相当于SQL中的INSERT
p1 = Publisher(name=‘Apress‘, address=‘2855 Telegraph Avenue‘)
p1.save()
# 注意:尽管我们没有在models给表设置主键,但是Django会自动添加一个id作为主键
# 通过objects这个模型管理器的all()获得所有数据行,相当于SQL中的SELECT * FROM
publisher_list = Publisher.objects.all()
for publisher in publisher_list:
# 对每个publisher做处理
# 修改其中一个字段,再save,相当于SQL中的UPDATE(但这里会更新所有列)
p1.name = ‘Apress Publishing‘
p1.save()
# 如果只需要更新一列,可以用update方法,并应用于结果集上更新多个数据
Publisher.objects.all().update(address=‘USA‘)
# 删除掉数据库中的一行,相当于SQL中的DELETE
p1.delete()
# filter相当于SQL中的WHERE,可设置条件过滤结果
p2 = Publisher.objects.filter(name=‘Apress‘) #单条件查询
p2 = Publisher.objects.filter(name=‘Apress‘, address__contains=‘Telegraph‘) # 多条件查询,双下划线表明会进行一些魔术般的操作,contains部分会被翻译成WHERE address LIKE ‘%Telegraph%‘
# 用get来获取单个结果,注意如果没有结果或结果不唯一会抛异常
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."
# 按name字段来排序,相当于SQL中的ORDER BY,如果换成"-name"则是逆序
result = Publisher.objects.order_by("name")
# 上面的方法可以连锁使用
Publisher.objects.filter(country="U.S.A.").order_by("-name")
# 用索引限定数据行数,相当于SQL中的OFFSET 0 LIMIT 2
Publisher.objects.order_by(‘name‘)[0:2]
# 直接通过字段外键来访问数据,这有点类似于SQL中的JOIN
from books.models import Book
publisher_addr = Book.objects.get(id=1).publisher.address
# 对于用"ForeignKey"定义的关系,关系的另一端也能反向追溯回来。通过字段名加_set的方式可以访问到
p = Publisher.objects.get(name=‘Apress Publishing‘)
p.book_set.all()
# 注意到Publisher类里面没有定义book这个字段,但因为定义了外键,Django已经帮我们生成了book_set这个属性
# 多对多和外键工作方式相同,只不过我们处理的是QuerySet而不是模型实例
b = Book.objects.get(id=1).author.all()
# 反向查询还是字段名加_set,例如要查看一个作者的所有书籍
a = Author.objects.get(name=‘Adrian‘)
a.book_set.all()
4. 结语
从上面的介绍可以看到Django的模型已经帮我们干了非常多的事情,比如我们可以通过访问对象的属性和方法来操作数据库,这种技术叫做对象关系映射(ORM,Object Relational Mapping)。本文仅仅介绍了Django模型最基础的部分,其他高级的用法比如增加额外的Manager方法,添加修改数据库字段等应用可以参照这里。虽然Django给我们提供了如此方便的工具,但它还是需要一定的学习成本的,比如以前你简简单单写个SQL语句就可以搞定的事情,现在要转换为对象的思维,然后去定义模型,学习模型的API。而且听别人说,在涉及到比较复杂的数据库查询和优化的时候,ORM会显得力不从心,所幸Django可以支持原始SQL查询(同样请参见上面的链接)。在日常使用和中小型应用中,使用Django的ORM已经游刃有余,毕竟开发效率才是王道。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。