Python Web框架——Django
使用框架简单快速开发特定的系统。
pip freeze > requirements.txt
pip install -r requirements.txt
一 MVC和MTV模式
二 简介
Django时有Python开发的一个免费的开源网站框架,可以用于快速搭建高性能、优雅的网站。
Django框架的特点:
- 强大的数据库功能
- 自带强大的后台功能
- 通过正则匹配随意定义的网址
- 强大易扩展的模板系统
- 缓存系统
- 国际化
三 Django安装方式
1.利用pip安装Django。
oliver@oliver-G460:~$ sudo pip3 install Django
2.利用源码包安装Django。
oliver@oliver-G460:~$ tar -zxvf django-1.10.xx.tar.gz
解压后进入目录,执行:
python3 setup.py install
3.利用Linux自带源安装Django。
sudo apt-get install python3-django
检查Django是否安装成功:
oliver@oliver-G460:~$ python3
Python 3.5.2 (default, Sep 10 2016, 08:21:44)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import django
>>> django.VERSION
(1, 10, 2, 'final', 0)
如果希望安装不同版本的Django环境,则需要通过virtualenv来管理多个开发环境。
四 Django项目创建
方式一:用命令创建项目和app
1. 创建一个新的Django项目
2. 创建app
python3 manage.py startapp app-name 或 django-admin.py startapp app-name
需要注意的是,通过命令行创建的项目,在settings.py中,如app名称和模板路径及templates目录等信息要自己添加。
方式二:用Pycharm创建
在File→New Project中选择Django,输入项目名称mysite和应用名称myApp,完成创建。
创建完成后, 用Pycharm打开项目,查看项目和app目录文件
- manage.py:用于管理Django站点。
- settings.py:项目所有的配置信息,包含项目默认设置,数据库信息,调试标识以及其它工作变量等。
- urls.py:负责把URL映射到视图函数,即路由系统。
- wsgi.py:内置runserver命令的WSGI应用配置。
五 Django urls(路由系统)
即urls.py文件。其本质是建立url与其所调用的视图函数的映射关系,以此来规定访问什么网址去对应什么内容,执行哪个视图函数。
urlpatterns = [
url(正则表达式,views视图函数,[参数],[别名]),
]
说明(括号中四部分的意义):
- 正则表达式字符串来匹配浏览器发送到服务端的URL网址
- 可调用的视图函数对象。先引入(import)再使用
- 要传给视图函数的默认参数(字典形式)
- name,即别名。HTML中form表单参数action属性值使用此别名后,即便url发生变化,也无需在HTML中批量进行修改。
1 URL配置举例:
from django.conf.urls import url
from django.contrib import admin from app01 import views urlpatterns = [ url(r'^articles/2003/$', views.special_case_2003), #url(r'^articles/[0-9]{4}/$', views.year_archive), url(r'^articles/([0-9]{4})/$', views.year_archive), #no_named group url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive), url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail), ]
用()括起来表示保存为一个子组,每个子组作为一个参数(无名参数),被views.py中的对应函数接收。参数个数与视图函数中的形参个数要保持一致。
(注意:当匹配到第一个url后立即返回,不再向下查找匹配。)
2 带命名的组Named group(?P<>)用法
?P<group_name> 表示带命名的参数,例如:将year='2016'作为一个整体传个视图函数。此处的组名称必须与视图函数中的形参名称一致。由于有参数名称与之对应,所以视图函数有多个形参时,不需要考虑参数的先后顺序。
from django.conf.urls import url from . import views urlpatterns = [
url(r'^articles/2003/$', views.special_case_2003),
url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive), # year=2016
url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail),
]
3 默认参数(可选)
如下所示,如果请求地址为/blog/2016,表示将year='2016',foo='bar'传给视图函数,视图函数中必须有相同名称的形参来接收值。
from django.conf.urls import url
from . import views urlpatterns = [
url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}),
]
4 name别名(可选)
固定用法:
url(r'^/index/',views.index,name='bieming')
如果url中的路径修改为/index2/,对应的模板,甚至还视图中的跳转,以及 models.py 中也可能有获取网址的地方。每个地方都要改,修改的代价很大,一不小心,有的地方没改过来,那个就不能用了。
因此,在需要跳转或获取网址的地方,使用别名设置的名称,以后便可以随意修改url了。
urlpatterns = [
url(r'^index',views.index,name='bieming'),
url(r'^admin/', admin.site.urls),
# url(r'^articles/2003/$', views.special_case_2003),
url(r'^articles/([0-9]{4})/$', views.year_archive),
# url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
# url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail), ]
################### def index(req):
if req.method=='POST':
username=req.POST.get('username')
password=req.POST.get('password')
if username=='alex' and password=='':
return HttpResponse("登陆成功") return render(req,'index.html') ##################### <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{# <form action="/index/" method="post">#}
<form action="{% url 'bieming' %}" method="post">
用户名:<input type="text" name="username">
密码:<input type="password" name="password">
<input type="submit" value="submit">
</form>
</body>
</html> #######################
5 URLconf
一个网站包含成千上万个URL,如果所有的URL映射都放在一个文件下,很可能会出错,也不便与维护。
因此,我们在每个app应用下分别创建一个urls目录,将不同的请求分发给不同app下的urls去匹配,如:对于/blog/index/请求直接交给‘blog.urls’去处理,清晰明确,更方便管理。
六 Django views(视图函数)
http请求中产生的两大核心对象:
http请求:HttpRequest对象
http响应:HttpResponse对象
所在位置:django.http
request就是指HttpRequest。
1 HttpRequest对象的属性和方法
属性 | 描述 |
---|---|
path | 请求页面的全路径,不包括域名—例如, "/music/bands/the_beatles/"。 |
method | 请求中使用的HTTP方法的字符串表示。全大写表示。 |
GET | 包含所有HTTP GET参数的类字典对象 |
POST | 包含所有HTTP POST参数的类字典对象 |
REQUEST | 为了方便,该属性是POST和GET属性的集合体,但是有特殊性,先查找POST属性,然后再查找GET属性 |
COOKIES | 包含所有cookies的标准Python字典对象。Keys和values都是字符串。 |
FILES | 包含所有上传文件的类字典对象。FILES中的每个Key都是<input type="file" name="" /> 标签中name属性的值. FILES中的每个value 同时也是一个标准Python字典对象,包含下面三个Keys:(Filename: 上传文件名,用Python字符串表示;content-type: 上传文件的Content type;content: 上传文件的原始内容)注意:只有在请求方法是POST,并且请求页面中<form> 有enctype="multipart/form-data" 属性时FILES才拥有数据。否则,FILES 是一个空字典。 |
META | 包含所有可用HTTP头部信息的字典,例如:(CONTENT_LENGTH,CONTENT_TYPE,QUERY_STRING: 未解析的原始查询字符,串,REMOTE_ADDR: 客户端IP地址REMOTE_HOST: 客户端主机名,SERVER_NAME: 服务器主机名,SERVER_PORT: 服务器端口);META 中这些头加上前缀HTTP_最为Key, 例如:(HTTP_ACCEPT_ENCODING,HTTP_ACCEPT_LANGUAGE,HTTP_HOST: 客户发送的HTTP主机头信息,HTTP_REFERER: referring页,HTTP_USER_AGENT: 客户端的user-agent字符串,HTTP_X_BENDER: X-Bender头信息) |
user | 是一个django.contrib.auth.models.User 对象,代表当前登录的用户。如果访问用户当前没有登录,user将被初始化为django.contrib.auth.models.AnonymousUser的实例。见例子1 |
session | 唯一可读写的属性,代表当前会话的字典对象。只有激活Django中的session支持时该属性才可用。 |
raw_post_data | 原始HTTP POST数据,未解析过。 高级处理时会有用处。 |
method | 描述 |
---|---|
__getitem__(key) | 返回GET/POST的键值,先取POST,后取GET。如果键不存在抛出 KeyError。这是我们可以使用字典语法访问HttpRequest对象。例如:request["foo"]等同于先request.POST["foo"] 然后 request.GET["foo"]的操作。 |
has_key() | 检查request.GET or request.POST中是否包含参数指定的Key。 |
get_full_path() | 返回包含查询字符串的请求路径。例如, "/music/bands/the_beatles/?print=true" |
is_secure() | 如果请求是安全的,返回True,就是说,发出的是HTTPS请求。 |
get_full_path(), 比如:http://127.0.0.1:8000/index33/?name=123 ,req.get_full_path()得到的结果就是/index33/?name=123
req.path得到的结果是:/index33
2 HttpResponse对象的属性和方法
对于HttpRequest对象来说,是由django自动创建的,但是,HttpResponse对象就必须我们自己创建。每个view请求处理方法必须返回一个HttpResponse对象。
HttpResponse类在django.http.HttpResponse
在HttpResponse对象上扩展的常用方法:
页面渲染: render()(推荐) 或 render_to_response(),
页面跳转: redirect("路径")
locals(): 可以直接将函数中所有的变量传给模板
七 Django templates(模板)
模板由HTML+逻辑控制代码组成。
1 变量
使用双大括号来引用变量
语法格式: {{var_name}}
2 Template和Context对象
渲染操作流程:
一旦创建Template对象之后,可以用context传递数据给它,它是一系列变量和它们值的集合,模板使用它来赋值模板变量标签和执行块标签
context在django里表现为Context类,在django.template模块中
Context类构造是一个可选参数:一个字典映射变量和它们的值
创建一系列Context对象之后,调用Template对象的render()方法并传递Context对象来填充模板
同一个模板渲染多个context:
>>>from django,template import Template,Context
>>>t=Template("My name is {{name}},I love{{language}}")
>>>c=Context({'name':'BeginMan','language':'Python/Js/C#'})
>>>t.render(c)
--------------------------------output----------------------------------------------
My name is BeginMan ,I love Python/Js/C#
推荐写法:
def current_time(req): now=datetime.datetime.now() return render(req, 'current_datetime.html', {'current_date':now}) # 字典部分指定就是Context对象,render()方法将Context对象的键值传递给模板,并填充模板。
3 深度变量查找
context不仅能传递简单的参数(字符串),也可以传递列表和字典对象。
#最好是用几个例子来说明一下。
# 首先,句点可用于访问列表索引,例如: >>> from django.template import Template, Context
>>> t = Template('Item 2 is {{ items.2 }}.')
>>> c = Context({'items': ['apples', 'bananas', 'carrots']})
>>> t.render(c)
'Item 2 is carrots.' #假设你要向模板传递一个 Python 字典。 要通过字典键访问该字典的值,可使用一个句点:
>>> from django.template import Template, Context
>>> person = {'name': 'Sally', 'age': ''}
>>> t = Template('{{ person.name }} is {{ person.age }} years old.')
>>> c = Context({'person': person})
>>> t.render(c)
'Sally is 43 years old.' #同样,也可以通过句点来访问对象的属性。 比方说, Python 的 datetime.date 对象有
#year 、 month 和 day 几个属性,你同样可以在模板中使用句点来访问这些属性: >>> from django.template import Template, Context
>>> import datetime
>>> d = datetime.date(1993, 5, 2)
>>> d.year
>>> d.month
>>> d.day
>>> t = Template('The month is {{ date.month }} and the year is {{ date.year }}.')
>>> c = Context({'date': d})
>>> t.render(c)
'The month is 5 and the year is 1993.' # 这个例子使用了一个自定义的类,演示了通过实例变量加一点(dots)来访问它的属性,这个方法适
# 用于任意的对象。
>>> from django.template import Template, Context
>>> class Person(object):
... def __init__(self, first_name, last_name):
... self.first_name, self.last_name = first_name, last_name
>>> t = Template('Hello, {{ person.first_name }} {{ person.last_name }}.')
>>> c = Context({'person': Person('John', 'Smith')})
>>> t.render(c)
'Hello, John Smith.' # 点语法也可以用来引用对象的方法。 例如,每个 Python 字符串都有 upper() 和 isdigit()
# 方法,你在模板中可以使用同样的句点语法来调用它们:
>>> from django.template import Template, Context
>>> t = Template('{{ var }} -- {{ var.upper }} -- {{ var.isdigit }}')
>>> t.render(Context({'var': 'hello'}))
'hello -- HELLO -- False'
>>> t.render(Context({'var': ''}))
'123 -- 123 -- True' # 注意这里调用方法时并* 没有* 使用圆括号 而且也无法给该方法传递参数;你只能调用不需参数的
# 方法。
4 变量过滤器filter
语法格式: {{obj|filter:param}}
# 1 add : 给变量加上相应的值
#
# 2 addslashes : 给变量中的引号前加上斜线
#
# 3 capfirst : 首字母大写
#
# 4 cut : 从字符串中移除指定的字符
#
# 5 date : 格式化日期字符串
#
# 6 default : 如果值是False,就替换成设置的默认值,否则就是用本来的值
#
# 7 default_if_none: 如果值是None,就替换成设置的默认值,否则就使用本来的值 #实例: #value1="aBcDe"
{{ value1|upper }} #value2=5
{{ value2|add:3 }} #value3='he llo wo r ld'
{{ value3|cut:' ' }} #import datetime
#value4=datetime.datetime.now()
{{ value4|date:'Y-m-d' }} #value5=[]
{{ value5|default:'空的' }} #value6='<a href="#">跳转</a>' {{ value6 }} {% autoescape off %}
{{ value6 }}
{% endautoescape %} {{ value6|safe }} {{ value6|striptags }} #value7='1234'
{{ value7|filesizeformat }}
{{ value7|first }}
{{ value7|length }}
{{ value7|slice:":-1" }} #value8='http://www.baidu.com/?a=1&b=3'
{{ value8|urlencode }}
value9='hello I am yuan'
5 常用标签(tag)
语法格式: {% tags %}
(1) {% if %}
(2) {% for %}
(3) {% csrf_token %}
(4) {% url %} :引用路由配置的地址
(5) {% with %} :用简短的变量名代替复杂的变量名
(6) {% verbatim %} :禁止render
(7) {% load %} :加载标签库
6 自定义filter和simple_tag
(1)在app下创建templatetags目录或模块,目录名称必须这样写。
(2)创建.py文件,如my_tags。(其中,register名称不可改变)
(3)在使用自定义filter和simple_tag的html文件之前,通过 {% load my_tags %}导入前面自己创建的my_tags标签库。(注意:settings中INSTALLED_APPS中必须添加当前的app名称,否则找不到自定义的tags)
(4)调用自定义的filter和simple_tag。
filter可以用在if等语句后,simple_tag不可以:
{% if num|filter_multi:30 > 100 %}
{{ num|filter_multi:30 }}
{% endif %}
7 extend模板继承
将shopping_car.html和ordered.html中大量重复的代码提取出来,写入base.html中,不同的部分分别写在各自模板中,通过extends继承base.html中的公共部分。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
*{
margin: 0;
} .top{
height: 45px;
background-color: darkblue;
} .menu{
width: 20%;
height: 700px;
background-color: cornflowerblue;
float: left;
margin-top: 5px;
} .menu a{
display: block;
text-align: center;
} .content{
width: 80%;
height: 700px;
float: left;
margin-top: 5px;
background-color: lightgray;
}
</style>
</head>
<body>
<div class="top"></div>
<div class="menu">
<a href="/shopping_car/">Shopping Car</a>
<a href="/ordered/">Ordered</a>
</div>
<div class="content">
{% block content %}
{% endblock %}
</div>
</body>
</html>
base.html
shopping_car.html:
{% extends 'base.html' %} {% block content %}
<a>购物车</a>
{% endblock %}
ordered.html:
{% extends 'base.html' %} {% block content %}
<a>订单</a>
{% endblock %}
八 Django modules(模型)
1 django默认支持sqlite,mysql, oracle,postgresql数据库。
<1> sqlite
django默认使用sqlite的数据库,默认自带sqlite的数据库驱动
引擎名称:django.db.backends.sqlite3
<2> mysql
引擎名称:django.db.backends.mysql
2 mysql驱动程序
MySQLdb(mysql python)
mysqlclient
MySQL
PyMySQL(纯python的mysql驱动程序)
3 Django的项目中默认使用sqlite数据库,在settings中设置如下:
如果想要使用mysql数据库,只需要做如下更改:
注意:NAME即数据库的名字,在mysql连接前该数据库必须已经创建,而上面的sqlite数据库下的db.sqlite3则是项目自动创建
USER和PASSWORD分别是数据库的用户名和密码。
设置完后,再启动我们的Django项目前,我们需要激活我们的mysql。
然后,启动项目,会报错:no module named MySQLdb
这是因为django默认你导入的驱动是MySQLdb,可是MySQLdb对于py3有很大问题,所以我们需要的驱动是PyMySQL
所以,我们只需要找到项目名文件下的__init__,在里面写入:
ORM(对象关系映射)
对象-关系映射(Object/Relation Mapping,简称ORM),是随着面向对象的软件开发方法发展而产生的。面向对象的开发方法是当今企业级应用开发环境中的主流开发方法,关系数据库是企业级应用环境中永久存放数据的主流数据存储系统。对象和关系数据是业务实体的两种表现形式,业务实体在内存中表现为对象,在数据库中表现为关系数据。内存中的对象之间存在关联和继承关系,而在数据库中,关系数据无法直接表达多对多关联和继承关系。因此,对象-关系映射(ORM)系统一般以中间件的形式存在,主要实现程序对象到关系数据库数据的映射。 面向对象是从软件工程基本原则(如耦合、聚合、封装)的基础上发展起来的,而关系数据库则是从数学理论发展而来的,两套理论存在显著的区别。为了解决这个不匹配的现象,对象关系映射技术应运而生。 让我们从O/R开始。字母O起源于"对象"(Object),而R则来自于"关系"(Relational)。几乎所有的程序里面,都存在对象和关系数据库。在业务逻辑层和用户界面层中,我们是面向对象的。当对象信息发生变化的时候,我们需要把对象的信息保存在关系数据库中。 当你开发一个应用程序的时候(不使用O/R Mapping),你可能会写不少数据访问层的代码,用来从数据库保存,删除,读取对象信息,等等。你在DAL中写了很多的方法来读取对象数据,改变状态对象等等任务。而这些代码写起来总是重复的。 如果打开你最近的程序,看看DAL代码,你肯定会看到很多近似的通用的模式。我们以保存对象的方法为例,你传入一个对象,为SqlCommand对象添加SqlParameter,把所有属性和对象对应,设置SqlCommand的CommandText属性为存储过程,然后运行SqlCommand。对于每个对象都要重复的写这些代码。 除此之外,还有更好的办法吗?有,引入一个O/R Mapping。实质上,一个O/R Mapping会为你生成DAL。与其自己写DAL代码,不如用O/R Mapping。你用O/R Mapping保存,删除,读取对象,O/R Mapping负责生成SQL,你只需要关心对象就好。 对象关系映射成功运用在不同的面向对象持久层产品中,如:Torque,OJB,hibernate,TopLink,Castor JDO, TJDO 等。
一般的ORM包括以下四部分: 一个对持久类对象进行CRUD操作的API; 一个语言或API用来规定与类和类属性相关的查询; 一个规定mapping metadata的工具; 一种技术可以让ORM的实现同事务对象一起进行dirty checking, lazy association fetching以及其他的优化操作。
1 django ORM——创建表(模型)
django模型常用的字段类型
字段名 |
参数 |
意义 |
AutoField |
一个能够根据可用ID自增的 IntegerField |
|
BooleanField |
一个真/假(true/false)字段 |
|
CharField |
(max_length) |
一个字符串字段,适用于中小长度的字符串。对于长段的文字,请使用 TextField |
CommaSeparatedIntegerField |
(max_length) |
一个用逗号分隔开的整数字段 |
DateField |
([auto_now], [auto_now_add]) |
日期字段 |
DateTimeField |
时间日期字段,接受跟 DateField 一样的额外选项 |
|
EmailField |
一个能检查值是否是有效的电子邮件地址的 CharField |
|
FileField |
(upload_to) |
一个文件上传字段 |
FilePathField |
(path,[match],[recursive]) |
一个拥有若干可选项的字段,选项被限定为文件系统中某个目录下的文件名 |
FloatField |
(max_digits,decimal_places) |
一个浮点数,对应Python中的 float 实例 |
ImageField |
(upload_to, [height_field] ,[width_field]) |
像 FileField 一样,只不过要验证上传的对象是一个有效的图片。 |
IntegerField |
一个整数。 |
|
IPAddressField |
一个IP地址,以字符串格式表示(例如: "24.124.1.30" )。 |
|
NullBooleanField |
就像一个 BooleanField ,但它支持 None /Null 。 |
|
PhoneNumberField |
它是一个 CharField ,并且会检查值是否是一个合法的美式电话格式 |
|
PositiveIntegerField |
和 IntegerField 类似,但必须是正值。 |
|
PositiveSmallIntegerField |
与 PositiveIntegerField 类似,但只允许小于一定值的值,最大值取决于数据库. |
|
SlugField |
嵌条 就是一段内容的简短标签,这段内容只能包含字母、数字、下 划线或连字符。通常用于URL中 |
|
SmallIntegerField |
和 IntegerField 类似,但是只允许在一个数据库相关的范围内的数值(通常是-32,768到 +32,767) |
|
TextField |
一个不限长度的文字字段 |
|
TimeField |
时分秒的时间显示。它接受的可指定参数与 DateField 和 DateTimeField 相同。 |
|
URLField |
用来存储URL的字段。 |
|
USStateField |
美国州名称缩写,两个字母。 |
|
XMLField |
(schema_path) |
它就是一个 TextField ,只不过要检查值是匹配指定schema的合法XML。 |
参数名 |
意义 |
null |
如果设置为 True 的话,Django将在数据库中存储空值为 NULL 。默认为 False 。 |
blank |
如果是 True ,该字段允许留空,默认为 False 。 |
choices |
一个包含双元素元组的可迭代的对象,用于给字段提供选项。 |
db_column |
当前字段在数据库中对应的列的名字。 |
db_index |
如果为 True ,Django会在创建表格(比如运行 manage.py syncdb )时对这一列创建数据库索引。 |
default |
字段的默认值 |
editable |
如果为 False ,这个字段在管理界面或表单里将不能编辑。默认为 True 。 |
help_text |
在管理界面表单对象里显示在字段下面的额外帮助文本。 |
primary_key |
如果为 True ,这个字段就会成为模型的主键。 |
radio_admin |
默认地,对于 ForeignKey 或者拥有 choices 设置的字段,Django管理界面会使用列表选择框(<select>)。如果 radio_admin 设置为 True 的话,Django就会使用单选按钮界面。 |
unique |
如果是 True ,这个字段的值在整个表中必须是唯一的。 |
unique_for_date |
把它的值设成一个 DataField 或者 DateTimeField 的字段的名称,可以确保字段在这个日期内不会出现重复值。 |
unique_for_month |
和 unique_for_date 类似,只是要求字段在指定字段的月份内唯一。 |
unique_for_year |
和 unique_for_date 及 unique_for_month 类似,只是时间范围变成了一年。 |
verbose_name |
除 ForeignKey 、 ManyToManyField 和 OneToOneField 之外的字段都接受一个详细名称作为第一个位置参数。 |
实例:创建一个书籍、作者、出版社数据库结构
一本书可能有多个作者,一个作者可以写多本书,一本书通常仅由一个出版社出版。因此作者与书为多对多关系,出版社与书为一对多关系。接下来,我们来创建表(模型)。
多对多关系(many-to-many):彼此一对多,自动创建第三张表来表示对应关系。
一对多关系(one-to-many):主外键关系,在many对应的表中给需要的字段添加外键。
一对一(one-to-one):在一对多基础上,在多的哪个表ForeignKey的基础上加unique=true。
1 每个数据模型都是django.db.models.Model的子类,它的父类Model包含了所有必要的和数据库交互的方法。并提供了一个简介漂亮的定义数据库字段的语法。
2 每个模型相当于单个数据库表(多对多关系例外,会多生成一张关系表),每个属性也是这个表中的字段。属性名就是字段名,它的类型(例如CharField)相当于数据库的字段类型(例如varchar)。
from django.db import models # Create your models here.
class Publisher(models.Model): name = models.CharField(max_length=64,verbose_name="出版社名称")
city = models.CharField(max_length=24,verbose_name="所在城市") def __str__(self): return self.name class Author(models.Model): name = models.CharField(max_length=20,verbose_name="作者名称")
sex = models.BooleanField(max_length=1,choices=((0,'男'),(1,'女')))
email = models.EmailField()
birthday = models.DateField() def __str__(self): return self.name class Book(models.Model): title = models.CharField(max_length=64,verbose_name="书名")
authors = models.ManyToManyField(Author)
publish = models.ForeignKey(Publisher)
price = models.DecimalField(max_digits=5,decimal_places=2,default=10) def __str__(self): return self.title
创建模型
确认当前app已经添加到settings设置中,然后执行数据库初始化操作: python3 manage.py makemigrations和python3 manage.py migrate。
2 django ORM——增(create、save)
增加数据有两种方式: (数据表中的每一条数据代表一个对象)
创建一对多关系:
创建多对多关系:
3 django ORM——删(delete)
4 django ORM——改(update、save)
只有QuerySet对象才有update方法,因此查找行对象时只能使用filter,不能使用get。返回的整数表示受影响的行数。
save方法会将所有属性重新设定一遍,而update只对指定的属性值进行设定,故update方法更高效。
5 django ORM——查
# 查询相关API: # <1>filter(**kwargs): 它包含了与所给筛选条件相匹配的对象 # <2>all(): 查询所有结果 # <3>get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。 #-----------下面的方法都是对查询的结果再进行处理:比如 objects.filter.values()-------- # <4>values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列 model的实例化对象,而是一个可迭代的字典序列 # <5>exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象 # <6>order_by(*field): 对查询结果排序 # <7>reverse(): 对查询结果反向排序 # <8>distinct(): 从返回结果中剔除重复纪录 # <9>values_list(*field): 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列 # <10>count(): 返回数据库中匹配查询(QuerySet)的对象数量。 # <11>first(): 返回第一条记录 # <12>last(): 返回最后一条记录 # <13>exists(): 如果QuerySet包含数据,就返回True,否则返回False。
查询API:
>>> Book.objects.all()
<QuerySet [<Book: python>, <Book: php>, <Book: python红宝书>, <Book: C语言>, <Book: C++>, <Book: 杜拉拉大结局>, <Book: 百年孤独>]>
>>> Book.objects.filter(price__lt=50)
<QuerySet [<Book: python红宝书>, <Book: 杜拉拉大结局>, <Book: 百年孤独>]>
>>> Book.objects.get(title='python')
<Book: python>
>>> Book.objects.filter(price__lt=50).values()
<QuerySet [{'title': 'python红宝书', 'price': Decimal('8.00'), 'publish_id': 4, 'id': 3}, {'title': '杜拉拉大结局', 'price': Decimal('32.00'), 'publish_id': 3, 'id': 6}, {'title': '百年孤独', 'price': Decimal('39.50'), 'publish_id': 4, 'id': 7}]>
>>> Book.objects.filter(price__lt=50).exclude(price__gt=60)
<QuerySet [<Book: python红宝书>, <Book: 杜拉拉大结局>, <Book: 百年孤独>]>
>>> Book.objects.filter(price__lt=50).exclude(id=6)
<QuerySet [<Book: python红宝书>, <Book: 百年孤独>]>
>>> Book.objects.all().order_by('price')
<QuerySet [<Book: python红宝书>, <Book: 杜拉拉大结局>, <Book: 百年孤独>, <Book: C语言>, <Book: php>, <Book: python>, <Book: C++>]>
>>> Book.objects.all().reverse()
<QuerySet [<Book: python>, <Book: php>, <Book: python红宝书>, <Book: C语言>, <Book: C++>, <Book: 杜拉拉大结局>, <Book: 百年孤独>]>
>>> Book.objects.all().distinct()
<QuerySet [<Book: python>, <Book: php>, <Book: python红宝书>, <Book: C语言>, <Book: C++>, <Book: 杜拉拉大结局>, <Book: 百年孤独>]>
>>> Book.objects.all().values_list()
<QuerySet [(1, 'python', 1, Decimal('78.00')), (2, 'php', 2, Decimal('54.00')), (3, 'python红宝书', 4, Decimal('8.00')), (4, 'C语言', 2, Decimal('50.00')), (5, 'C++', 1, Decimal('78.00')), (6, '杜拉拉大结局', 3, Decimal('32.00')), (7, '百年孤独', 4, Decimal('39.50'))]>
>>> Book.objects.all().count()
7
>>> Book.objects.all().first()
<Book: python>
>>> Book.objects.all().last()
<Book: 百年孤独>
>>> Book.objects.all().exists()
True
扩展查询:
#扩展查询,有时候DJANGO的查询API不能方便的设置查询条件,提供了另外的扩展查询方法extra:
#extra(select=None, where=None, params=None, tables=None,order_by=None, select_params=None (1) Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"})
(2) Blog.objects.extra(
select=SortedDict([('a', '%s'), ('b', '%s')]),
select_params=('one', 'two')) (3) q = Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"})
q = q.extra(order_by = ['-is_recent']) (4) Entry.objects.extra(where=['headline=%s'], params=['Lennon']) extra
惰性机制:
Book.objects.filter()或Book.objects.all()等只是返回一个QuerySet对象(查询结果集对象),并不会马上执行SQL,而是当调用QuerySet对象时才会执行SQL。
QuerySet特点:
<1>可迭代
<2>可切片
QuerySet的高效使用:
#<1>Django的queryset是惰性的 Django的queryset对应于数据库的若干记录(row),通过可选的查询来过滤。例如,下面的代码会得到数据库中
名字为‘Dave’的所有的人:
person_set = Person.objects.filter(first_name="Dave") 上面的代码并没有运行任何的数据库查询。你可以使用person_set,给它加上一些过滤条件,或者将它传给某个函数,
这些操作都不会发送给数据库。这是对的,因为数据库查询是显著影响web应用性能的因素之一。 #<2>要真正从数据库获得数据,你可以遍历queryset或者使用if queryset,总之你用到数据时就会执行sql.
为了验证这些,需要在settings里加入 LOGGING(验证方式) obj=models.Book.objects.filter(id=3) # for i in obj:
# print(i) # if obj:
# print("ok") #<3>queryset是具有cache的
当你遍历queryset时,所有匹配的记录会从数据库获取,然后转换成Django的model。这被称为执行(evaluation).
这些model会保存在queryset内置的cache中,这样如果你再次遍历这个queryset,你不需要重复运行通用的查询。
obj=models.Book.objects.filter(id=3) # for i in obj:
# print(i) # for i in obj:
# print(i) #LOGGING只会打印一次 #<4>
简单的使用if语句进行判断也会完全执行整个queryset并且把数据放入cache,虽然你并不需要这些数据!
为了避免这个,可以用exists()方法来检查是否有数据: obj = Book.objects.filter(id=4)
# exists()的检查可以避免数据放入queryset的cache。
if obj.exists():
print("hello world!") #<5>当queryset非常巨大时,cache会成为问题 处理成千上万的记录时,将它们一次装入内存是很浪费的。更糟糕的是,巨大的queryset可能会锁住系统进程,让你的
程序濒临崩溃。要避免在遍历数据的同时产生queryset cache,可以使用iterator()方法来获取数据,处理完数据就
将其丢弃。
objs = Book.objects.all()
# iterator()可以一次只从数据库获取少量数据,这样可以节省内存
for obj in objs.iterator():
print(obj.name)
当然,使用iterator()方法来防止生成cache,意味着遍历同一个queryset时会重复执行查询。所以使用iterator()
的时候要当心,确保你的代码在操作一个大的queryset时没有重复执行查询 总结:
queryset的cache是用于减少程序对数据库的查询,在通常的使用下会保证只有在需要的时候才会查询数据库。
使用exists()和iterator()方法可以优化程序对内存的使用。不过,由于它们并不会生成queryset cache,可能
会造成额外的数据库查询。
对象查询、单表条件查询、多表条件关联查询:
#--------------------对象形式的查找--------------------------
# 正向查找
ret1=models.Book.objects.first()
print(ret1.title)
print(ret1.price)
print(ret1.publisher)
print(ret1.publisher.name) #因为一对多的关系所以ret1.publisher是一个对象,而不是一个queryset集合 # 反向查找
ret2=models.Publish.objects.last()
print(ret2.name)
print(ret2.city)
#如何拿到与它绑定的Book对象呢?
print(ret2.book_set.all()) #ret2.book_set是一个queryset集合 #---------------了不起的双下划线(__)之单表条件查询---------------- # models.Tb1.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值
#
# models.Tb1.objects.filter(id__in=[11, 22, 33]) # 获取id等于11、22、33的数据
# models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in
#
# models.Tb1.objects.filter(name__contains="ven")
# models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
#
# models.Tb1.objects.filter(id__range=[1, 2]) # 范围bettwen and
#
# startswith,istartswith, endswith, iendswith, #----------------了不起的双下划线(__)之多表条件关联查询--------------- # 正向查找(条件) # ret3=models.Book.objects.filter(title='Python').values('id')
# print(ret3)#[{'id': 1}] #正向查找(条件)之一对多 ret4=models.Book.objects.filter(title='Python').values('publisher__city')
print(ret4) #[{'publisher__city': '北京'}]
ret5=models.Book.objects.filter(publisher__address='北京').values('publisher__name')
print(ret5) #[{'publisher__name': '人大出版社'}, {'publisher__name': '人大出版社'}] #正向查找(条件)之多对多
ret6=models.Book.objects.filter(title='Python').values('author__name')
print(ret6)
ret7=models.Book.objects.filter(author__name="alex").values('title')
print(ret7) # 反向查找(条件) #反向查找之一对多:
ret8=models.Publisher.objects.filter(book__title='Python').values('name')
print(ret8)#[{'name': '人大出版社'}] 注意,book__title中的book就是Publisher的关联表名 ret9=models.Publisher.objects.filter(book__title='Python').values('book__authors')
print(ret9)#[{'book__authors': 1}, {'book__authors': 2}] #反向查找之多对多:
ret10=models.Author.objects.filter(book__title='Python').values('name')
print(ret10)#[{'name': 'alex'}, {'name': 'alvin'}]
>>> Publisher.objects.filter(book__price__gt=50).values('book__title')
<QuerySet [{'book__title': 'python'}, {'book__title': 'php'}, {'book__title': 'C++'}]>
聚合查询和分组查询:
<1> aggregate(*args,**kwargs)
from django.db.models import Avg,Min,Sum,Max 从整个查询集生成统计值。比如,你想要计算所有在售书的平均价钱。Django的查询语法提供了一种方式描述所有
图书的集合。 >>> Book.objects.all().aggregate(Avg('price'))
{'price__avg': 34.35} aggregate()子句的参数描述了我们想要计算的聚合值,在这个例子中,是Book模型中price字段的平均值 aggregate()是QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。键的名称是聚合值的
标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。如果你想要为聚合值指定
一个名称,可以向聚合子句提供它:
>>> Book.objects.aggregate(average_price=Avg('price'))
{'average_price': 34.35} 如果你也想知道所有图书价格的最大值和最小值,可以这样查询:
>>> Book.objects.aggregate(Avg('price'), Max('price'), Min('price'))
{'price__avg': 34.35, 'price__max': Decimal('81.20'), 'price__min': Decimal('12.99')}
<2> annotate(*args,**kwargs)
可以通过计算查询结果中每一个对象所关联的对象集合,从而得出总计值(也可以是平均值或总和),即为查询集的每一项生成聚合。
查询alex出的书总价格
查询各个作者出的书的总价格,这里就涉及到分组了,分组条件是authors__name
查询各个出版社最便宜的书价是多少
F查询和Q查询:
# F 使用查询条件的值,专门取对象中某列值的操作 # from django.db.models import F
# models.Tb1.objects.update(num=F('num')+1) # Q 构建搜索条件
from django.db.models import Q #1 Q对象(django.db.models.Q)可以对关键字参数进行封装,从而更好地应用多个查询
q1=models.Book.objects.filter(Q(title__startswith='P')).all()
print(q1)#[<Book: Python>, <Book: Perl>] # 2、可以组合使用&,|操作符,当一个操作符是用于两个Q的对象,它产生一个新的Q对象。
Q(title__startswith='P') | Q(title__startswith='J') # 3、Q对象可以用~操作符放在前面表示否定,也可允许否定与不否定形式的组合
Q(title__startswith='P') | ~Q(pub_date__year=2005) # 4、应用范围: # Each lookup function that takes keyword-arguments (e.g. filter(),
# exclude(), get()) can also be passed one or more Q objects as
# positional (not-named) arguments. If you provide multiple Q object
# arguments to a lookup function, the arguments will be “AND”ed
# together. For example: Book.objects.get(
Q(title__startswith='P'),
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
) #sql:
# SELECT * from polls WHERE question LIKE 'P%'
# AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06') # import datetime
# e=datetime.date(2005,5,6) #2005-05-06 # 5、Q对象可以与关键字参数查询一起使用,不过一定要把Q对象放在关键字参数查询的前面。
# 正确:
Book.objects.get(
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
title__startswith='P')
# 错误:
Book.objects.get(
question__startswith='P',
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))
原生SQL的用法:
http://www.cnblogs.com/lijintian/p/6100097.html
附录 Django命令行工具
django-admin.py 是Django的一个用于管理任务的命令行工具,manage.py是对django-admin.py的简单包装,每一个Django Project里都会有一个mannage.py。
1 django-admin.py startproject project_name
创建一个新的django工程。
2 python manage.py startapp app_name
创建一个应用。
3 python manage.py runserver
启动django项目。
4 python manage.py makemigrations
migrations目录下生成同步数据库的脚本。
同步数据库:python manage.py migrate
5 python manage.py createsuperuser
创建超级管理员,设置用户名和密码。当我们访问http://http://127.0.0.1:8080/admin/时,便可以通过超级管理员用户登录了。
6 python manage.py flush
清空数据库。
7 django-admin.py help startapp
查询某个命令的详细信息。
8 python manage.py shell
启动交互界面。
9 python manage.py
查看django提供的命令。
Python Web框架——Django的更多相关文章
- 利用python web框架django实现py-faster-rcnn demo实例
操作系统.编程环境及其他: window7 cpu python2.7 pycharm5.0 django1.8x 说明:本blog是上一篇blog(http://www.cnblogs.co ...
- python web框架 django wsgi 理论
django wsgi python有个自带的wsgi模块 可以写自定义web框架 用wsgi在内部创建socket对象就可以了 自己只写处理函数就可以了django只是web框架 他也不负责写soc ...
- python web框架 django 工程 创建 目录介绍
# 创建Django工程django-admin startproject [工程名称] 默认创建django 项目都会自带这些东西 django setting 配置文件 django可以配置缓存 ...
- python web框架 Django进阶
django 进阶 基础中,一些操作都是手动创建连接的非主流操作,这样显得太low,当然也是为了熟悉这个框架! 实际中,django自带连接数据库和创建app的机制,同时还有更完善的路由系统机制.既然 ...
- python web框架 Django基本操作
django 操作总结! django框架安装: cmd安装: pip3 install django pycharm安装: 在python变量下 搜索 django 安装 创建django项目: c ...
- python web框架Django入门
Django 简介 背景及介绍 Django是一个开放源代码的Web应用框架,由Python写成.采用了MVC的框架模式,即模型M,视图V和控制器C.它最初是被开发来用于管理劳伦斯出版集团旗下的一些以 ...
- python web框架Django——ORM
ORM简介 MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库 ORM是“对象-关系-映射”的简称 ...
- python web框架 django 练习1 django 1.11版本
django练习 在我自己项目里创建一个xiaoliu的文件夹 里面创建s1.py 文件 s1.py文件 里面写各种函数 from django.shortcuts import HttpRespon ...
- python web框架 django工程的创建
安装 django pip3 install django pip install django 安装完后出现这两个文件 django-admin 用来创建文件夹 在script目录 执行这个命令 d ...
随机推荐
- SAPUI5实例一:来创建Web应用UI
试试SAPUI5.这是SAP比较重要的一个UI库.完全通过HTML5实现,可以作为Web和移动应用的UI开发. 现在已经开源了.在这里可以下载: http://sap.github.io/openui ...
- 对集合应用符号 | & ^ -
s1 = set('abc') s2 = set('abs') # 在s1而不在s2 print s1 - s2 # set(['c']) # 在s1或者s2 print s1 | s2 # set( ...
- Appium+python(1)简单的介绍环境搭建
环境搭建其实并不难,只不过安装的东西有点多,要加的环境变量有点多. 链接:https://pan.baidu.com/s/1nwLhNIT 密码:56wn 这个压缩包里要用的都有了,只需要下载,然后安 ...
- ballerina 学习五 使用composer管理ballerina 项目
1. 启动 composer 备注: 因为这个命名和php的一个包管理工具重名了,所以可能需要使用决定路径 比如我的mac系统使用:Library/Ballerina/ballerina-0.970. ...
- elixir jenkins 集成构建方式配置
备注: 主要问题是环境变量配置的问题,解决方法是使用软连接进行解决 1. 下载软件包 wget https://github.com/elixir-lang/elixir/releases/ ...
- asciidoctor 安装试用
备注: asciidoctor 是asciidoc 的增强,使用简单,模板比较丰富,对于持续集成方面的开发也是一个不错的工具 1. 安装 a. 环境准备 MRI Ruby 1.8.7, 1. ...
- sysbench 1.0.9 mysql 压测工具安装使用
备注: 安装比较简单,可以使用源码或者使用yum 进行安装,本次测试使用yum 注意1.0 之后版本与老版本改动比较大,好多地方都有修改,本次测试使用 的mysql 使用docker ...
- elastic search6.2.2 实现用户搜索记录查询(去重、排序)
elastic search6.2.2 实现搜索记录查询 ,类似新浪微博这种,同样的搜索记录后面时间点的会覆盖前面的(主要思路:关键词去重,然后按时间排序) 先创建索引 //我的搜索 PUT my_s ...
- mysql innodb引擎事务的隔离级别
一.事务的基本要素(ACID) 1.原子性(Atomicity):事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节.事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有 ...
- 20165226 实验四 Android程序设计
实验四 Android程序设计 实验目的 一.Android Studio的安装测试 二.Activity测试 三.UI测试 四.布局测试 五.事件处理测试 实验内容及步骤 (一)Android St ...