【转】PythonWeb框架学习Django

Django

一 什么是web框架?

框架,即framework,特指为解决一个开放性问题而设计的具备必定约束性的支撑结构,使用框架能够帮你快速开发特定的系统,简单地说,就是你用别人搭建好的舞台来作表演。html

对于全部的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端。python

import socket

def handle_request(client):

    buf = client.recv(1024)
    client.send("HTTP/1.1 200 OK\r\n\r\n".encode("utf8"))
    client.send("<h1 style='color:red'>Hello, yuan</h1>".encode("utf8"))

def main():

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind(('localhost',8001))
    sock.listen(5)

    while True:
        connection, address = sock.accept()
        handle_request(connection)
        connection.close()

if __name__ == '__main__':

    main()
View Code

 

 最简单的Web应用就是先把HTML用文件保存好,用一个现成的HTTP服务器软件,接收用户请求,从文件中读取HTML,返回。mysql

若是要动态生成HTML,就须要把上述步骤本身来实现。不过,接受HTTP请求、解析HTTP请求、发送HTTP响应都是苦力活,若是咱们本身来写这些底层代码,还没开始写动态HTML呢,就得花个把月去读HTTP规范。程序员

      正确的作法是底层代码由专门的服务器软件实现,咱们用Python专一于生成HTML文档。由于咱们不但愿接触到TCP链接、HTTP原始请求和响应格式,因此,须要一个统一的接口,让咱们专心用Python编写Web业务。web

这个接口就是WSGI:Web Server Gateway Interface。正则表达式

-----------------------------Do a web  framework ourselves---------------------------sql

step 1:

from wsgiref.simple_server import make_server


def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return [b'<h1>Hello, web!</h1>']


httpd = make_server('', 8080, application)

print('Serving HTTP on port 8000...')
# 开始监听HTTP请求:
httpd.serve_forever()
复制代码
View Code

注意:

整个application()函数自己没有涉及到任何解析HTTP的部分,也就是说,底层代码不须要咱们本身编写,
咱们只负责在更高层次上考虑如何响应请求就能够了。

application()函数必须由WSGI服务器来调用。有不少符合WSGI规范的服务器,咱们能够挑选一个来用。

Python内置了一个WSGI服务器,这个模块叫wsgiref    
    
    
application()函数就是符合WSGI标准的一个HTTP处理函数,它接收两个参数:

        //environ:一个包含全部HTTP请求信息的dict对象;
        
        //start_response:一个发送HTTP响应的函数。

在application()函数中,调用:

start_response('200 OK', [('Content-Type', 'text/html')])

就发送了HTTP响应的Header,注意Header只能发送一次,也就是只能调用一次start_response()函数。
start_response()函数接收两个参数,一个是HTTP响应码,一个是一组list表示的HTTP Header,每
个Header用一个包含两个str的tuple表示。

一般状况下,都应该把Content-Type头发送给浏览器。其余不少经常使用的HTTP Header也应该发送。

而后,函数的返回值b'<h1>Hello, web!</h1>'将做为HTTP响应的Body发送给浏览器。

有了WSGI,咱们关心的就是如何从environ这个dict对象拿到HTTP请求信息,而后构造HTML,
经过start_response()发送Header,最后返回Body。
View Code

step2shell

print(environ['PATH_INFO'])
    path=environ['PATH_INFO']
    start_response('200 OK', [('Content-Type', 'text/html')])
    f1=open("index1.html","rb")
    data1=f1.read()
    f2=open("index2.html","rb")
    data2=f2.read()

    if path=="/yuan":
        return [data1]
    elif path=="/alex":
        return [data2]
    else:
        return ["<h1>404</h1>".encode('utf8')]
View Code

step3数据库

from wsgiref.simple_server import make_server

def f1():
    f1=open("index1.html","rb")
    data1=f1.read()
    return [data1]

def f2():
    f2=open("index2.html","rb")
    data2=f2.read()
    return [data2]

def application(environ, start_response):

    print(environ['PATH_INFO'])
    path=environ['PATH_INFO']
    start_response('200 OK', [('Content-Type', 'text/html')])


    if path=="/yuan":
        return f1()

    elif path=="/alex":
        return f2()

    else:
        return ["<h1>404</h1>".encode("utf8")]


httpd = make_server('', 8502, application)

print('Serving HTTP on port 8084...')

# 开始监听HTTP请求:
httpd.serve_forever()
View Code

