admin管理员组

文章数量:1661565

文章目录

          • 1. 初识web框架
            • 1.1 http协议
            • 1.2 socket简介
            • 1.3 socket服务端概述
            • 1.4 自己写web框架
            • 1.5 web框架的分类
          • 2. 初识django
          • 3. django程序目录
          • 4. 第一个django请求
          • 5. 静态文件以及模板的配置
            • 5.1 静态文件路径的配置
            • 5.2 HttpResponse与render函数
            • 5.3 模板路径的配置
          • 6. 创建程序步骤
            • 6.1 创建project
            • 6.2 配置模板路径
            • 6.3 配置静态文件目录
            • 6.4 额外配置
          • 7. 用户登录示例
          • 8. request.GET与 request.POST
            • 8.1 request.GET
            • 8.2 request.POST
          • 9. django模板语言特殊标记(重点)
            • 9.1 取字符串的值
            • 9.2 取列表的值
            • 9.3 取字典的值
            • 9.4 取嵌套于列表中字典的值
          • 10. 学生信息管理系统
          • 11. 初识cookie
          • 12. 基于cookie的登录验证
          • 13. django操作cookie
          • 14. 设置cookie的签名
          • 18. 三大web框架的区别与联系
          • 19. Django非主流操作到主流操作
          • 20. Django程序目录
          • 21. 路由系统
            • 1. 静态路由
            • 2. 动态路由
            • 3. 路由分发
            • 4. 反向生成路由
          • 22. ORM
            • 1. ORM的功能
            • 2. 数据库设置
            • 3. makemigrations和migrate
            • 4. ORM创建数据表
            • 5. ORM单表CURD
          • 23. CBV
            • 1. CBV的引入
            • 2. CBV的应用
            • 3. dispatch方法
            • 4. CBV中添加装饰器
          • 24. 内置分页
            • 1. 后台分页逻辑
            • 2. 前台分页展示
          • 25. 自定义分页
            • 1. 自定义分页效果
            • 2. 自定义分页的实现
            • 3. 分页插件
          • 26. 解决跨站脚本攻击XSS
            • 1. Django处理XSS攻击
            • 2. 前端标记字符串
            • 3. 后端标记字符串
          • 27. 中间件
            • 1. 中间件执行流程
            • 2. 中间件原理浅析
            • 3. 中间件的应用
          • 28. Form组件
            • 1. Form组件的功能
            • 2. 数据校验
            • 3. 常用字段和参数
            • 4. 保留上次输入内容

1. 初识web框架
1.1 http协议

http协议是无状态,短连接的。客户端连接服务器,发送请求,服务器响应请求后断开连接。

1.2 socket简介

所有的网络请求都是基于socket,浏览器是socket客户端,网站是socket服务端。

1.3 socket服务端概述

根据url的不同返回给用户不同的内容,使用路由系统,路由系统是url与函数的对应关系。返回给用户的内容本质是字符串,基本上返回的内容是动态的,所以需要使用到模板渲染。模板渲染实际上是把html充当模板,自己创造任意数据替换模板中的特殊字符,比如替换特殊字符为数据库中的数据。

1.4 自己写web框架
  • 静态应用
# coding:utf-8
import socket

def f1(request):
    '''
    处理用户请求,并返回相应的内容
    :param request:用户请求的所有信息
    :return:返回相应的内容
    '''
    return b'f1'

def f2(request):
    '''
    处理用户请求,并返回相应的内容
    :param request:
    :return:
    '''
    f = open('index.html', 'rb')
    data = f.read()
    f.close()
    return data


def f3(request):
    '''
    处理用户请求,并返回相应的内容
    '''
    f = open('news.html', 'rb')
    data = f.read()
    f.close()
    return data

routers = [
    ('/user', f1),
    ('/', f2)
]

def run():
    sock = socket.socket()
    sock.bind(('127.0.0.1', 8080))
    sock.listen(5)

    while True:
        conn, addr = sock.accept()
        '''
        有用户来连接,
        获取用户发送的数据
        '''
        data = conn.recv(8096)
        print(data)
        '''请求头:
        GET / HTTP/1.1
        Host: 127.0.0.1:8080
        Connection: keep-alive
        Upgrade-Insecure-Requests: 1\
        User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36
        Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
        Purpose: prefetch
        Accept-Encoding: gzip, deflate, 
        Accept-Language: zh-CN,zh;q=0.9
        '''
        # 解析请求头,目标:获取请求头中的url,并根据url向服务端发送请求
        data = str(data, encoding='utf-8')

        headers, bodys = data.split('\r\n\r\n')
        headers_list = headers.split('\r\n')
        methods, url, protocal = headers_list[0].split(' ')
        func_name = None
        for item in routers:
            if item[0] == url:
                func_name = item[1]
                break
        if func_name:
            response = func_name(data)
        else:
            response = '404'

        # if url == '/user':
        #     conn.send(b'user page')
        # else:
        #     conn.send(b'404 is not found!')
        # conn.send(b"HTTP/1.1 200 OK\r\n\r\n")  # 响应头
        # conn.send(b"hello thanlon!")  # 相应体
        conn.close()

