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),

]
View Code

用()括起来表示保存为一个子组,每个子组作为一个参数(无名参数),被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=='123':
            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>


#######################
View Code

 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:

1 >>>from django,template import Template,Context
2 >>>t=Template("My name is {{name}},I love{{language}}")
3 >>>c=Context({'name':'BeginMan','language':'Python/Js/C#'})
4 >>>t.render(c)
5 --------------------------------output----------------------------------------------
6 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不仅能传递简单的参数(字符串),也可以传递列表和字典对象。

 1 #最好是用几个例子来说明一下。
 2 # 首先,句点可用于访问列表索引,例如:
 3 
 4 >>> from django.template import Template, Context
 5 >>> t = Template('Item 2 is {{ items.2 }}.')
 6 >>> c = Context({'items': ['apples', 'bananas', 'carrots']})
 7 >>> t.render(c)
 8 'Item 2 is carrots.'
 9 
10 #假设你要向模板传递一个 Python 字典。 要通过字典键访问该字典的值,可使用一个句点:
11 >>> from django.template import Template, Context
12 >>> person = {'name': 'Sally', 'age': '43'}
13 >>> t = Template('{{ person.name }} is {{ person.age }} years old.')
14 >>> c = Context({'person': person})
15 >>> t.render(c)
16 'Sally is 43 years old.'
17 
18 #同样,也可以通过句点来访问对象的属性。 比方说, Python 的 datetime.date 对象有
19 #year 、 month 和 day 几个属性,你同样可以在模板中使用句点来访问这些属性:
20 
21 >>> from django.template import Template, Context
22 >>> import datetime
23 >>> d = datetime.date(1993, 5, 2)
24 >>> d.year
25 >>> d.month
26 >>> d.day
27 >>> t = Template('The month is {{ date.month }} and the year is {{ date.year }}.')
28 >>> c = Context({'date': d})
29 >>> t.render(c)
30 'The month is 5 and the year is 1993.'
31 
32 # 这个例子使用了一个自定义的类,演示了通过实例变量加一点(dots)来访问它的属性,这个方法适
33 # 用于任意的对象。
34 >>> from django.template import Template, Context
35 >>> class Person(object):
36 ...     def __init__(self, first_name, last_name):
37 ...         self.first_name, self.last_name = first_name, last_name
38 >>> t = Template('Hello, {{ person.first_name }} {{ person.last_name }}.')
39 >>> c = Context({'person': Person('John', 'Smith')})
40 >>> t.render(c)
41 'Hello, John Smith.'
42 
43 # 点语法也可以用来引用对象的方法。 例如,每个 Python 字符串都有 upper() 和 isdigit()
44 # 方法,你在模板中可以使用同样的句点语法来调用它们:
45 >>> from django.template import Template, Context
46 >>> t = Template('{{ var }} -- {{ var.upper }} -- {{ var.isdigit }}')
47 >>> t.render(Context({'var': 'hello'}))
48 'hello -- HELLO -- False'
49 >>> t.render(Context({'var': '123'}))
50 '123 -- 123 -- True'
51 
52 # 注意这里调用方法时并* 没有* 使用圆括号 而且也无法给该方法传递参数;你只能调用不需参数的
53 # 方法。
View Code

4 变量过滤器filter

语法格式:      {{obj|filter:param}}
 1 # 1  add          :   给变量加上相应的值
 2    #
 3    # 2  addslashes   :    给变量中的引号前加上斜线
 4    #
 5    # 3  capfirst     :    首字母大写
 6    #
 7    # 4  cut          :   从字符串中移除指定的字符
 8    #
 9    # 5  date         :   格式化日期字符串