step4express

 

from wsgiref.simple_server import make_server


def f1(req):
    print(req)
    print(req["QUERY_STRING"])

    f1=open("index1.html","rb")
    data1=f1.read()
    return [data1]

def f2(req):

    f2=open("index2.html","rb")
    data2=f2.read()
    return [data2]

import time

def f3(req):        #模版以及数据库

    f3=open("index3.html","rb")
    data3=f3.read()
    times=time.strftime("%Y-%m-%d %X", time.localtime())
    data3=str(data3,"utf8").replace("!time!",str(times))


    return [data3.encode("utf8")]


def routers():

    urlpatterns = (
        ('/yuan',f1),
        ('/alex',f2),
        ("/cur_time",f3)
    )
    return urlpatterns


def application(environ, start_response):

    print(environ['PATH_INFO'])
    path=environ['PATH_INFO']
    start_response('200 OK', [('Content-Type', 'text/html')])


    urlpatterns = routers()
    func = None
    for item in urlpatterns:
        if item[0] == path:
            func = item[1]
            break
    if func:
        return func(environ)
    else:
        return ["<h1>404</h1>".encode("utf8")]

httpd = make_server('', 8518, application)

print('Serving HTTP on port 8084...')

# 开始监听HTTP请求:

httpd.serve_forever()
View Code

伙计们,不知不觉咱们本身已经写出一个web框架啦!

二 MVC和MTV模式

著名的MVC模式:所谓MVC就是把web应用分为模型(M),控制器(C),视图(V)三层;他们之间以一种插件似的,松耦合的方式链接在一块儿。

模型负责业务对象与数据库的对象(ORM),视图负责与用户的交互(页面),控制器(C)接受用户的输入调用模型和视图完成用户的请求。

                   

Django的MTV模式本质上与MVC模式没有什么差异,也是各组件之间为了保持松耦合关系,只是定义上有些许不一样,Django的MTV分别表明:

       Model(模型):负责业务对象与数据库的对象(ORM)

       Template(模版):负责如何把页面展现给用户

       View(视图):负责业务逻辑,并在适当的时候调用Model和Template

       此外,Django还有一个url分发器,它的做用是将一个个URL的页面请求分发给不一样的view处理,view再调用相应的Model和Template

 三 django的流程和命令行工具

django实现流程

django
    #安装: pip3 install django

          添加环境变量

    #1  建立project
       django-admin startproject mysite

       ---mysite

          ---settings.py
          ---url.py
          ---wsgi.py

       ---- manage.py(启动文件)  

    #2  建立APP       
       python mannage.py startapp  app01

    #3  settings配置
    
       TEMPLATES

       STATICFILES_DIRS=(
            os.path.join(BASE_DIR,"statics"),
        )

       STATIC_URL = '/static/' 
       #  咱们只能用 STATIC_URL,但STATIC_URL会按着你的STATICFILES_DIRS去找#4  根据需求设计代码
           url.py
           view.py

    #5  使用模版
       render(req,"index.html")   

    #6  启动项目
       python manage.py runserver  127.0.0.1:8090

    #7  链接数据库,操做数据
       model.py
View Code

 

django的命令行工具

django-admin.py 是Django的一个用于管理任务的命令行工具,manage.py是对django-admin.py的简单包装,每个Django Project里都会有一个mannage.py。

<1> 建立一个django工程 : django-admin.py startproject mysite

        当前目录下会生成mysite的工程,目录结构以下:

        

  • manage.py ----- Django项目里面的工具,经过它能够调用django shell和数据库等。
  • settings.py ---- 包含了项目的默认设置,包括数据库信息,调试标志以及其余一些工做的变量。
  • urls.py ----- 负责把URL模式映射到应用程序。

<2>在mysite目录下建立blog应用: python manage.py startapp blog

        

<3>启动django项目:python manage.py runserver 8080

       这样咱们的django就启动起来了!当咱们访问:http://127.0.0.1:8080/时就能够看到:

       

<4>生成同步数据库的脚本:python manage.py makemigrations  

                     同步数据库:  python manage.py migrate   

       注意:在开发过程当中,数据库同步误操做以后,不免会遇到后面不能同步成功的状况,解决这个问题的一个简单粗暴方法是把migrations目录下

                的脚本(除__init__.py以外)所有删掉,再把数据库删掉以后建立一个新的数据库,数据库同步操做再从新作一遍。            