if __name__ == '__main__':
    run()
  • 动态应用示例一
# coding:utf-8
import socket

def f1(request):
    '''
    处理用户请求,并动态返回相应的内容
    :param request:
    :return:
    '''
    f = open('news.html', 'r', encoding='utf-8')
    data = f.read()
    f.close()
    import time
    ctime = time.time()
    data = data.replace('%', str(ctime))
    return bytes(data, encoding='utf-8')

routers = [
    ('/user', f1),
]

def run():
    sock = socket.socket()
    sock.bind(('127.0.0.1', 8080))
    sock.listen(5)

    while True:
        conn, addr = sock.accept()
        '''
        有用户来连接,
        获取用户发送的数据
        '''
        data = conn.recv(8096)
        print(data)
        '''请求头:
        GET / HTTP/1.1
        Host: 127.0.0.1:8080
        Connection: keep-alive
        Upgrade-Insecure-Requests: 1\
        User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36
        Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
        Purpose: prefetch
        Accept-Encoding: gzip, deflate, 
        Accept-Language: zh-CN,zh;q=0.9
        '''
        # 解析请求头,目标:获取请求头中的url,并根据url向服务端发送请求
        data = str(data, encoding='utf-8')

        headers, bodys = data.split('\r\n\r\n')
        headers_list = headers.split('\r\n')
        methods, url, protocal = headers_list[0].split(' ')
        func_name = None
        for item in routers:
            if item[0] == url:
                func_name = item[1]
                break
        if func_name:
            response = func_name(data)
        else:
            response = '404'

        # if url == '/user':
        #     conn.send(b'user page')
        # else:
        #     conn.send(b'404 is not found!')
        # conn.send(b"HTTP/1.1 200 OK\r\n\r\n")  # 响应头
        # conn.send(b"hello thanlon!")  # 相应体
        conn.close()

if __name__ == '__main__':
    run()
  • 动态应用示例二
# coding:utf-8
import socket

def f1(request):
    import pymysql
    # 创建连接
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='wwwnxl', db='test')
    # 创建游标
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    # 执行sql语句,并返回受影响的行数
    cursor.execute("select id,name,passwd from userinfo")
    user_list = cursor.fetchall()
    cursor.close()
    conn.close()
    # print(user_list)
    content_list = []
    for row in user_list:
        tp = '<tr>%s</tr><tr>%s</tr><tr>%s</tr>' % (row['id'], row['name'], row['passwd'],)
        content_list.append(tp)
    content = ''.join(content_list)
    f = open('userlist.html', 'r', encoding='utf-8')
    template = f.read()
    f.close()
    data = template.replace('{
   {content}}', content)
    print(data)
    return bytes(data, encoding='utf-8')

routers = [
    ('/user', f1),
]

def run():
    sock = socket.socket()
    sock.bind(('127.0.0.1', 8080))
    sock.listen(5)

    while True:
        conn, addr = sock.accept()
        '''
        有用户来连接,
        获取用户发送的数据
        '''
        data = conn.recv(8096)
        # print(data)
        '''请求头:
        GET / HTTP/1.1
        Host: 127.0.0.1:8080
        Connection: keep-alive
        Upgrade-Insecure-Requests: 1\
        User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36
        Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
        Purpose: prefetch
        Accept-Encoding: gzip, deflate, 
        Accept-Language: zh-CN,zh;q=0.9
        '''
        # 解析请求头,目标:获取请求头中的url,并根据url向服务端发送请求
        data = str(data, encoding='utf-8')

        headers, bodys = data.split('\r\n\r\n')
        headers_list = headers.split('\r\n')
        methods, url, protocal = headers_list[0].split(' ')
        func_name = None
        for item in routers:
            if item[0] == url:
                func_name = item[1]
                break
        if func_name:
            response = func_name(data)
        else:
            response = b'404'
        conn.send(response)
        conn.close()

if __name__ == '__main__':
    run()
1.5 web框架的分类