10    #
11    # 6  default      :   如果值是False,就替换成设置的默认值,否则就是用本来的值
12    #
13    # 7  default_if_none:  如果值是None,就替换成设置的默认值,否则就使用本来的值
14 
15 
16 #实例:
17 
18 #value1="aBcDe"
19 {{ value1|upper }}
20 
21 #value2=5
22 {{ value2|add:3 }}
23 
24 #value3='he  llo wo r ld'
25 {{ value3|cut:' ' }}
26 
27 #import datetime
28 #value4=datetime.datetime.now()
29 {{ value4|date:'Y-m-d' }}
30 
31 #value5=[]
32 {{ value5|default:'空的' }}
33 
34 #value6='<a href="#">跳转</a>'
35 
36 {{ value6 }}
37 
38 {% autoescape off %}
39   {{ value6 }}
40 {% endautoescape %}
41 
42 {{ value6|safe }}
43 
44 {{ value6|striptags }}
45 
46 #value7='1234'
47 {{ value7|filesizeformat }}
48 {{ value7|first }}
49 {{ value7|length }}
50 {{ value7|slice:":-1" }}
51 
52 #value8='http://www.baidu.com/?a=1&b=3'
53 {{ value8|urlencode }}
54     value9='hello I am yuan'
View Code

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中的公共部分。

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6     <style>
 7         *{
 8             margin: 0;
 9         }
10 
11         .top{
12             height: 45px;
13             background-color: darkblue;
14         }
15 
16         .menu{
17             width: 20%;
18             height: 700px;
19             background-color: cornflowerblue;
20             float: left;
21             margin-top: 5px;
22         }
23 
24         .menu a{
25             display: block;
26             text-align: center;
27         }
28 
29         .content{
30             width: 80%;
31             height: 700px;
32             float: left;
33             margin-top: 5px;
34             background-color: lightgray;
35         }
36     </style>
37 </head>
38 <body>
39     <div class="top"></div>
40     <div class="menu">
41         <a href="/shopping_car/">Shopping Car</a>
42         <a href="/ordered/">Ordered</a>
43     </div>
44     <div class="content">
45         {% block content %}
46         {% endblock %}
47     </div>
48 </body>
49 </html>
base.html

shopping_car.html:

1 {% extends 'base.html' %}
2 
3 
4 {% block content %}
5  <a>购物车</a>
6 {% endblock %}

ordered.html:

1 {% extends 'base.html' %}
2 
3 
4 {% block content %}
5  <a>订单</a>
6 {% 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)。

 1 from django.db import models
 2 
 3 # Create your models here.
 4 class Publisher(models.Model):
 5 
 6     name = models.CharField(max_length=64,verbose_name="出版社名称")
 7     city = models.CharField(max_length=24,verbose_name="所在城市")
 8 
 9 
10     def __str__(self):
11 
12         return self.name
13 
14 
15 class Author(models.Model):
16 
17     name = models.CharField(max_length=20,verbose_name="作者名称")
18     sex = models.BooleanField(max_length=1,choices=((0,''),(1,'')))
19     email = models.EmailField()
20     birthday = models.DateField()
21 
22     def __str__(self):
23 
24         return self.name
25 
26 
27 class Book(models.Model):
28 
29     title = models.CharField(max_length=64,verbose_name="书名")
30     authors = models.ManyToManyField(Author)
31     publish = models.ForeignKey(Publisher)
32     price = models.DecimalField(max_digits=5,decimal_places=2,default=10)
33 
34     def __str__(self):
35 
36         return self.title
创建模型

确认当前app已经添加到settings设置中,然后执行数据库初始化操作: python3 manage.py makemigrationspython3 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——查

 1 # 查询相关API:
 2 
 3 #  <1>filter(**kwargs):      它包含了与所给筛选条件相匹配的对象
 4 
 5 #  <2>all():                 查询所有结果
 6 
 7 #  <3>get(**kwargs):         返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。
 8 
 9 #-----------下面的方法都是对查询的结果再进行处理:比如 objects.filter.values()--------
10 
11 #  <4>values(*field):        返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列 model的实例化对象,而是一个可迭代的字典序列
12                                      
13 #  <5>exclude(**kwargs):     它包含了与所给筛选条件不匹配的对象
14 
15 #  <6>order_by(*field):      对查询结果排序
16 
17 #  <7>reverse():             对查询结果反向排序
18 
19 #  <8>distinct():            从返回结果中剔除重复纪录
20 
21 #  <9>values_list(*field):   它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
22 
23 #  <10>count():              返回数据库中匹配查询(QuerySet)的对象数量。
24 
25 # <11>first():               返回第一条记录
26 
27 # <12>last():                返回最后一条记录
28 
29 #  <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
View Code

   扩展查询:

#扩展查询,有时候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
View Code

   惰性机制:

Book.objects.filter()或Book.objects.all()等只是返回一个QuerySet对象(查询结果集对象),并不会马上执行SQL,而是当调用QuerySet对象时才会执行SQL。

   QuerySet特点:

    <1>可迭代

   

    <2>可切片

  

  QuerySet的高效使用:

 1 #<1>Django的queryset是惰性的
 2 
 3 Django的queryset对应于数据库的若干记录(row),通过可选的查询来过滤。例如,下面的代码会得到数据库中
 4 名字为‘Dave’的所有的人:
 5 person_set = Person.objects.filter(first_name="Dave")
 6 
 7 上面的代码并没有运行任何的数据库查询。你可以使用person_set,给它加上一些过滤条件,或者将它传给某个函数,
 8 这些操作都不会发送给数据库。这是对的,因为数据库查询是显著影响web应用性能的因素之一。
 9 
10 #<2>要真正从数据库获得数据,你可以遍历queryset或者使用if queryset,总之你用到数据时就会执行sql.
11    为了验证这些,需要在settings里加入 LOGGING(验证方式)
12 
13         obj=models.Book.objects.filter(id=3)
14 
15         # for i in obj:
16         #     print(i)
17 
18         # if obj:
19         #     print("ok")
20 
21 #<3>queryset是具有cache的
22 当你遍历queryset时,所有匹配的记录会从数据库获取,然后转换成Django的model。这被称为执行(evaluation).
23 这些model会保存在queryset内置的cache中,这样如果你再次遍历这个queryset,你不需要重复运行通用的查询。
24         obj=models.Book.objects.filter(id=3)
25 
26         # for i in obj:
27         #     print(i)
28 
29         # for i in obj:
30         #     print(i)   #LOGGING只会打印一次
31 
32 
33 #<4>
34      简单的使用if语句进行判断也会完全执行整个queryset并且把数据放入cache,虽然你并不需要这些数据!
35 为了避免这个,可以用exists()方法来检查是否有数据:
36 
37 obj = Book.objects.filter(id=4)
38 #  exists()的检查可以避免数据放入queryset的cache。
39 if obj.exists():
40     print("hello world!")
41 
42 #<5>当queryset非常巨大时,cache会成为问题
43 
44 处理成千上万的记录时,将它们一次装入内存是很浪费的。更糟糕的是,巨大的queryset可能会锁住系统进程,让你的
45 程序濒临崩溃。要避免在遍历数据的同时产生queryset cache,可以使用iterator()方法来获取数据,处理完数据就
46 将其丢弃。
47 objs = Book.objects.all()
48 # iterator()可以一次只从数据库获取少量数据,这样可以节省内存
49 for obj in objs.iterator():
50     print(obj.name)
51 当然,使用iterator()方法来防止生成cache,意味着遍历同一个queryset时会重复执行查询。所以使用iterator()
52 的时候要当心,确保你的代码在操作一个大的queryset时没有重复执行查询
53 
54 总结:
55     queryset的cache是用于减少程序对数据库的查询,在通常的使用下会保证只有在需要的时候才会查询数据库。
56 使用exists()和iterator()方法可以优化程序对内存的使用。不过,由于它们并不会生成queryset cache,可能
57 会造成额外的数据库查询。
View Code

 对象查询、单表条件查询、多表条件关联查询:

 1 #--------------------对象形式的查找--------------------------
 2     # 正向查找
 3     ret1=models.Book.objects.first()
 4     print(ret1.title)
 5     print(ret1.price)
 6     print(ret1.publisher)
 7     print(ret1.publisher.name)  #因为一对多的关系所以ret1.publisher是一个对象,而不是一个queryset集合
 8 
 9     # 反向查找