<5>当咱们访问http://127.0.0.1:8080/admin/时,会出现:

       

       因此咱们须要为进入这个项目的后台建立超级管理员:python manage.py createsuperuser设置好用户名和密码后即可登陆啦!

<6>清空数据库:python manage.py  flush

<7>查询某个命令的详细信息: django-admin.py  help  startapp

       admin 是Django 自带的一个后台数据库管理系统。

<8>启动交互界面 :python manage.py  shell

     这个命令和直接运行 python 进入 shell 的区别是:你能够在这个 shell 里面调用当前项目的 models.py 中的 API,对于操做数据,还有一些小测试很是方便。

<9> 终端上输入python manage.py 能够看到详细的列表,在忘记子名称的时候特别有用

实例练习1-提交数据并展现

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>建立我的信息</h1>

<form action="/userInfor/" method="post">

    <p>姓名<input type="text" name="username"></p>
    <p>性别<input type="text" name="sex"></p>
    <p>邮箱<input type="text" name="email"></p>
    <p><input type="submit" value="submit"></p>

</form>

<hr>

<h1>信息展现</h1>

<table border="1">

    <tr>
        <td>姓名</td>
        <td>性别</td>
        <td>邮箱</td>
    </tr>
    {% for i in info_list %}

        <tr>
            <td>{{ i.username }}</td>
            <td>{{ i.sex }}</td>
            <td>{{ i.email }}</td>
        </tr>

    {% endfor %}

</table>

</body>
</html>


-----------------------url.py---------------------------------------
url(r'^userInfor/', views.userInfor)

-----------------------views.py--------------------------------------

info_list=[]

def userInfor(req):

    if req.method=="POST":
        username=req.POST.get("username",None)
        sex=req.POST.get("sex",None)
        email=req.POST.get("email",None)

        info={"username":username,"sex":sex,"email":email}
        info_list.append(info)

    return render(req,"userInfor.html",{"info_list":info_list})
View Code

 

实例练习2-提交数据并展现(数据库)

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>建立我的信息</h1>

<form action="/userInfor/" method="post">

    <p>姓名<input type="text" name="username"></p>
    <p>性别<input type="text" name="sex"></p>
    <p>邮箱<input type="text" name="email"></p>
    <p><input type="submit" value="submit"></p>

</form>

<hr>

<h1>信息展现</h1>

<table border="1">

    <tr>
        <td>姓名</td>
        <td>性别</td>
        <td>邮箱</td>
    </tr>
    {% for i in info_list %}

        <tr>
            <td>{{ i.username }}</td>
            <td>{{ i.sex }}</td>
            <td>{{ i.email }}</td>
        </tr>

    {% endfor %}

</table>

</body>
</html>


----------------------------------------------models.py
from django.db import models

# Create your models here.


class UserInfor(models.Model):

    username=models.CharField(max_length=64)
    sex=models.CharField(max_length=64)
    email=models.CharField(max_length=64)

----------------------------------------------views.py

from django.shortcuts import render

from app01 import models
# Create your views here.


def userInfor(req):

    if req.method=="POST":
        u=req.POST.get("username",None)
        s=req.POST.get("sex",None)
        e=req.POST.get("email",None)


       #---------表中插入数据方式一
            # info={"username":u,"sex":e,"email":e}
            # models.UserInfor.objects.create(**info)

       #---------表中插入数据方式二
        models.UserInfor.objects.create(
            username=u,
            sex=s,
            email=e
        )

        info_list=models.UserInfor.objects.all()

        return render(req,"userInfor.html",{"info_list":info_list})

    return render(req,"userInfor.html")
View Code

 

 

 

四 Django的配置文件(settings)

静态文件设置:

  View Code

其它重要参数设置:

复制代码
APPEND_SLASH
       Default: True
       When set to True, if the request URL does not match any of the patterns in the URLconf and it 
doesn’t end in a slash, an HTTP redirect is issued to the same URL with a slash appended. Note
that the redirect may cause any data submitted in a POST request to be lost.
复制代码

五 Django URL (路由系统)

     URL配置(URLconf)就像Django 所支撑网站的目录。它的本质是URL模式以及要为该URL模式调用的视图函数之间的映射表;你就是以这种方式告诉Django,对于这个URL调用这段代码,对于那个URL调用那段代码。

1
2
3
urlpatterns = [
     url(正则表达式, views视图函数,参数,别名),
]

