1. Web应用程序处理流程

# 第一个app指的是app.py文件,第二个指的是flask应用的名字;
gunicorn -w 4 -b 0.0.0.0:8000 app:app
# 参数详解
# -w INT, --workers INT:用于处理工作进程的数量,为正整数,默认为1;
# -b ADDRESS: ADDRESS,ip加端口,绑定运行的主机;
# gunicorn.conf文件

# 并行工作进程数
workers = 4
# 指定每个工作者的线程数
threads = 2
# 监听内网端口5000
bind = '127.0.0.1:5000'
# 设置守护进程,将进程交给supervisor管理
daemon = 'false'
# 工作模式协程
worker_class = 'gevent'
# 设置最大并发量
worker_connections = 2000
# 设置进程文件目录
pidfile = '/var/run/gunicorn.pid'
# 设置访问日志和错误信息日志路径
accesslog = '/var/log/gunicorn_acess.log'
errorlog = '/var/log/gunicorn_error.log'
# 设置日志记录水平
loglevel = 'warning'
gunicorn -c gunicorn.conf app:app
# -c CONFIG: CONFIG,配置文件的路径,通过配置文件启动;生产环境使用;

2. Web程序框架的意义

  • 用于搭建Web应用程序
  • 免去不同Web应用相同代码部分的重复编写,只需关心Web应用核心的业务逻辑实现

3. Web应用程序的本质

  • 接收并解析HTTP请求,获取具体的请求信息
  • 处理本次HTTP请求,即完成本次请求的业务逻辑处理
  • 构造并返回处理结果——HTTP响应

4. Web框架

  • 如何搭建工程程序
    • 工程的组建
    • 工程的配置
    • 路由定义
    • 视图函数定义
  • 如何获取请求数据(操作request对象)
  • 如何构造响应数据(构造response对象)
  • 如何使用中间层
  • 框架提供的其他功能组件的使用
    • 数据库
    • 模板
    • admin

5.特点

django-admin startproject xxx
Python manage.py startapp xxx

6.项目工程

  • 创建
Django-admin startproject 项目名称
  • 运行
python manage.py runserver ip:端口
  • 创建子应用模块
Python manage.py startapp 子应用名称

7.配置文件

    1. BASE_DIR

当前工程的根目录,Django会依此来定位工程内的相关文件,我们也可以使用该参数来构造文件路径。

    1. DEBUG

调试模式,创建工程后初始值为True,即默认工作在调试模式下。

​ 作用:Django程序出现异常时,向前端显示详细的错误追踪信息,

注意:部署线上运行的Django不要运行在调式模式下,会影响用户体验,记得修改DEBUG=False。

    1. 本地语言与时区

初始化的工程默认语言和时区为英语和UTC标准时区

LANGUAGE_CODE = 'en-us'  # 语言
TIME_ZONE = 'UTC'  # 时区

将语言和时区修改为中国大陆信息

LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'

8.静态文件

项目中的CSS、图片、js都是静态文件。一般会将静态文件放到一个单独的目录中,以方便管理。在html页面中调用时,也需要指定静态文件的路径,Django中提供了一种解析的方式配置静态文件路径。静态文件可以放在项目根目录下,也可以放在应用的目录下,由于有些静态文件在项目中是通用的,所以推荐放在项目的根目录下,方便管理。

为了提供静态文件,需要配置两个参数:

  • STATICFILES_DIRS=[ ] 存放查找静态文件的目录 接收的是list

  • STATIC_URL 访问静态文件的URL前缀

    注意

    • Django 仅在调试模式下(DEBUG=True)能对外提供静态文件。
    • 当DEBUG=False工作在生产模式时,Django不再对外提供静态文件,需要是用collectstatic命令来收集静态文件并交由其他静态文件服务器来提供。

9. 路由命名与reverse反解析(逆向)

  • 路由命名
    在定义路由的时候,可以为路由命名,方便查找特定视图的具体路径信息。

    1) 在使用include函数定义路由时,可以使用namespace参数定义路由的命名空间,如

url(r'^users/', include('users.urls', namespace='users')),

命名空间表示,凡是users.urls中定义的路由,均属于namespace指明的users名下。

命名空间的作用:避免不同应用中的路由使用了相同的名字发生冲突,使用命名空间区别开。

2) 在定义普通路由时,可以使用name参数指明路由的名字,如

urlpatterns = [
    url(r'^index/$', views.index, name='index'),
    url(r'^say', views.say, name='say'),
]
  • reverse反解析
    使用reverse函数,可以根据路由名称,返回具体的路径,如:
from django.urls import reverse  # 注意导包路径

def index(request):
    return HttpResponse("hello the world!")

def say(request):
    url = reverse('users:index')  # 返回 /users/index/
    return HttpResponse('say')