10     ret2=models.Publish.objects.last()
11     print(ret2.name)
12     print(ret2.city)
13     #如何拿到与它绑定的Book对象呢?
14     print(ret2.book_set.all()) #ret2.book_set是一个queryset集合
15 
16 #---------------了不起的双下划线(__)之单表条件查询----------------
17 
18 #    models.Tb1.objects.filter(id__lt=10, id__gt=1)   # 获取id大于1 且 小于10的值
19 #
20 #    models.Tb1.objects.filter(id__in=[11, 22, 33])   # 获取id等于11、22、33的数据
21 #    models.Tb1.objects.exclude(id__in=[11, 22, 33])  # not in
22 #
23 #    models.Tb1.objects.filter(name__contains="ven")
24 #    models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
25 #
26 #    models.Tb1.objects.filter(id__range=[1, 2])   # 范围bettwen and
27 #
28 #    startswith,istartswith, endswith, iendswith,
29 
30 #----------------了不起的双下划线(__)之多表条件关联查询---------------
31 
32 # 正向查找(条件)
33 
34 #     ret3=models.Book.objects.filter(title='Python').values('id')
35 #     print(ret3)#[{'id': 1}]
36 
37       #正向查找(条件)之一对多
38 
39       ret4=models.Book.objects.filter(title='Python').values('publisher__city')
40       print(ret4)  #[{'publisher__city': '北京'}]
41       ret5=models.Book.objects.filter(publisher__address='北京').values('publisher__name')
42       print(ret5)   #[{'publisher__name': '人大出版社'}, {'publisher__name': '人大出版社'}]
43 
44       #正向查找(条件)之多对多
45       ret6=models.Book.objects.filter(title='Python').values('author__name')
46       print(ret6)
47       ret7=models.Book.objects.filter(author__name="alex").values('title')
48       print(ret7)
49 
50 # 反向查找(条件)
51 
52     #反向查找之一对多:
53     ret8=models.Publisher.objects.filter(book__title='Python').values('name')
54     print(ret8)#[{'name': '人大出版社'}]  注意,book__title中的book就是Publisher的关联表名
55 
56     ret9=models.Publisher.objects.filter(book__title='Python').values('book__authors')
57     print(ret9)#[{'book__authors': 1}, {'book__authors': 2}]
58 
59     #反向查找之多对多:
60     ret10=models.Author.objects.filter(book__title='Python').values('name')
61     print(ret10)#[{'name': 'alex'}, {'name': 'alvin'}]
View Code
>>> 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')}
View Code

<2> annotate(*args,**kwargs)

可以通过计算查询结果中每一个对象所关联的对象集合,从而得出总计值(也可以是平均值或总和),即为查询集的每一项生成聚合。

       查询alex出的书总价格                   

       

 

        查询各个作者出的书的总价格,这里就涉及到分组了,分组条件是authors__name

 

            

 

         查询各个出版社最便宜的书价是多少

 

       

 

F查询和Q查询:

 1 # F 使用查询条件的值,专门取对象中某列值的操作
 2 
 3     # from django.db.models import F
 4     # models.Tb1.objects.update(num=F('num')+1)
 5 
 6 
 7 # Q 构建搜索条件
 8     from django.db.models import Q
 9 
10     #1 Q对象(django.db.models.Q)可以对关键字参数进行封装,从而更好地应用多个查询
11     q1=models.Book.objects.filter(Q(title__startswith='P')).all()
12     print(q1)#[<Book: Python>, <Book: Perl>]
13 
14     # 2、可以组合使用&,|操作符,当一个操作符是用于两个Q的对象,它产生一个新的Q对象。
15     Q(title__startswith='P') | Q(title__startswith='J')
16 
17     # 3、Q对象可以用~操作符放在前面表示否定,也可允许否定与不否定形式的组合
18     Q(title__startswith='P') | ~Q(pub_date__year=2005)
19 
20     # 4、应用范围:
21 
22     # Each lookup function that takes keyword-arguments (e.g. filter(),
23     #  exclude(), get()) can also be passed one or more Q objects as
24     # positional (not-named) arguments. If you provide multiple Q object
25     # arguments to a lookup function, the arguments will be “AND”ed
26     # together. For example:
27 
28     Book.objects.get(
29         Q(title__startswith='P'),
30         Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
31     )
32 
33     #sql:
34     # SELECT * from polls WHERE question LIKE 'P%'
35     #     AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')
36 
37     # import datetime
38     # e=datetime.date(2005,5,6)  #2005-05-06
39 
40     # 5、Q对象可以与关键字参数查询一起使用,不过一定要把Q对象放在关键字参数查询的前面。
41     # 正确:
42     Book.objects.get(
43         Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
44         title__startswith='P')
45     # 错误:
46     Book.objects.get(
47         question__startswith='P',
48         Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))
View Code

 

原生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 8080

启动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提供的命令。

 

posted on 2016-12-01 19:32  oliver.lee  阅读(1541)  评论(0编辑  收藏  举报

导航