参数说明:

  • 一个正则表达式字符串
  • 一个可调用对象,一般为一个视图函数或一个指定视图函数路径的字符串
  • 可选的要传递给视图函数的默认参数(字典形式)
  • 一个可选的name参数

5.1 Here’s a sample URLconf:

复制代码
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),

]
复制代码

Note:

  View Code

5.2 Named groups

      The above example used simple, non-named regular-expression groups (via parenthesis) to capture bits of the URL and pass them as positional arguments to a view. In more advanced usage, it’s possible to use named regular-expression groups to capture URL bits and pass them as keyword arguments to a view.

       In Python regular expressions, the syntax for named regular-expression groups is (?P<name>pattern), where name is the name of the group and pattern is some pattern to match.

Here’s the above example URLconf, rewritten to use named groups:

  ready
复制代码
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),
    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),
]
复制代码

       This accomplishes exactly the same thing as the previous example, with one subtle difference: The captured values are passed to view functions as keyword arguments rather than positional arguments.

5.3  Passing extra options to view functions

       URLconfs have a hook that lets you pass extra arguments to your view functions, as a Python dictionary.

The django.conf.urls.url() function can take an optional third argument which should be a dictionary of extra keyword arguments to pass to the view function.

For example:

from django.conf.urls import url
from . import views
  
urlpatterns = [
    url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}),
]

       In this example, for a request to /blog/2005/, Django will call views.year_archive(request, year='2005',foo='bar').

This technique is used in the syndication framework to pass metadata and options to views.

Dealing with conflicts

       It’s possible to have a URL pattern which captures named keyword arguments, and also passes arguments with the same names in its dictionary of extra arguments. When this happens, the arguments in the dictionary will be used instead of the arguments captured in the URL.

5.4 name param

  View Code

5.5 Including other URLconfs

复制代码
#At any point, your urlpatterns can “include” other URLconf modules. This
#essentially “roots” a set of URLs below other ones.

#For example, here’s an excerpt of the URLconf for the Django website itself.
#It includes a number of other URLconfs:


from django.conf.urls import include, url

urlpatterns = [
   url(r'^admin/', admin.site.urls),
   url(r'^blog/', include('blog.urls')),
]
复制代码

六 Django Views(视图函数)

http请求中产生两个核心对象:

        http请求:HttpRequest对象

        http响应:HttpResponse对象

所在位置:django.http

以前咱们用到的参数request就是HttpRequest    检测方法:isinstance(request,HttpRequest)

1 HttpRequest对象的属性和方法:

  View Code

注意一个经常使用方法:request.POST.getlist('')

2 HttpResponse对象:

  对于HttpRequest对象来讲,是由django自动建立的,可是,HttpResponse对象就必须咱们本身建立。每一个view请求处理方法必须返回一个HttpResponse对象。

  HttpResponse类在django.http.HttpResponse

  在HttpResponse对象上扩展的经常使用方法:

1
2
3
页面渲染:         render()(推荐)<br>                 render_to_response(),
页面跳转:         redirect( "路径" )
locals():    能够直接将函数中全部的变量传给模板

补充:

  View Code 

七 Template基础 

模板系统的介绍

你可能已经注意到咱们在例子视图中返回文本的方式有点特别。 也就是说,HTML被直接硬编码在 Python代码之中。

def current_datetime(request):
    now = datetime.datetime.now()
    html = "<html><body>It is now %s.</body></html>" % now
    return HttpResponse(html)

尽管这种技术便于解释视图是如何工做的,但直接将HTML硬编码到你的视图里却并非一个好主意。 让咱们来看一下为何:

  • 对页面设计进行的任何改变都必须对 Python 代码进行相应的修改。 站点设计的修改每每比底层 Python 代码的修改要频繁得多,所以若是能够在不进行 Python 代码修改的状况下变动设计,那将会方便得多。

  • Python 代码编写和 HTML 设计是两项不一样的工做,大多数专业的网站开发环境都将他们分配给不一样的人员(甚至不一样部门)来完成。 设计者和HTML/CSS的编码人员不该该被要求去编辑Python的代码来完成他们的工做。

  • 程序员编写 Python代码和设计人员制做模板两项工做同时进行的效率是最高的,远胜于让一我的等待另外一我的完成对某个既包含 Python又包含 HTML 的文件的编辑工做。

