Django基础篇 01: Django基础篇

01: Django基础篇

 

目录:Django其他篇

01:Django基础篇

02:Django进阶篇

03:Django数据库操作--->Model

04: Form 验证用户数据 & 生成html

05:ModelForm 数据验证 & 生成html & 数据库操作

06: Django Admin

07: Django 学习补充

目录:

django参考网站

1.1 Web框架本质----socket

  1、web框架本质

      1. 对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端。

      2. 真实web框架一般会分为两部分:服务器程序和应用程序。  

          1)服务器程序负责对socket服务器进行封装,并在请求到来时,对请求的各种数据进行整理

          2)应用程序则负责具体的逻辑处理

  2、WSGI(Web Server Gateway Interface)

      1. 不同的框架有不同的开发方式,但是无论如何,开发出的应用程序都要和服务器程序配合,才能为用户提供服务。

      2. 这样,服务器程序就需要为不同的框架提供不同的支持,只有支持它的服务器才能被开发出的应用使用,这时就需要有一个标准

      3. WSGI是一种规范,它定义了使用python编写的web app与web server之间接口格式,实现web app与web server间的解耦。

  3、使用socket创建一个简单web服务

  使用socket创建一个简单web服务
import socket

def handle_request(client):
    buf = client.recv(1024)
    client.send("HTTP/1.1 200 OK\r\n\r\n".encode('utf-8'))      # 伪造浏览器请求头
    client.send("Hello, Seven".encode('utf-8'))                  # 返回数据到客户端浏览器

def main():
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind(('localhost', 8000))
    sock.listen(5)
    while True:
        connection, address = sock.accept()
        handle_request(connection)
        connection.close()

if __name__ == '__main__':
    main()

  4、自定义Web框架

      说明: 通过python标准库提供的wsgiref模块开发一个自己的Web框架

  自定义web框架
from wsgiref.simple_server import make_server

def handle_index():
    return ['<h1>Hello, Index!</h1>'.encode('utf-8'),]
def handle_date():
    return ['<h1>Hello, date!</h1>'.encode('utf-8'),]

URl_DICT = {
    "/index":handle_index,
    "/date":handle_date,
}