对于未指明namespace的,reverse(路由name)
对于指明namespace的,reverse(命名空间namespace:路由name)

10.Request

  • 利用HTTP协议向服务器传参有几种途径?

    • 提取URL的特定部分,如/weather/beijing/2018,可以在服务器端的路由中用正则表达式截取;
    • 查询字符串(query string),形如key1=value1&key2=value2;
    • 请求体(body)中发送的数据,比如表单数据、json、xml;
    • 在http报文的头(header)中。
  • Django中的QueryDict对象

    定义在django.http.QueryDict

    HttpRequest对象的属性GET、POST都是QueryDict类型的对象

    与python字典不同,QueryDict类型的对象用来处理同一个键带有多个值的情况

​ 1)方法get():根据键获取值

如果一个键同时拥有多个值将获取最后一个值

如果键不存在则返回None值,可以设置默认值进行后续处理

dict.get('键',默认值)
可简写为
dict['键']

​ 2) 方法getlist():根据键获取值,值以列表返回,可以获取指定键的所有值

如果键不存在则返回空列表[],可以设置默认值进行后续处理

dict.getlist('键',默认值)
  • 查询字符串Query String

获取请求路径中的查询字符串参数(形如?k1=v1&k2=v2),可以通过request.GET属性获取,返回QueryDict对象。

# /qs/?a=1&b=2&a=3

def qs(request):
    a = request.GET.get('a')
    b = request.GET.get('b')
    alist = request.GET.getlist('a')
    print(a)  # 3
    print(b)  # 2
    print(alist)  # ['1', '3']
    return HttpResponse('OK')

重要:查询字符串不区分请求方式,即假使客户端进行POST方式的请求,依然可以通过request.GET获取请求中的查询字符串数据。

  • 请求体

请求体数据格式不固定,可以是表单类型字符串,可以是JSON字符串,可以是XML字符串,应区别对待。

可以发送请求体数据的请求方式有POSTPUTPATCHDELETE

Django默认开启了CSRF防护,会对上述请求方式进行CSRF防护验证,在测试时可以关闭CSRF防护机制,方法为在settings.py文件中注释掉CSRF中间件,如:

​ 1) 表单类型 Form Data

前端发送的表单类型的请求体数据,可以通过request.POST属性获取,返回QueryDict对象。

def get_body(request):
    a = request.POST.get('a')
    b = request.POST.get('b')
    alist = request.POST.getlist('a')
    print(a)
    print(b)
    print(alist)
    return HttpResponse('OK')

重要:request.POST只能用来获取POST方式的请求体表单数据。

​ 2)非表单类型 Non-Form Data

非表单类型的请求体数据,Django无法自动解析,可以通过request.body属性获取最原始的请求体数据,自己按照请求体格式(JSON、XML等)进行解析。request.body返回bytes类型。

例如要获取请求体中的如下JSON数据

{"a": 1, "b": 2}

可以进行如下方法操作:

import json

def get_body_json(request):
    json_str = request.body
    json_str = json_str.decode()  # python3.6 无需执行此步
    req_data = json.loads(json_str)
    print(req_data['a'])
    print(req_data['b'])
    return HttpResponse('OK')
  • 请求头

可以通过request.META属性获取请求头headers中的数据,request.META为字典类型

具体使用如:

def get_headers(request):
    print(request.META['CONTENT_TYPE'])
    return HttpResponse('OK')
  • 其他常用HttpRequest对象属性
    • method:一个字符串,表示请求使用的HTTP方法,常用值包括:‘GET’、‘POST’。
    • user:请求的用户对象。
    • path:一个字符串,表示请求的页面的完整路径,不包含域名和参数部分。
    • encoding:一个字符串,表示提交的数据的编码方式。
      • 如果为None则表示使用浏览器的默认设置,一般为utf-8。
      • 这个属性是可写的,可以通过修改它来修改访问表单数据使用的编码,接下来对属性的任何访问将使用新的encoding值。
    • FILES:一个类似于字典的对象,包含所有的上传文件。

11. HttpResponse

#第一种方式设置响应对象
HttpResponse(content=响应体, content_type='响应体数据类型', status='状态码')
content_type='Application/json' 或 'image/jpg'

#第二种方式设置响应对象
response = HttpResponse()
response.content='data'
response.status_code = 200/300/400/500
  • 响应头设置
response = HttpResponse()
response['food1'] = 'hotdrynoodles'  # 自定义响应头food1, 值为hotdrynoodles
  • JsonResponse
    • 帮助我们将数据转换为json字符串
    • 设置响应头Content-Typeapplication/json
from django.http import JsonResponse

def demo_view(request):
    return JsonResponse({'city': 'beijing', 'subject': 'python'},status=xxxx)
  • redirect重定向
from django.shortcuts import redirect

def demo_view(request):
    return redirect(reverse('users:say'))

12.cookie