基于这些缘由,将页面的设计和Python的代码分离开会更干净简洁更容易维护。 咱们可使用 Django的 模板系统 (Template System)来实现这种模式,这就是本章要具体讨论的问题。

------------------------------------------------------------------模板语法------------------------------------------------------------------

一模版的组成

组成:HTML代码+逻辑控制代码

二 逻辑控制代码的组成

1  变量(使用双大括号来引用变量):

1
语法格式:       {{var_name}}

------Template和Context对象

  View Code

 Django 模板解析很是快捷。 大部分的解析工做都是在后台经过对简短正则表达式一次性调用来完成。 这和基于 XML 的模板引擎造成鲜明对比,那些引擎承担了 XML 解析器的开销,且每每比 Django 模板渲染引擎要慢上几个数量级。

  推荐方式

------深度变量的查找(万能的句点号)

在到目前为止的例子中,咱们经过 context 传递的简单参数值主要是字符串,然而,模板系统可以很是简洁地处理更加复杂的数据结构,例如list、dictionary和自定义的对象。

在 Django 模板中遍历复杂数据结构的关键是句点字符 (.)。

  View Code

------变量的过滤器(filter)的使用

1
语法格式:      {{obj|filter:param}}
  View Code

2 标签(tag)的使用(使用大括号和百分比的组合来表示使用tag)

1
{% tags %}

------{% if %} 的使用 

{% if %}标签计算一个变量值,若是是“true”,即它存在、不为空而且不是false的boolean值,系统则会显示{% if %}和{% endif %}间的全部内容

  View Code

------{% for %}的使用

{% for %}标签容许你按顺序遍历一个序列中的各个元素,每次循环模板系统都会渲染{% for %}和{% endfor %}之间的全部内容

  View Code

------{%csrf_token%}:csrf_token标签

     用于生成csrf_token的标签,用于防治跨站攻击验证。注意若是你在view的index里用的是render_to_response方法,不会生效

     其实,这里是会生成一个input标签,和其余表单标签一块儿提交给后台的。

------{% url %}:  引用路由配置的地址

  View Code

------{% with %}:用更简单的变量名替代复杂的变量名

1
{% with total=fhjsaldfhjsdfhlasdfhljsdal %} {{ total }} {% endwith %}

------{% verbatim %}: 禁止render

1
2
3
{% verbatim %}
          {{ hello }}
{% endverbatim %}

------{% load %}: 加载标签库 

3 自定义filter和simple_tag

------a、在app中建立templatetags模块(必须的)

------b、建立任意 .py 文件,如:my_tags.py

  View Code

------c、在使用自定义simple_tag和filter的html文件中导入以前建立的 my_tags.py :{% load my_tags %}

------d、使用simple_tag和filter(如何调用)

  View Code

------e、在settings中的INSTALLED_APPS配置当前app,否则django没法找到自定义的simple_tag.

注意:

filter能够用在if等语句后,simple_tag不能够

  View Code

extend模板继承

------include 模板标签

在讲解了模板加载机制以后,咱们再介绍一个利用该机制的内建模板标签: {% include %} 。该标签容许在(模板中)包含其它的模板的内容。 标签的参数是所要包含的模板名称,能够是一个变量,也能够是用单/双引号硬编码的字符串。 每当在多个模板中出现相同的代码时,就应该考虑是否要使用 {% include %} 来减小重复。

------extend(继承)模板标签

到目前为止,咱们的模板范例都只是些零星的 HTML 片断,但在实际应用中,你将用 Django 模板系统来建立整个 HTML 页面。 这就带来一个常见的 Web 开发问题: 在整个网站中,如何减小共用页面区域(好比站点导航)所引发的重复和冗余代码?

解决该问题的传统作法是使用 服务器端的 includes ,你能够在 HTML 页面中使用该指令将一个网页嵌入到另外一个中。 事实上, Django 经过刚才讲述的 {% include %} 支持了这种方法。 可是用 Django 解决此类问题的首选方法是使用更加优雅的策略—— 模板继承 。

本质上来讲,模板继承就是先构造一个基础框架模板,然后在其子模板中对它所包含站点公用部分和定义块进行重载。

让咱们经过修改 current_datetime.html 文件,为 current_datetime 建立一个更加完整的模板来体会一下这种作法:

  View Code

这看起来很棒,但若是咱们要为 hours_ahead 视图建立另外一个模板会发生什么事情呢?

  View Code