为了方便开发者开发web应用,web框架应用而生。有的web框架帮助开发者构建好了socket服务端,有的web框架帮助开发者写好了模板渲染。总之,借助web框架可以减轻了开发者的工作量。flask框架只有路由系统,没有socket服务端和模板引擎,socket服务端使用是python第三方模块,如wsgiref。模板引擎使用的也是第三方模块jinjia2。django框架有路由系统、模板引擎,但是没有socket服务端,socket服务端使用的是python的第三方内置模块wsgiref,wsgiref把请求交给django做处理。另外,还有一种叫Tornado的框架,Tornado框架包含socket服务端、路由系统、模板引擎。可以将web框架这样分类,django框架和其它框架。因为django框架提供了很多特殊的功能,如缓存、分布式。其它框架是轻量级的web框架。

2. 初识django

安装django:pip3 install django
创建django程序:django-admin startproject 项目名称
运行django程序:python manager.py runserver 127.0.0.1:8080(如果不指定,默认运行在8000端口)

3. django程序目录

manager.py:对当前django程序所有操作可以基于python manager.py runserver

settings.py:django配置文件

url.py:路由系统,url->函数

wsgi.py:用于定义django使用什么socket服务端,如wsgiref,uwsgi(wsgiref性能比较低)

4. 第一个django请求

usr.py:

from django.shortcuts import HttpResponse
# 处理请求的函数
def login(request):  #
    '''
    处理用户请求,返回相响应结果
    :param request:用户请求的相关信息(不是字节,是对象)
    :return:
    '''
    pass
    return HttpResponse('login!')
    
# url
urlpatterns = [
    # path('admin/', admin.site.urls),
    path('login/', login),
]
5. 静态文件以及模板的配置
5.1 静态文件路径的配置

创建静态文件目录也需要配置:

修改settings.py:

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject/en/2.2/howto/static-files/
'''
只要是使用/static/的前缀,就在这个目录(static目录)下找静态文件
'''
STATIC_URL = '/static/'
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static'),
)
5.2 HttpResponse与render函数
  • 返回字符串
    return HttpResponse(‘login!’)
    return HttpResponse(’< input type=“text”>’)
  • 返回模板
    render函数默认是在“templates”中自动找文件,读取文件内容后返回给用户。
    return render(request, ‘xxx.html’)
    render函数本质上是调用HttpResponse。
5.3 模板路径的配置

模板名称需要与配置文件设定的模板名字一致,

6. 创建程序步骤
6.1 创建project

django-admin startproject project名,也可以在pycharm中选择Django,创建project

6.2 配置模板路径

创建templates目录,然后修改配置文件:

TEMPLATES = [
    {
   
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')]#BASE_DIR指当前路径
        ,
        'APP_DIRS': True,
        'OPTIONS': {
   
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]
6.3 配置静态文件目录

创建static目录,然后修改配置文件:

'''
只要是使用/static/的前缀,就在这个目录下找静态文件
'''
STATIC_URL = '/static/'
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static'),
)
6.4 额外配置

django.middleware.csrf.CsrfViewMiddleware注释掉:

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middlewaremon.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
7. 用户登录示例

urls.py:

from django.contrib import admin
from django.urls import path

from django.shortcuts import HttpResponse, render, redirect

def login(request):  #
    '''
    处理用户请求,返回相响应结果
    :param request:用户请求的相关信息(不是字节,是对象)
    :return:
    '''
    if request.method == 'GET':
        return render(request, 'login.html')  # 本质上是调用HttpResponse,自动找到login.html文件,读取内容并返回给用户
    else:
        # print(request.POST)  # 用户POST提交的数据(请求体)<QueryDict: {'name': ['thanlon'], 'pwd': ['123']}>
        # user = request.POST['username']#直接索引,如果没有username会报错
        username = request.POST.get('username')  # 如果没有username不会报错,返回None
        pwd = request.POST.get('pwd')  # 如果没有username不会报错,返回None
        if username == 'thanlon' and pwd == '123456':
            return redirect('https://www.blueflags')
        else:
            return render(request, 'login.html', {
   'msg': '用户名或密码错误!'})  # django内部做模板渲染
            
urlpatterns = [
    # path('admin/', admin.site.urls),
    path('login/', login),
]

login.html:

<form action="/login/" method="POST" name="loginForm">
    <div class="form-group">
        <label for="name">用户名</label> <input type="text" class="form-control" name="username" placeholder="请输入用户名">
    </div>
    <div class="form-group">
        <label for="">密码</label> <input type="password" class="form-control" name="pwd" placeholder="请输入密码">
        <div style="color: red;font-weight: bold">{
   {
    msg }}</div>
    </div>
    <button type="submit" class="btn btn-primary" onclick="return checkForm()">登录</button>
</form>

登录效果:

8. request.GET与 request.POST
8.1 request.GET

request.GET是从请求头的url中获取值

8.2 request.POST

request.POST是从请求体中获取值。GET请求时,只有request.GET可以获取值。但POST请求时,request.POST和request.GET都可能获取值。

<form action="/login/?page=1" method="POST" name="loginForm">……

可以通过request.GET获取url中的page

9. django模板语言特殊标记(重点)
9.1 取字符串的值
def index(request):
    return render(request, 'index/index.html', {
   'username': '一问奈何'})
<p>{
  { username }}</p> # 一问奈何
9.2 取列表的值
def index(request):
    # return render(request, 'index/index.html', {'username': '一问奈何'})
    return render(request, 'index/index.html', {
   'username': ['thanlon','Kiku']})
  • 直接通过索引
{#<p>{
  { username }}</p>#}
{
  { username }}
{
  { username.0 }}
{
  { username.1 }}
  • 通过循环遍历
{% for item in username %}
    {
  { item }}
{% endfor %}

9.3 取字典的值
def index(request):
    return render(request, 'index/index.html', {
   
        'user_dict': {
   'name': '一问奈何', 'age': 23}
    })
<body>
	{
  { user_dict.name }}
	{
  { user_dict.age }}
<body>

9.4 取嵌套于列表中字典的值
def index(request):
    return render(request, 'index/index.html', {
   
        'user_list_dict': [
            {
   'id': 1, 'name': 'thanlon'},
            {
   'id': 2, 'name': 'kuku'},
        ]
    })
  • 通过索引取值
{
  { user_list_dict.0.id}}--{
  { user_list_dict.0.name}}
{
  { user_list_dict.1.id}}--{
  { user_list_dict.0.name}}
  • 通过循环取值
{% for row in user_list_dict %}
    {
  { row.id }}--{
  { row.name }}
{% endfor %}

10. 学生信息管理系统

Django实战项目 ------ 学生信息管理系统

11. 初识cookie

cookie是保存在浏览器端的特殊"键值对",服务端可以向浏览器端写cookie,客户端每次发送请求时需要携带本地cookie,此时cookie放到请求头中。服务端回写cookie会放到响应头中,render函数和redirect以及HttpResponse函数都可以在向服务端浏览器返回响应体的时候回写cookie。cookie的应用:可以用于投票,也可以用于用户登录

12. 基于cookie的登录验证

views.py:

def classes(request):
    '''
    查询班级id、班级名称
    :param request:对象相关的数据
    :return:渲染后的模板
    '''
    ticket = request.COOKIES.get('ticket')
    if not ticket:
        return redirect('/login/')
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='test')
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    cursor.execute("select id,title from class")
    classes_list = cursor.fetchall()
    cursor.close()
    conn.close()
    return render(request, 'classes.html', {
   'classes_list': classes_list})
    
def login(request):
    '''
    登录
    :param request:
    :return:
    '''
    username = request.POST.get('username')
    pwd = request.POST.get('pwd')
    if request.method == 'POST':
        if username == 'thanlon' and pwd == '123456':
            obj = redirect('/classes/')
            # obj.set_cookie('ticket', 'O2UikIFGGvHxcUQD7rIbgxedinIpEoMjStxoO579rgY8NeQM')
            return obj
    else:
        return render(request, 'login.html')

读所有的cookie使用request.COOKIES

13. django操作cookie

(1) 设置超时时间有两种方式,下面是设置cookie的函数源码:

def set_cookie(self, key, value='', max_age=None, expires=None, path='/',domain=None, secure=False, httponly=False, samesite=None):

第一种方式:

def login(request):
    username = request.POST.get('username')
    pwd = request.POST.get('pwd')
    if request.method == 'POST':
        if username == 'thanlon' and pwd == '123456':
            obj = redirect('/classes/')
            obj.set_cookie('ticket', 'O2UikIFGGvHxcUQD7rIbgxedinIpEoMjStxoO579rgY8NeQM',max_age=10)
            return obj
    else:
        return render(request, 'login.html')

max_age=10表示超时时间是10秒,10秒过后不管客户端有没有操作,都会跳转到登录页面。

第二种方式:

def login(request):
    username = request.POST.get('username')
    pwd = request.POST.get('pwd')
    if request.method == 'POST':
        if username == 'thanlon' and pwd == '123456'

本文标签: 实战入门django