Cookie,有时也用其复数形式Cookies,指某些网站为了辨别用户身份、进行session跟踪而储存在用户本地终端上的数据(通常经过加密)。Cookie是由服务器端生成,发送给User-Agent(一般是浏览器),浏览器会将Cookie的key/value保存到某个目录下的文本文件内,下次请求同一网站时就发送该Cookie给服务器(前提是浏览器设置为启用cookie)。Cookies最典型记住用户名。Cookie是存储在浏览器中的一段纯文本信息

Cookie的特点

  • Cookie以键值对Key-Value形势进行信息的存储。
  • Cookie基于域名安全,不同域名的Cookie是不能互相访问的

设置Cookie

可以通过HttpResponse对象中的set_cookie方法来设置cookie。

HttpResponse.set_cookie(cookie名, value=cookie值, max_age=cookie有效期)
  • max_age 单位为秒,默认为None。如果是临时cookie,可将max_age设置为None。

读取Cookie

可以通过HttpRequest对象的COOKIES属性来读取本次请求携带的cookie值。request.COOKIES为字典类型

13.session

  • session的作用

Session 的作用就是它在 Web服务器上保持用户的状态信息供在任何时间从任何设备上的页面进行访问。因为浏览器不需要存储任何这种信息,所以可以使用任何浏览器,即使是像 Pad 或手机这样的浏览器设备。保持会话状态!

  • 特点
  1. 依赖cookies
  2. 存储敏感、重要的信息
  3. 支持更多字节
  4. Session共享问题
  request.session['键']=值
  request.session.get('键',默认值) #如果value为none,则返回默认值
  request.session.clear()
request.session.flush()
del request.session['键']
request.session.set_expiry(value)

Django类视图的说明详解

# 为全部请求方法添加装饰器
@method_decorator(my_decorator, name='dispatch')
# 为特定请求方法添加装饰器
@method_decorator(my_decorator, name='get')
@method_decorator(my_decorator)  # 为get方法添加了装饰器,其他方法同理
def get(self, request):
    pass

中间件

def simple_middleware(get_response):
    # 此处编写的代码仅在Django第一次配置和初始化的时候执行一次。

    def middleware(request):
        # 此处编写的代码会在每个请求处理视图前被调用。

        response = get_response(request)

        # 此处编写的代码会在每个请求处理视图之后被调用。

        return response

    return middleware

模板

{{变量}}
    {% for item in 列表 %}
循环逻辑
    {{forloop.counter}}表示当前是第几次循环,从1开始
{%empty%} 列表为空或不存在时执行此逻辑
    {% endfor %}  # 结尾语句不能丢
if条件
      {% if ... %}
    逻辑1
      {% elif ... %}
      逻辑2
      {% else %}
      逻辑3
      {% endif %}    # 结尾语句不能丢
{% if a == 1 %}  # 正确
{% if a==1 %}  # 错误

过滤器

data|default:'默认值'

自定义过滤器

#实例化对象
register = template.Library()
#创建一个template能认识的函数,对创建的每一个过滤器,都要用加上装饰器
@register.fitler 
def multi_age(x):
    return x * x
{% load filter_age %}
{{ age | multi_age }}

注释

  • 单行注释语法如下:
{#...#}
  • 多行注释使用comment标签,语法如下:
{% comment %}
...
{% endcomment %}

数据库

pip install PyMySQL
from pymysql import install_as_MySQLdb

install_as_MySQLdb()
#DATABASES = {
#   'default': {
#      'ENGINE': 'django.db.backends.sqlite3',
#     'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
#}
#}
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'HOST': '127.0.0.1',  # 数据库主机
        'PORT': 3306,  # 数据库端口
        'USER': 'root',  # 数据库用户名
        'PASSWORD': 'mysql',  # 数据库用户密码
        'NAME': 'django_demo'  # 数据库名字
    }
}
create database django_demo default charset=utf8;
属性=models.字段类型(选项)
from django.conf import settings
from django.contrib.auth import get_user_model
from django.db import models

def get_sentinel_user():
    return get_user_model().objects.get_or_create(username='deleted')[0]

class MyModel(models.Model):
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET(get_sentinel_user),
    )
python manage.py makemigrations
python manage.py migrate
sudo vi /etc/mysql/mysql.conf.d/mysqld.cnf
# 添加一下代码
general_log_file = /var/log/mysql/mysql.log
general_log = 1
# 重启服务
sudo service mysql restart
tail -f /var/log/mysql/mysql.log  # 可以实时查看数据库的日志内容
# 如提示需要sudo权限,执行
# sudo tail -f /var/log/mysql/mysql.log

Admin站点

  • 使用Django的管理模块,需要按照如下步骤操作:
    1. 管理界面本地化
    2. 创建管理员
    3. 注册模型类
    4. 自定义管理页面