很明显,咱们刚才重复了大量的 HTML 代码。 想象一下,若是有一个更典型的网站,它有导航条、样式表,可能还有一些 JavaScript 代码,事情必将以向每一个模板填充各类冗余的 HTML 而了结。

解决这个问题的服务器端 include 方案是找出两个模板中的共同部分,将其保存为不一样的模板片断,而后在每一个模板中进行 include。 也许你会把模板头部的一些代码保存为 header.html 文件:

  View Code

你可能会把底部保存到文件 footer.html :

  View Code

对基于 include 的策略,头部和底部的包含很简单。 麻烦的是中间部分。 在此范例中,每一个页面都有一个<h1>My helpful timestamp site</h1> 标题,可是这个标题不能放在 header.html 中,由于每一个页面的 <title> 是不一样的。 若是咱们将 <h1> 包含在头部,咱们就不得不包含 <title> ,但这样又不容许在每一个页面对它进行定制。 何去何从呢?

Django 的模板继承系统解决了这些问题。 你能够将其视为服务器端 include 的逆向思惟版本。 你能够对那些不一样 的代码段进行定义,而不是 共同 代码段。

第一步是定义 基础模板,该框架以后将由子模板所继承。 如下是咱们目前所讲述范例的基础模板:

  View Code

这个叫作 base.html 的模板定义了一个简单的 HTML 框架文档,咱们将在本站点的全部页面中使用。 子模板的做用就是重载、添加或保留那些块的内容。 (若是你一直按顺序学习到这里,保存这个文件到你的template目录下,命名为 base.html .)

咱们使用模板标签: {% block %} 。 全部的 {% block %} 标签告诉模板引擎,子模板能够重载这些部分。 每一个{% block %}标签所要作的是告诉模板引擎,该模板下的这一块内容将有可能被子模板覆盖。

如今咱们已经有了一个基本模板,咱们能够修改 current_datetime.html 模板来 使用它:

  View Code

再为 hours_ahead 视图建立一个模板,看起来是这样的:

  View Code

看起来很漂亮是否是? 每一个模板只包含对本身而言 独一无二 的代码。 无需多余的部分。 若是想进行站点级的设计修改,仅需修改 base.html ,全部其它模板会当即反映出所做修改。

      如下是其工做方式:

      在加载 current_datetime.html 模板时,模板引擎发现了 {% extends %} 标签, 注意到该模板是一个子模板。 模板引擎当即装载其父模板,即本例中的 base.html 。此时,模板引擎注意到 base.html 中的三个 {% block %} 标签,并用子模板的内容替换这些 block 。所以,引擎将会使用咱们在 block title %} 中定义的标题,对 {% block content %} 也是如此。 因此,网页标题一块将由{% block title %}替换,一样地,网页的内容一块将由 {% block content %}替换。

     注意因为子模板并无定义 footer 块,模板系统将使用在父模板中定义的值。 父模板 {% block %} 标签中的内容老是被看成一条退路。继承并不会影响到模板的上下文。 换句话说,任何处在继承树上的模板均可以访问到你传到模板中的每个模板变量。你能够根据须要使用任意多的继承次数。 使用继承的一种常见方式是下面的三层法:

   <1> 建立 base.html 模板,在其中定义站点的主要外观感觉。 这些都是不常修改甚至从不修改的部分。
   <2> 为网站的每一个区域建立 base_SECTION.html 模板(例如, base_photos.html 和 base_forum.html )。这些模板对base.html 进行拓展,
并包含区域特定的风格与设计。 <3> 为每种类型的页面建立独立的模板,例如论坛页面或者图片库。 这些模板拓展相应的区域模板。

      这个方法可最大限度地重用代码,并使得向公共区域(如区域级的导航)添加内容成为一件轻松的工做。

如下是使用模板继承的一些诀窍:

  View Code

八 Models

数据库的配置

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里有以下设置:

           

若是咱们想要更改数据库,须要修改以下:

           

  View Code

注意:

  View Code

ORM(对象关系映射)

用于实现面向对象编程语言里不一样类型系统的数据之间的转换,换言之,就是用面向对象的方式去操做数据库的建立表以及增删改查等操做。