#1 environ客户端发来的所有数据
#2 start_response封装要返回给用户的数据,响应头状态
#3 return返回的是正真用户在浏览器中看到的内容(Hello, web!)
def RunServer(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    current_url = environ['PATH_INFO']                           #用户访问的url目录:/index 或 /date
    func = None
    if current_url in URl_DICT:
        func = URl_DICT[current_url]
        return func()
    else:
        return ['<h1>404</h1>'.encode('utf-8'),]

if __name__ == '__main__':
    httpd = make_server('', 8001, RunServer)
    print("Serving HTTP on port 8000...")
    httpd.serve_forever()

1.2 MVC和MTV架构

  1、MVC架构

      1. MVC架构把一个完整的程序或者网站项目分成三个主要的组成部分,分别是Model模型,View视图,Controller控制器

      2. 希望一个项目可以让内部数据的储存方式,外部的可见部分以及过程控制逻辑相互配合运行

      3. 进一步简化项目复杂度,提高可扩充性,维护性,有助于不同成员之间的分工

  2、MTV框架(Django)

      1. 对于网站而言,网页服务器在接收到远程浏览器的请求的时候,不同的网址做出不同的响应

      2. 有不同的链接方式其实就隐含了逻辑控制,因此很难严谨的将其定义为上述三个部分

      3. 因此Django另外设计了MTV结构(Model,Template,View)。

  3、MVC vs MTV

    MVC

        Model       View          Controller

        数据库      模板文件      业务处理

    MTV

        Model      Template       View

        数据库      模板文件      业务处理

1.3 Django常用命令

  1、安装Django

      pip3 install django

  2、创建Django工程

      D:\>  django-admin startproject laoniu                                               //创建项目名称laoniu

      D:\>  cd laoniu

      D:\laoniu>  python manage.py runserver 127.0.0.1:8002                 //运行laoniu即可用浏览器访问了

      D:\laoniu>  python manage.py createsuperuser                               //创建Django admin用户

  3、创建app

      python manage.py startapp app01

  4、创建表  

      python manage.py makemigrations
      python manage.py migrate

  5、执行python manage.py migrate无法创建表

      执行时报:No migrations to apply.

      1. 进入数据库,找到django_migrations的表,删除该app名字对应的所有记录

          python manage.py dbshell
          delete from django_migrations where app='app01';

      2. 删除该app名字下的migrations下的除了__init__.py之外的文件。

      3. 执行下面这两条命令:(在项目目录下)

          python manage.py makemigrations
          python manage.py migrate

                注:如果个别app表依然无法建立可以在后面添加app名称:python manage.py makemigrations/migrate app01

  6、“Column 'last_login' cannot be null”报错

      mysql> SELECT * FROM django_migrations;

      mysql> TRUNCATE TABLE django_migrations;

      $ python manage.py migrate --fake-initial
      Make sure this message appears: 0005_alter_user_last_login_null - [OK]

  7、windows中杀死指定端口号进程

      D:\>netstat -aon|findstr "8000"
      D:\>taskkill /PID 12516 -t -f

1.4 配置settings.py文件

  1、配置模板的路径

TEMPLATES = [
    {
       'DIRS': [os.path.join(BASE_DIR,'templates')],
    },
]

  2、 配置静态目录

#像ccs和js这些静态文件如果想要使用必须在这里配置路径
STATICFILES_DIRS = (
    os.path.join(BASE_DIR,'static'),
)

  3、注释CSRF

MIDDLEWARE = [
    # 'django.middleware.csrf.CsrfViewMiddleware',
]

  4、修改settings.py中时区

  修改settings.py中时区
# LANGUAGE_CODE = 'en-us'
LANGUAGE_CODE = 'zh-hans'

# TIME_ZONE = 'UTC'
TIME_ZONE = 'Asia/Shanghai'

1.5 Django各种url写法

  1、无正则匹配url  (http://127.0.0.1:8000/index/?nid=1&pid=2)

  urls.py
urlpatterns = [
    url(r'^index/', views.index),
]
  views.py
from django.shortcuts import render

def index(request):
    print(request.GET.get('nid'))             # 1
    print(request.GET.get('pid'))             # 2
    return render(request,'index.html')
  index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <a href="/index/?nid=1&pid=2"> url.py中不必用正则匹配 </a>
</body>
</html>

  2、基于(\d+)正则的url

  urls.py
urlpatterns = [
    url(r'^index/(\d+)/(\d+)/', views.index),
]
  views.py
def index(request,nid,pid):
    return render(request,'index.html')
  index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <a href="/index/1/2/"> url.py中必须使用正则匹配传入的参数 </a>
</body>
</html>

  3、基于正则分组(?P<nid>\d+),可以不考虑接收参数顺序 (推荐)

  urls.py
urlpatterns = [
    url(r'^index/(?P<nid>\d+)/(?P<pid>\d+)/', views.index),
]
  views.py
def index(request,nid,pid):
    return render(request,'index.html')
  index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <a href="/index/1/2/"> 使用分组匹配,不必关心传入参数顺序 </a>
</body>
</html>

  4、使用name构建自己想要的url

     1. 使用name在前端和后端分别构建自己想要的url

  urls.py中定义路由系统
urlpatterns = [
    url(r'^index1/', views.index,name='indexname1'),
    url(r'^index2/(\d+)/(\d+)/', views.index,name='indexname2'),
    url(r'^index2/(?P<pid>\d+)/(?P<nid>\d+)/', views.index,name='indexname3'),
]
  views.py中根据reverse模块构建url路径
from django.shortcuts import render
from django.core.urlresolvers import reverse

def index(request,*args,**kwargs):
    url1 = reverse('indexname1')                                      # /index1/
    url2 = reverse('indexname2', args=(1,2,))                         # /index2/1/2/
    url3 = reverse('indexname3', kwargs={'pid': 11, "nid":22})        # /index2/11/22/
    return render(request,'index.html')
  index.html中构建url路径:前端
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <p><a href="{% url 'indexname1' %}">  http://127.0.0.1:8000/index/  </a></p>
    <p><a href="{% url 'indexname2' 1 2 %}">  http://127.0.0.1:8000/index2/1/2/  </a></p>
    <p><a href="{% url 'indexname3' 11 22 %}">  http://127.0.0.1:8000/index2/11/22/  </a></p>
</body>
</html>

    2. 根据request.path中的绝对路径反解出url中的name名字

resolve_url_obj = resolve(request.path)    #request.path路径: /student/homework_detail/52
resolve_url_obj.url_name                   #从path中解析出url名字 url_name = homework_detail

  5、Django路由分发    并使用name构建url路径

      作用:对URL路由关系进行命名, ***** 以后可以根据此名称生成自己想要的URL *****

  /project/urls.py
from django.conf.urls import url,include
from app01 import urls

urlpatterns = [
    url(r'^app01/', include("app01.urls", app_name='app01', namespace='app01')),
]
  /app01/urls.py
from django.conf.urls import url
from app01 import views

urlpatterns = [
    url(r'^index/$', views.index, name='index'),
]
  views.py
from django.shortcuts import render

def index(request):
    return render(request,'index.html')
  index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <p> <a href="{% url "app01:index" %}">  http://127.0.0.1:8000/app01/index/</a></p>
</body>
</html>

1.6 Django的CBV和FBV

  1、FBVfunction  base  view:views.py文件中使用函数

  FBV写法
def index(request):
    return render(request, 'index.html')

  2、CBV(class  base  view):在views.py文件中使用类

      1、 dispatch是父类中用来反射的函数,找对应的函数(比对应函数先执行)

      2、 比如你发送post请求就可以通过dispatch找到对应的post函数进行处理,get就会找到get函数处理

  CBV:urls.py
from django.conf.urls import url
from app01 import views

urlpatterns = [
    url(r'^home/',views.Home.as_view()), #as_view是指定调用view的as_view这个方法固定写法
]
  CBV:views.py
from django.shortcuts import HttpResponse

from django.views import View
class Home(View):
    '''使用CBV时必须要继承view父类'''
    def dispatch(self, request, *args, **kwargs):
        # 调用父类中的dispatch
        result = super(Home,self).dispatch(request, *args, **kwargs)
        # 使用result主动继承view父类,然后return就可以重写父类的dispath方法
        return result
    # 在这里使用get发来请求就会调用get方法,使用post发来请求就会调用post方法
    def get(self,request):
        print(request.method)
        return HttpResponse('get')

    def post(self,request):
        print(request.method,'POST')
        return HttpResponse('post')
  CBC:指定某个视图函数不使用csrf验证
from django.shortcuts import HttpResponse
from django.views import View
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt

class Home(View):
    '''使用CBV时必须要继承view父类'''
    @method_decorator(csrf_exempt)        # 指定Home这个视图函数不使用csrf
    def dispatch(self, request, *args, **kwargs):
        # 调用父类中的dispatch
        result = super(Home,self).dispatch(request, *args, **kwargs)
        # 使用result主动继承view父类,然后return就可以重写父类的dispath方法
        return result
    # 在这里使用get发来请求就会调用get方法,使用post发来请求就会调用post方法
    def get(self,request):
        print(request.method)
        return HttpResponse('get')

    def post(self,request):
        print(request.method,'POST')
        return HttpResponse('post')

1.7 模板渲染

  1、for循环

  for循环字典
<body>
    {% for k in user_dic.keys %}
        <p>{{ k }}</p>
    {% endfor %}

    {% for v in user_dic.values %}
        <p>{{ v }}</p>
    {% endfor %}

    {% for k,v in user_dic.items %}
        <p>{{ k }}--{{ v }}</p>
    {% endfor %}
</body>
  for循环列表
<body>
    {% for k in l %}
        <p>{{ k }}</p>
    {% endfor %}
</body>

  2if语句

  views.py视图函数
def index(request):
    return render(request,'index.html',{
        'current_user':"alex",
        'user_list':['alex','eric'],
        'user_dict':{'k1':'v1', 'k2':'v2'}
    })
  index.html模板渲染
<div>{{current_user}}</div>

<a> {{ user_list.1 }} </a>          #在模板语言中获取列表中的元素
<a> {{ user_dict.k1 }} </a>         #在模板语言中获取字典中元素

{% if age %}
   <a>有年龄</a>
   {% if age > 16 %}
      <a>老男人</a>
   {% else %}
      <a>小鲜肉</a>
   {% endif %}
{% else %}
   <a>无年龄</a>
{% endif %}

   3、ifequal判断值相等

  判断两个值是否相等
{% ifequal a1 a2 %}
            <h1>equal!</h1>
        {% else %}
            <h1>not equal!</h1>
        {% endifequal %}

  4、in判断在列表中

  in判断是否在列表中
{% if '讲师' in roles %}
<ul class="nav nav-sidebar">
  <li><a data-url="/webapp/staff/attendance/">发起签到</a></li>
  <li><a data-url="/webapp/staff/score/">学员成绩</a></li>
</ul>
{% endif %}

  5、HTML中转换时间格式

  时间格式化
# 1、使用下面方法转换
    <td>{{ c.start_time|date:'Y-m-d' }}</td>

# 2、转换前显示的格式
    July 2, 2017, 10:27 a.m.

# 3、转换后的格式
    2017-07-02

   6、forloop:显示数据序号

  forloop模板语言中显示数据序号
# 1、<td>{{ forloop.counter }}</td>
# 2、<td>{{ forloop.counter0 }}</td>
# 3、<td>{{ forloop.revcounter }}</td>
# 4、<td>{{ forloop.revcounter0 }}</td>
# 5、<td>{{ forloop.last }}</td>
# 6、<td>{{ forloop.first }}</td>

  7、{% for detail in parameter|safe|json_to_obj %}

  for循环时 json化
@register.filter(name='json_to_obj')
def json_to_obj(obj):
    return json.loads(obj)
    
{% for detail in parameter|safe|json_to_obj %}    


{% endfor %}

1.8 自定义simple_tag和自定义filter

  作用: 在模板语言中对数据加工后返回

  1、自定义simple_tag步骤

      1、app下创建templatetags目录,并在templatetags目录下新建任意python文件(比如:xxoo.py)

      2、settings中注册APP

      3、在templates/下的html文件中引用

  2、在templatetags/xxoo.py文件中写处理函数

  在templatetags/xxoo.py文件中写处理函数
from django import template
from django.utils.safestring import mark_safe

register = template.Library()      # 对象名register不可变

@register.simple_tag               #1 simple_tag用法
def houyafan(a1,a2):
    return a1 + a2

@register.filter                  #2 filter用法
def jiajingze(a1,a2):
    return a1 + a2
  在templates/index.html文件中使用
<!-- 1、 在html文件最顶部引用xxoo.py文件  -->
{% load xxoo %}
<html>
<head lang="en">
    <meta charset="UTF-8">
</head>
<body>
<!-- 2、在html文件最顶部引用xxoo.py文件  -->
<!-- houyafan是xxoo.py文件中函数名,2 4是传入的参数 显示到页面的结果是2+4是6 -->

    {% houyafan 2 4 %}


<!-- 3、filter参数格式  参数1|函数名:参数2  -->

    {{ "maliya"|jiajingze:"LS" }}

    {% if "maliya"|jiajingze:"LS" %}

    {% endif %}
</body>
</html>

  3、自定义simple_tag和自定义filter优缺点比较

    1、自定simple_tag

        缺点:   不能作为if条件

        优点:  参数任意个

    2、自定义filter

        缺点:  最多两个参数,不能加空格

        优点:  能作为if条件

1.9 模板继承

   1、模板继承使用

       1. 在master.html中定义模板:  {% block css %} {% endblock %}

       2. 在子类中引入要继承的模板:  {% extends 'master.html' %}

   2、模板导入

       1. 使用时直接导入即可:  {% include "tag.html" %}

  模板(templates/master.html)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">

{#1、子类标题#}
    <title>{% block title %}{% endblock %}</title>

    <link rel="stylesheet" href="/static/commons.css">
{#2、子类css样式#}
    {% block css %} {% endblock %}

</head>
<body>
    <div class="pg-header">小男孩管理</div>

{#3、子类页面主要内容#}
    {% block content %}{% endblock %}

    <script src="/static/jquery.js"></script>
{#4、子类js样式#}
    {% block js %} {% endblock %}

</body>
</html>
  在子类中继承模板中内容
{#1 extends关键字引入要继承的模板#}
{% extends 'master.html' %}

{#2 有些时候我们继承的时候想要有一些自己的东西,比如:标题#}
{% block title %} 用户管理 {% endblock %}

{#3 我们可以将每个页面自己的内容放到这里#}
{% block content %}
    <h1>用户管理</h1>
    <ul>
        {% for i in u %}
            <li>{{ i }}</li>
        {% endfor %}
    </ul>

    
{#模板导入 这里的”tag.html”在右边#}
{% include "tag.html" %}

{% endblock %}


{#4 本网页自己的css样式#}
{% block css %}
    <style>
        body{
            background-color: red;
        }
    </style>
{% endblock %}

{#5 本网页自己的js样式#}
{% block js %}
    <script>
        alert(1234)
    </script>
{% endblock %}

1.10 前后端交互:提交数据、提交文件

  index.html提交数据
<form action="/login/" method="post" enctype="multipart/form-data">
    <p>
        <input type="text" name="user" placeholder="用户名">
    </p>
    
    {# 1、单选框,返回单条数据的列表 #}
    <p>     
        男:<input type="radio" name="gender" value="1">
        女:<input type="radio" name="gender" value="2">
        张扬:<input type="radio" name="gender" value="3">
    </p>

    {# 2、多选框、返回多条数据列表 #}
    <p>     
        男:<input type="checkbox" name="favor" value="11">
        女:<input type="checkbox" name="favor" value="22">
        张扬:<input type="checkbox" name="favor" value="33">
    </p>

    {# 3、多选,返回多条数据的列表 #}
    <p>     
        <select name="city" multiple>
            <option value="bj">北京</option>
            <option value="sh">上海</option>
            <option value="gz">广州</option>
        </select>
    </p>

    {# 4、提交文件 #}
    <p><input type="file" name="fff"></p>
    <input type="submit" value="提交">
</form>
  views.py获取数据   
def login(request):
    if request.method == 'GET':
        return render(request,'login.html')
    elif request.method == 'POST':
        v = request.POST.get('gender')      #1 获取单选框的value值
        v = request.POST.getlist('favor')   #2 获取多选框value:['11', '22', '33']
        v = request.POST.getlist('city')    #3 获取多选下拉菜单:['bj', 'sh', 'gz']
        print(v.name,type(v))


        #当服务器端取客户端发送来的数据,不会将数据一下拿过来而是一点点取(chunks就是文件分成的块)
        
        obj = request.FILES.get('fff')      #4 下面是获取客户端上传的文件(如:图片)
        import os
        file_path = os.path.join('upload',obj.name)
        f = open(file_path,mode='wb')
        for i in obj.chunks():
            f.write(i)
        f.close()

        return render(request,'login.html')
  request获取数据方式
# 1、request.POST
# 2、request.GET
# 3、request.FILES
# 4、request.getlist
# 5、request.method
# 6、request.path_info                   #获取当前url
# 7、request.body                        #自己获取数据
# 8、a = ‘中国’
    response = HttpResponse(a)
    response[“name”] = ‘alex’        #HttpResponse不仅可以在响应头中传字符串,也可以传键值对
    response.set_cookie()                #设置cookie实质也是向请求头中传入键值对

1.11 Django生命周期与中间件

  1、中间件处理过程

      1、首先客户端发起请求,会将请求交给settings.py中排在最前面的中间件

      2、前面中间件收到请求会调用类中的process_request方法处理,然后交给下一个中间件的process_request函数

      3、到达最后一个中间件的process_request函数处理后会到达url路由系统

      4、然后从路由系统直接跳转到第一个中间件的process_view函数,依次向后面中间的process_view传递,最后
          到达views.py处理函数,获取网页中的数据

      5、获取的数据会交给最后一个中间件的process_response方法处理,然后依次向前面的中间件process_response
          方法提交请求的内容,最后由最前面的中间件将请求数据返回到客户端

      6、在任一中间件的process_request和process_view方法中有返回值就会直接返回给process_response

  2、生命周期图解

                 

  3、Django生命周期请求过程

    1客户端访问

      1、客户端在浏览器中输入url路径访问指定网页

    2.  请求发送给Django程序

      1、首先会交给中间件,中间件处理后交给路由系统

      2、路由系统

            1:Django程序会到urls.py文件中找到对应请求的处理函数(视图函数)

      3、视图函数

            1:视图函数会找到对应的html模板文件

            2:然后到数据库中取得数据替换html模板中的内容

            3:使用static中的js和css文件结合对html渲染

            4:最后Django将最终渲染后的html文件返回给中间件

      4、中间件再调用process_response方法处理,最后交给用户

1.12 中间件使用举例

  1、创建存放中间件的文件夹

      1) 在工程目录下创建任意目录,这里创建路径为: /project/middle/m1.py

  2、在project/settings.py文件中注册我们自己的中间件

MIDDLEWARE = [
    'middle.m1.Row1',
    'middle.m1.Row2',
    'middle.m1.Row3',
]

  3、 在views.py文件中写处理函数test

  views.py处理函数
def test(request):
    # int('fds')    #当views函数出现异常,中间件中的process_exception执行
    print('没带钱|')
    return HttpResponse('ok')

  4、在/project/middle/m1.py文件中定义中间件

  在/project/middle/m1.py文件中定义中间件
from django.utils.deprecation import MiddlewareMixin
class Row1(MiddlewareMixin):
    def process_request(self,request):
        print('process_request_1')

    def process_view(self,request, view_func, view_func_args, view_func_kwargs):
        #view_func_args:   url中传递的非字典的值会用这个变量接收
        #view_func_kwargs: url中传递的字典会传递到这个变量接收(如:nid=1)
        print('process_view_1')

    def process_response(self,request, response):    #response就是拿到的返回信息
        print('response_1')
        return response

    def process_exception(self, request, exception):
        '''只有当views函数中异常这个函数才会执行'''
        if isinstance(exception, ValueError):
            return HttpResponse('>>出现异常了')

class Row2(MiddlewareMixin):
    def process_request(self,request):
        print('process_request_2')
        #1 如果在Row2中的process_request中有返回值,那么就不会到达Row3
        #2 Row2直接将返回值交给自己的process_response再交给Row1的process_response
        #3 最后客户端页面显示的就是‘走’请求没机会到达views函数,不会打印‘没带钱’
        # return HttpResponse('走')

    def process_view(self,request, view_func, view_func_args, view_func_kwargs):
        print('process_view_2')

    def process_response(self,request, response):
        print('response_2')
        return response

class Row3(MiddlewareMixin):
    def process_request(self,request):
        print('process_request_3')

    def process_view(self,request, view_func, view_func_args, view_func_kwargs):
        print('process_view_3')

    def process_response(self,request, response):
        print('response_3')
        return response

目录:Django其他篇

01:Django基础篇

02:Django进阶篇

03:Django数据库操作--->Model

04: Form 验证用户数据 & 生成html

05:ModelForm 数据验证 & 生成html & 数据库操作

06: Django Admin

07: Django 学习补充

目录:

django参考网站

1.1 Web框架本质----socket

  1、web框架本质

      1. 对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端。

      2. 真实web框架一般会分为两部分:服务器程序和应用程序。  

          1)服务器程序负责对socket服务器进行封装,并在请求到来时,对请求的各种数据进行整理

          2)应用程序则负责具体的逻辑处理

  2、WSGI(Web Server Gateway Interface)

      1. 不同的框架有不同的开发方式,但是无论如何,开发出的应用程序都要和服务器程序配合,才能为用户提供服务。

      2. 这样,服务器程序就需要为不同的框架提供不同的支持,只有支持它的服务器才能被开发出的应用使用,这时就需要有一个标准

      3. WSGI是一种规范,它定义了使用python编写的web app与web server之间接口格式,实现web app与web server间的解耦。

  3、使用socket创建一个简单web服务

  使用socket创建一个简单web服务
import socket

def handle_request(client):
    buf = client.recv(1024)
    client.send("HTTP/1.1 200 OK\r\n\r\n".encode('utf-8'))      # 伪造浏览器请求头
    client.send("Hello, Seven".encode('utf-8'))                  # 返回数据到客户端浏览器

def main():
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind(('localhost', 8000))
    sock.listen(5)
    while True:
        connection, address = sock.accept()
        handle_request(connection)
        connection.close()

if __name__ == '__main__':
    main()

  4、自定义Web框架

      说明: 通过python标准库提供的wsgiref模块开发一个自己的Web框架

  自定义web框架
from wsgiref.simple_server import make_server

def handle_index():
    return ['<h1>Hello, Index!</h1>'.encode('utf-8'),]
def handle_date():
    return ['<h1>Hello, date!</h1>'.encode('utf-8'),]

URl_DICT = {
    "/index":handle_index,
    "/date":handle_date,
}

#1 environ客户端发来的所有数据
#2 start_response封装要返回给用户的数据,响应头状态
#3 return返回的是正真用户在浏览器中看到的内容(Hello, web!)
def RunServer(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    current_url = environ['PATH_INFO']                           #用户访问的url目录:/index 或 /date
    func = None
    if current_url in URl_DICT:
        func = URl_DICT[current_url]
        return func()
    else:
        return ['<h1>404</h1>'.encode('utf-8'),]

if __name__ == '__main__':
    httpd = make_server('', 8001, RunServer)
    print("Serving HTTP on port 8000...")
    httpd.serve_forever()

1.2 MVC和MTV架构

  1、MVC架构

      1. MVC架构把一个完整的程序或者网站项目分成三个主要的组成部分,分别是Model模型,View视图,Controller控制器

      2. 希望一个项目可以让内部数据的储存方式,外部的可见部分以及过程控制逻辑相互配合运行

      3. 进一步简化项目复杂度,提高可扩充性,维护性,有助于不同成员之间的分工

  2、MTV框架(Django)

      1. 对于网站而言,网页服务器在接收到远程浏览器的请求的时候,不同的网址做出不同的响应

      2. 有不同的链接方式其实就隐含了逻辑控制,因此很难严谨的将其定义为上述三个部分

      3. 因此Django另外设计了MTV结构(Model,Template,View)。

  3、MVC vs MTV

    MVC

        Model       View          Controller

        数据库      模板文件      业务处理

    MTV

        Model      Template       View

        数据库      模板文件      业务处理

1.3 Django常用命令

  1、安装Django

      pip3 install django

  2、创建Django工程

      D:\>  django-admin startproject laoniu                                               //创建项目名称laoniu

      D:\>  cd laoniu

      D:\laoniu>  python manage.py runserver 127.0.0.1:8002                 //运行laoniu即可用浏览器访问了

      D:\laoniu>  python manage.py createsuperuser                               //创建Django admin用户

  3、创建app

      python manage.py startapp app01

  4、创建表  

      python manage.py makemigrations
      python manage.py migrate

  5、执行python manage.py migrate无法创建表

      执行时报:No migrations to apply.

      1. 进入数据库,找到django_migrations的表,删除该app名字对应的所有记录

          python manage.py dbshell
          delete from django_migrations where app='app01';

      2. 删除该app名字下的migrations下的除了__init__.py之外的文件。

      3. 执行下面这两条命令:(在项目目录下)

          python manage.py makemigrations
          python manage.py migrate

                注:如果个别app表依然无法建立可以在后面添加app名称:python manage.py makemigrations/migrate app01

  6、“Column 'last_login' cannot be null”报错

      mysql> SELECT * FROM django_migrations;

      mysql> TRUNCATE TABLE django_migrations;

      $ python manage.py migrate --fake-initial
      Make sure this message appears: 0005_alter_user_last_login_null - [OK]

  7、windows中杀死指定端口号进程

      D:\>netstat -aon|findstr "8000"
      D:\>taskkill /PID 12516 -t -f

1.4 配置settings.py文件

  1、配置模板的路径

TEMPLATES = [
    {
       'DIRS': [os.path.join(BASE_DIR,'templates')],
    },
]

  2、 配置静态目录

#像ccs和js这些静态文件如果想要使用必须在这里配置路径
STATICFILES_DIRS = (
    os.path.join(BASE_DIR,'static'),
)

  3、注释CSRF

MIDDLEWARE = [
    # 'django.middleware.csrf.CsrfViewMiddleware',
]

  4、修改settings.py中时区

  修改settings.py中时区
# LANGUAGE_CODE = 'en-us'
LANGUAGE_CODE = 'zh-hans'

# TIME_ZONE = 'UTC'
TIME_ZONE = 'Asia/Shanghai'

1.5 Django各种url写法

  1、无正则匹配url  (http://127.0.0.1:8000/index/?nid=1&pid=2)

  urls.py
urlpatterns = [
    url(r'^index/', views.index),
]
  views.py
from django.shortcuts import render

def index(request):
    print(request.GET.get('nid'))             # 1
    print(request.GET.get('pid'))             # 2
    return render(request,'index.html')
  index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <a href="/index/?nid=1&pid=2"> url.py中不必用正则匹配 </a>
</body>
</html>

  2、基于(\d+)正则的url

  urls.py
urlpatterns = [
    url(r'^index/(\d+)/(\d+)/', views.index),
]
  views.py
def index(request,nid,pid):
    return render(request,'index.html')
  index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <a href="/index/1/2/"> url.py中必须使用正则匹配传入的参数 </a>
</body>
</html>

  3、基于正则分组(?P<nid>\d+),可以不考虑接收参数顺序 (推荐)

  urls.py
urlpatterns = [
    url(r'^index/(?P<nid>\d+)/(?P<pid>\d+)/', views.index),
]
  views.py
def index(request,nid,pid):
    return render(request,'index.html')
  index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <a href="/index/1/2/"> 使用分组匹配,不必关心传入参数顺序 </a>
</body>
</html>

  4、使用name构建自己想要的url

     1. 使用name在前端和后端分别构建自己想要的url

  urls.py中定义路由系统
urlpatterns = [
    url(r'^index1/', views.index,name='indexname1'),
    url(r'^index2/(\d+)/(\d+)/', views.index,name='indexname2'),
    url(r'^index2/(?P<pid>\d+)/(?P<nid>\d+)/', views.index,name='indexname3'),
]
  views.py中根据reverse模块构建url路径
from django.shortcuts import render
from django.core.urlresolvers import reverse

def index(request,*args,**kwargs):
    url1 = reverse('indexname1')                                      # /index1/
    url2 = reverse('indexname2', args=(1,2,))                         # /index2/1/2/
    url3 = reverse('indexname3', kwargs={'pid': 11, "nid":22})        # /index2/11/22/
    return render(request,'index.html')
  index.html中构建url路径:前端
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <p><a href="{% url 'indexname1' %}">  http://127.0.0.1:8000/index/  </a></p>
    <p><a href="{% url 'indexname2' 1 2 %}">  http://127.0.0.1:8000/index2/1/2/  </a></p>
    <p><a href="{% url 'indexname3' 11 22 %}">  http://127.0.0.1:8000/index2/11/22/  </a></p>
</body>
</html>

    2. 根据request.path中的绝对路径反解出url中的name名字

resolve_url_obj = resolve(request.path)    #request.path路径: /student/homework_detail/52
resolve_url_obj.url_name                   #从path中解析出url名字 url_name = homework_detail

  5、Django路由分发    并使用name构建url路径

      作用:对URL路由关系进行命名, ***** 以后可以根据此名称生成自己想要的URL *****

  /project/urls.py
from django.conf.urls import url,include
from app01 import urls

urlpatterns = [
    url(r'^app01/', include("app01.urls", app_name='app01', namespace='app01')),
]
  /app01/urls.py
from django.conf.urls import url
from app01 import views

urlpatterns = [
    url(r'^index/$', views.index, name='index'),
]
  views.py
from django.shortcuts import render

def index(request):
    return render(request,'index.html')
  index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <p> <a href="{% url "app01:index" %}">  http://127.0.0.1:8000/app01/index/</a></p>
</body>
</html>

1.6 Django的CBV和FBV

  1、FBVfunction  base  view:views.py文件中使用函数

  FBV写法
def index(request):
    return render(request, 'index.html')

  2、CBV(class  base  view):在views.py文件中使用类

      1、 dispatch是父类中用来反射的函数,找对应的函数(比对应函数先执行)

      2、 比如你发送post请求就可以通过dispatch找到对应的post函数进行处理,get就会找到get函数处理

  CBV:urls.py
from django.conf.urls import url
from app01 import views

urlpatterns = [
    url(r'^home/',views.Home.as_view()), #as_view是指定调用view的as_view这个方法固定写法
]
  CBV:views.py
from django.shortcuts import HttpResponse

from django.views import View
class Home(View):
    '''使用CBV时必须要继承view父类'''
    def dispatch(self, request, *args, **kwargs):
        # 调用父类中的dispatch
        result = super(Home,self).dispatch(request, *args, **kwargs)
        # 使用result主动继承view父类,然后return就可以重写父类的dispath方法
        return result
    # 在这里使用get发来请求就会调用get方法,使用post发来请求就会调用post方法
    def get(self,request):
        print(request.method)
        return HttpResponse('get')

    def post(self,request):
        print(request.method,'POST')
        return HttpResponse('post')
  CBC:指定某个视图函数不使用csrf验证
from django.shortcuts import HttpResponse
from django.views import View
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt

class Home(View):
    '''使用CBV时必须要继承view父类'''
    @method_decorator(csrf_exempt)        # 指定Home这个视图函数不使用csrf
    def dispatch(self, request, *args, **kwargs):
        # 调用父类中的dispatch
        result = super(Home,self).dispatch(request, *args, **kwargs)
        # 使用result主动继承view父类,然后return就可以重写父类的dispath方法
        return result
    # 在这里使用get发来请求就会调用get方法,使用post发来请求就会调用post方法
    def get(self,request):
        print(request.method)
        return HttpResponse('get')

    def post(self,request):
        print(request.method,'POST')
        return HttpResponse('post')

1.7 模板渲染

  1、for循环

  for循环字典
<body>
    {% for k in user_dic.keys %}
        <p>{{ k }}</p>
    {% endfor %}

    {% for v in user_dic.values %}
        <p>{{ v }}</p>
    {% endfor %}

    {% for k,v in user_dic.items %}
        <p>{{ k }}--{{ v }}</p>
    {% endfor %}
</body>
  for循环列表
<body>
    {% for k in l %}
        <p>{{ k }}</p>
    {% endfor %}
</body>

  2if语句

  views.py视图函数
def index(request):
    return render(request,'index.html',{
        'current_user':"alex",
        'user_list':['alex','eric'],
        'user_dict':{'k1':'v1', 'k2':'v2'}
    })
  index.html模板渲染
<div>{{current_user}}</div>

<a> {{ user_list.1 }} </a>          #在模板语言中获取列表中的元素
<a> {{ user_dict.k1 }} </a>         #在模板语言中获取字典中元素

{% if age %}
   <a>有年龄</a>
   {% if age > 16 %}
      <a>老男人</a>
   {% else %}
      <a>小鲜肉</a>
   {% endif %}
{% else %}
   <a>无年龄</a>
{% endif %}

   3、ifequal判断值相等

  判断两个值是否相等
{% ifequal a1 a2 %}
            <h1>equal!</h1>
        {% else %}
            <h1>not equal!</h1>
        {% endifequal %}

  4、in判断在列表中

  in判断是否在列表中
{% if '讲师' in roles %}
<ul class="nav nav-sidebar">
  <li><a data-url="/webapp/staff/attendance/">发起签到</a></li>
  <li><a data-url="/webapp/staff/score/">学员成绩</a></li>
</ul>
{% endif %}

  5、HTML中转换时间格式

  时间格式化
# 1、使用下面方法转换
    <td>{{ c.start_time|date:'Y-m-d' }}</td>

# 2、转换前显示的格式
    July 2, 2017, 10:27 a.m.

# 3、转换后的格式
    2017-07-02

   6、forloop:显示数据序号

  forloop模板语言中显示数据序号
# 1、<td>{{ forloop.counter }}</td>
# 2、<td>{{ forloop.counter0 }}</td>
# 3、<td>{{ forloop.revcounter }}</td>
# 4、<td>{{ forloop.revcounter0 }}</td>
# 5、<td>{{ forloop.last }}</td>
# 6、<td>{{ forloop.first }}</td>

  7、{% for detail in parameter|safe|json_to_obj %}

  for循环时 json化
@register.filter(name='json_to_obj')
def json_to_obj(obj):
    return json.loads(obj)
    
{% for detail in parameter|safe|json_to_obj %}    


{% endfor %}

1.8 自定义simple_tag和自定义filter

  作用: 在模板语言中对数据加工后返回

  1、自定义simple_tag步骤

      1、app下创建templatetags目录,并在templatetags目录下新建任意python文件(比如:xxoo.py)

      2、settings中注册APP

      3、在templates/下的html文件中引用

  2、在templatetags/xxoo.py文件中写处理函数

  在templatetags/xxoo.py文件中写处理函数
from django import template
from django.utils.safestring import mark_safe

register = template.Library()      # 对象名register不可变

@register.simple_tag               #1 simple_tag用法
def houyafan(a1,a2):
    return a1 + a2

@register.filter                  #2 filter用法
def jiajingze(a1,a2):
    return a1 + a2
  在templates/index.html文件中使用
<!-- 1、 在html文件最顶部引用xxoo.py文件  -->
{% load xxoo %}
<html>
<head lang="en">
    <meta charset="UTF-8">
</head>
<body>
<!-- 2、在html文件最顶部引用xxoo.py文件  -->
<!-- houyafan是xxoo.py文件中函数名,2 4是传入的参数 显示到页面的结果是2+4是6 -->

    {% houyafan 2 4 %}


<!-- 3、filter参数格式  参数1|函数名:参数2  -->

    {{ "maliya"|jiajingze:"LS" }}

    {% if "maliya"|jiajingze:"LS" %}

    {% endif %}
</body>
</html>

  3、自定义simple_tag和自定义filter优缺点比较

    1、自定simple_tag

        缺点:   不能作为if条件

        优点:  参数任意个

    2、自定义filter

        缺点:  最多两个参数,不能加空格

        优点:  能作为if条件

1.9 模板继承

   1、模板继承使用

       1. 在master.html中定义模板:  {% block css %} {% endblock %}

       2. 在子类中引入要继承的模板:  {% extends 'master.html' %}

   2、模板导入

       1. 使用时直接导入即可:  {% include "tag.html" %}

  模板(templates/master.html)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">

{#1、子类标题#}
    <title>{% block title %}{% endblock %}</title>

    <link rel="stylesheet" href="/static/commons.css">
{#2、子类css样式#}
    {% block css %} {% endblock %}

</head>
<body>
    <div class="pg-header">小男孩管理</div>

{#3、子类页面主要内容#}
    {% block content %}{% endblock %}

    <script src="/static/jquery.js"></script>
{#4、子类js样式#}
    {% block js %} {% endblock %}

</body>
</html>
  在子类中继承模板中内容
{#1 extends关键字引入要继承的模板#}
{% extends 'master.html' %}

{#2 有些时候我们继承的时候想要有一些自己的东西,比如:标题#}
{% block title %} 用户管理 {% endblock %}

{#3 我们可以将每个页面自己的内容放到这里#}
{% block content %}
    <h1>用户管理</h1>
    <ul>
        {% for i in u %}
            <li>{{ i }}</li>
        {% endfor %}
    </ul>

    
{#模板导入 这里的”tag.html”在右边#}
{% include "tag.html" %}

{% endblock %}


{#4 本网页自己的css样式#}
{% block css %}
    <style>
        body{
            background-color: red;
        }
    </style>
{% endblock %}

{#5 本网页自己的js样式#}
{% block js %}
    <script>
        alert(1234)
    </script>
{% endblock %}

1.10 前后端交互:提交数据、提交文件

  index.html提交数据
<form action="/login/" method="post" enctype="multipart/form-data">
    <p>
        <input type="text" name="user" placeholder="用户名">
    </p>
    
    {# 1、单选框,返回单条数据的列表 #}
    <p>     
        男:<input type="radio" name="gender" value="1">
        女:<input type="radio" name="gender" value="2">
        张扬:<input type="radio" name="gender" value="3">
    </p>

    {# 2、多选框、返回多条数据列表 #}
    <p>     
        男:<input type="checkbox" name="favor" value="11">
        女:<input type="checkbox" name="favor" value="22">
        张扬:<input type="checkbox" name="favor" value="33">
    </p>

    {# 3、多选,返回多条数据的列表 #}
    <p>     
        <select name="city" multiple>
            <option value="bj">北京</option>
            <option value="sh">上海</option>
            <option value="gz">广州</option>
        </select>
    </p>

    {# 4、提交文件 #}
    <p><input type="file" name="fff"></p>
    <input type="submit" value="提交">
</form>
  views.py获取数据   
def login(request):
    if request.method == 'GET':
        return render(request,'login.html')
    elif request.method == 'POST':
        v = request.POST.get('gender')      #1 获取单选框的value值
        v = request.POST.getlist('favor')   #2 获取多选框value:['11', '22', '33']
        v = request.POST.getlist('city')    #3 获取多选下拉菜单:['bj', 'sh', 'gz']
        print(v.name,type(v))


        #当服务器端取客户端发送来的数据,不会将数据一下拿过来而是一点点取(chunks就是文件分成的块)
        
        obj = request.FILES.get('fff')      #4 下面是获取客户端上传的文件(如:图片)
        import os
        file_path = os.path.join('upload',obj.name)
        f = open(file_path,mode='wb')
        for i in obj.chunks():
            f.write(i)
        f.close()

        return render(request,'login.html')
  request获取数据方式
# 1、request.POST
# 2、request.GET
# 3、request.FILES
# 4、request.getlist
# 5、request.method
# 6、request.path_info                   #获取当前url
# 7、request.body                        #自己获取数据
# 8、a = ‘中国’
    response = HttpResponse(a)
    response[“name”] = ‘alex’        #HttpResponse不仅可以在响应头中传字符串,也可以传键值对
    response.set_cookie()                #设置cookie实质也是向请求头中传入键值对

1.11 Django生命周期与中间件

  1、中间件处理过程

      1、首先客户端发起请求,会将请求交给settings.py中排在最前面的中间件

      2、前面中间件收到请求会调用类中的process_request方法处理,然后交给下一个中间件的process_request函数

      3、到达最后一个中间件的process_request函数处理后会到达url路由系统

      4、然后从路由系统直接跳转到第一个中间件的process_view函数,依次向后面中间的process_view传递,最后
          到达views.py处理函数,获取网页中的数据

      5、获取的数据会交给最后一个中间件的process_response方法处理,然后依次向前面的中间件process_response
          方法提交请求的内容,最后由最前面的中间件将请求数据返回到客户端

      6、在任一中间件的process_request和process_view方法中有返回值就会直接返回给process_response

  2、生命周期图解

                 

  3、Django生命周期请求过程

    1客户端访问

      1、客户端在浏览器中输入url路径访问指定网页

    2.  请求发送给Django程序

      1、首先会交给中间件,中间件处理后交给路由系统

      2、路由系统

            1:Django程序会到urls.py文件中找到对应请求的处理函数(视图函数)

      3、视图函数

            1:视图函数会找到对应的html模板文件

            2:然后到数据库中取得数据替换html模板中的内容

            3:使用static中的js和css文件结合对html渲染

            4:最后Django将最终渲染后的html文件返回给中间件

      4、中间件再调用process_response方法处理,最后交给用户

1.12 中间件使用举例

  1、创建存放中间件的文件夹

      1) 在工程目录下创建任意目录,这里创建路径为: /project/middle/m1.py

  2、在project/settings.py文件中注册我们自己的中间件

MIDDLEWARE = [
    'middle.m1.Row1',
    'middle.m1.Row2',
    'middle.m1.Row3',
]

  3、 在views.py文件中写处理函数test

  views.py处理函数
def test(request):
    # int('fds')    #当views函数出现异常,中间件中的process_exception执行
    print('没带钱|')
    return HttpResponse('ok')

  4、在/project/middle/m1.py文件中定义中间件

  在/project/middle/m1.py文件中定义中间件
from django.utils.deprecation import MiddlewareMixin
class Row1(MiddlewareMixin):
    def process_request(self,request):
        print('process_request_1')

    def process_view(self,request, view_func, view_func_args, view_func_kwargs):
        #view_func_args:   url中传递的非字典的值会用这个变量接收
        #view_func_kwargs: url中传递的字典会传递到这个变量接收(如:nid=1)
        print('process_view_1')

    def process_response(self,request, response):    #response就是拿到的返回信息
        print('response_1')
        return response

    def process_exception(self, request, exception):
        '''只有当views函数中异常这个函数才会执行'''
        if isinstance(exception, ValueError):
            return HttpResponse('>>出现异常了')

class Row2(MiddlewareMixin):
    def process_request(self,request):
        print('process_request_2')
        #1 如果在Row2中的process_request中有返回值,那么就不会到达Row3
        #2 Row2直接将返回值交给自己的process_response再交给Row1的process_response
        #3 最后客户端页面显示的就是‘走’请求没机会到达views函数,不会打印‘没带钱’
        # return HttpResponse('走')

    def process_view(self,request, view_func, view_func_args, view_func_kwargs):
        print('process_view_2')

    def process_response(self,request, response):
        print('response_2')
        return response

class Row3(MiddlewareMixin):
    def process_request(self,request):
        print('process_request_3')

    def process_view(self,request, view_func, view_func_args, view_func_kwargs):
        print('process_view_3')

    def process_response(self,request, response):
        print('response_3')
        return response

猜你喜欢

转载自www.cnblogs.com/bokeyuanan/p/12620326.html