优势: 1 ORM使得咱们的通用数据库交互变得简单易行,并且彻底不用考虑该死的SQL语句。快速开发,由此而来。

          2 能够避免一些新手程序猿写sql语句带来的性能问题。

            好比 咱们查询User表中的全部字段:

            

            新手可能会用select * from  auth_user,这样会由于多了一个匹配动做而影响效率的。

 缺点:1  性能有所牺牲,不过如今的各类ORM框架都在尝试各类方法,好比缓存,延迟加载登来减轻这个问题。效果很显著。

          2  对于个别复杂查询,ORM仍然力不从心,为了解决这个问题,ORM通常也支持写raw sql。

          3  经过QuerySet的query属性查询对应操做的sql语句

1
2
author_obj=models.Author.objects.filter(id=2)
print(author_obj.query)

     下面要开始学习Django ORM语法了,为了更好的理解,咱们来作一个基本的 书籍/做者/出版商 数据库结构。 咱们这样作是由于 这是一个众所周知的例子,不少SQL有关的书籍也经常使用这个举例。

表(模型)的建立:

实例:咱们来假定下面这些概念,字段和关系

做者模型:一个做者有姓名。

做者详细模型:把做者的详情放到详情表,包含性别,email地址和出生日期,做者详情模型和做者模型之间是一对一的关系(one-to-one)(相似于每一个人和他的身份证之间的关系),在大多数状况下咱们没有必要将他们拆分红两张表,这里只是引出一对一的概念。

出版商模型:出版商有名称,地址,所在城市,省,国家和网站。

书籍模型:书籍有书名和出版日期,一本书可能会有多个做者,一个做者也能够写多本书,因此做者和书籍的关系就是多对多的关联关系(many-to-many),一本书只应该由一个出版商出版,因此出版商和书籍是一对多关联关系(one-to-many),也被称做外键。

  View Code

注意1:记得在settings里的INSTALLED_APPS中加入'app01',而后再同步数据库。

注意2: models.ForeignKey("Publish") & models.ForeignKey(Publish)

分析代码:

       <1>  每一个数据模型都是django.db.models.Model的子类,它的父类Model包含了全部必要的和数据库交互的方法。并提供了一个简介漂亮的定义数据库字段的语法。

       <2>  每一个模型至关于单个数据库表(多对多关系例外,会多生成一张关系表),每一个属性也是这个表中的字段。属性名就是字段名,它的类型(例如CharField)至关于数据库的字段类型(例如varchar)。你们能够留意下其它的类型都和数据库里的什么字段对应。

       <3>  模型之间的三种关系:一对一,一对多,多对多。

             一对一:实质就是在主外键(author_id就是foreign key)的关系基础上,给外键加了一个UNIQUE=True的属性;

             一对多:就是主外键关系;(foreign key)

             多对多:(ManyToManyField) 自动建立第三张表(固然咱们也能够本身建立第三张表:两个foreign key)

       <4>  模型经常使用的字段类型参数

  View Code

       <5>  Field重要参数

  View Code

表的操做(增删改查):

-------------------------------------增(create  ,  save) -------------------------------

复制代码
from app01.models import *

    #create方式一:   Author.objects.create(name='Alvin')

    #create方式二:   Author.objects.create(**{"name":"alex"})

    #save方式一:     author=Author(name="alvin")
                    author.save()

    #save方式二:     author=Author()
                    author.name="alvin"
                    author.save()
复制代码

重点来了------->那么如何建立存在一对多或多对多关系的一本书的信息呢?(如何处理外键关系的字段如一对多的publisher和多对多的authors)

  View Code

-----------------------------------------删(delete) ---------------------------------------------

>>> Book.objects.filter(id=1).delete()
(3, {'app01.Book_authors': 2, 'app01.Book': 1})

咱们表面上删除了一条信息,实际却删除了三条,由于咱们删除的这本书在Book_authors表中有两条相关信息,这种删除方式就是django默认的级联删除。

若是是多对多的关系: remove()和clear()方法: 

复制代码
#正向
book = models.Book.objects.filter(id=1)

#删除第三张表中和女孩1关联的全部关联信息
book.author.clear()        #清空与book中id=1 关联的全部数据
book.author.remove(2)  #能够为id
book.author.remove(*[1,2,3,4])     #能够为列表,前面加*

#反向
author = models.Author.objects.filter(id=1)
author.book_set.clear() #清空与boy中id=1 关联的全部数据
复制代码

-----------------------------------------改(update和save) ----------------------------------------

实例:

    

注意:

<1> 第二种方式修改不能用get的缘由是:update是QuerySet对象的方法,get返回的是一个model对象,它没有update方法,而filter返回的是一个QuerySet对象(filter里面的条件可能有多个条件符合,好比name='alvin',可能有两个name='alvin'的行数据)。

<2>在“插入和更新数据”小节中,咱们有提到模型的save()方法,这个方法会更新一行里的全部列。 而某些状况下,咱们只须要更新行里的某几列。

  View Code

      在这个例子里咱们能够看到Django的save()方法更新了不只仅是title列的值,还有更新了全部的列。 若title之外的列有可能会被其余的进程所改动的状况下,只更改title列显然是更加明智的。更改某一指定的列,咱们能够调用结果集(QuerySet)对象的update()方法,与之等同的SQL语句变得更高效,而且不会引发竞态条件。

此外,update()方法对于任何结果集(QuerySet)均有效,这意味着你能够同时更新多条记录update()方法会返回一个整型数值,表示受影响的记录条数。

注意,这里由于update返回的是一个整形,因此无法用query属性;对于每次建立一个对象,想显示对应的raw sql,须要在settings加上日志记录部分:

  LOGGING

注意:若是是多对多的改:

 

    obj=Book.objects.filter(id=1)[0]
    author=Author.objects.filter(id__gt=2)

    obj.author.clear()
    obj.author.add(*author)

 

 

---------------------------------------查(filter,value等) -------------------------------------

---------->查询API:

  View Code

补充:

  extra

---------->惰性机制:

所谓惰性机制:Publisher.objects.all()或者.filter()等都只是返回了一个QuerySet(查询结果集对象),它并不会立刻执行sql,而是当调用QuerySet的时候才执行。

QuerySet特色:

       <1>  可迭代的

       <2>  可切片

  View Code

QuerySet的高效使用:

  View Code

---------->对象查询,单表条件查询,多表条件关联查询

  View Code

注意:条件查询即与对象查询对应,是指在filter,values等方法中的经过__来明确查询条件。

---------->聚合查询和分组查询

<1> aggregate(*args,**kwargs):

   经过对QuerySet进行计算,返回一个聚合值的字典。aggregate()中每个参数都指定一个包含在字典中的返回值。即在查询集上生成聚合。

  View Code

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

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

       查询alex出的书总价格                   

       

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

           

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

       

---------->F查询和Q查询

仅仅靠单一的关键字参数查询已经很难知足查询要求。此时Django为咱们提供了F和Q查询:

  View Code

raw sql

django中models的操做,也是调用了ORM框架来实现的,pymysql 或者mysqldb,因此咱们也可使用原生的SQL语句来操做数据库!

九 admin的配置

admin是django强大功能之一,它能共从数据库中读取数据,呈如今页面中,进行管理。默认状况下,它的功能已经很是强大,若是你不须要复杂的功能,它已经够用,可是有时候,一些特殊的功能还须要定制,好比搜索功能,下面这一系列文章就逐步深刻介绍如何定制适合本身的admin应用。

若是你以为英文界面很差用,能够在setting.py 文件中修改如下选项

1
LANGUAGE_CODE  =  'en-us'   #LANGUAGE_CODE = 'zh-hans'

一  认识ModelAdmin

   管理界面的定制类,如需扩展特定的model界面需从该类继承。

二 注册medel类到admin的两种方式:

     <1>   使用register的方法

1
admin.site.register(Book,MyAdmin)

     <2>   使用register的装饰器

1
@admin .register(Book)

三 掌握一些经常使用的设置技巧

  •     list_display:     指定要显示的字段
  •     search_fields:  指定搜索的字段
  •     list_filter:        指定列表过滤器
  •     ordering:       指定排序字段
复制代码
from django.contrib import admin
from app01.models import *
# Register your models here.

# @admin.register(Book)#----->单给某个表加一个定制
class MyAdmin(admin.ModelAdmin):
    list_display = ("title","price","publisher")
    search_fields = ("title","publisher")
    list_filter = ("publisher",)
    ordering = ("price",)
    fieldsets =[
        (None,               {'fields': ['title']}),
        ('price information', {'fields': ['price',"publisher"], 'classes': ['collapse']}),
    ]

admin.site.register(Book,MyAdmin)
admin.site.register(Publish)
admin.site.register(Author)
复制代码

 

参考文献:http://www.admin10000.com/document/2220.html

转自:http://www.cnblogs.com/yuanchenqi/articles/6083427.html

相关文章
相关标签/搜索