【2022-08-30】Django框架(一)

Django框架

纯手撸web框架

搭建socket服务端

import socket

# 1.创建一个socket对象
server = socket.socket()
# 2.绑定一个固定的IP地址+端口号(ip:port)
server.bind(('127.0.0.1', 8080))
# 3.创建半连接池,为了做缓冲使用,减轻服务端压力
server.listen(5)
# 4.创建连接循环,实现数据交互
while True:
    sock, address = server.accept()
    # 5.接收客户端数据
    data = sock.recv(1024)
    print(data.decode())
    # 6.服务端响应的数据需要符合HTTP响应格式
    sock.send(b'HTTP/1.1 200 ok \r\n\r\n')
    # 7.将客户端请求相关数据转换为字符串
    data_str = data.decode('utf8')
    # 8.从请求数据格式中筛选出用户输入的网址后缀
    current_path = data_str.split(' ')[1]
    # 9.根据后缀不同返回不同的内容
    if current_path == '/register':
        sock.send(b'This is a register function')
    elif current_path == '/login':
        sock.send(b'This is a login function')
    else:
        sock.send(b'404 not found')

总结

http请求方式:
	GET
    	朝服务端索要数据
 	POST
    	朝服务端提交数据


上述手撸web框架的缺陷:
	1.socket代码重复编写造轮子
	2.针对请求数据格式的处理复杂且重复
 	3.针对不同网址后缀的匹配方式过于low

基于wsgiref模块搭建web框架

wsgiref内部封装了socket代码和对请求数据的处理

from wsgiref.simple_server import make_server


def run(request, response):
    """

    :param request:  请求相关数据
    :param response: 响应相关数据
    :return: 返回给客户端展示的数据
    """
    response('200 ok', [])  # 固定编写
    return [b'This is a wsgiref models very good']


if __name__ == '__main__':
    server = make_server('127.0.0.1', 8080, run)
    "监听本机端口8080,一旦有请求访问,则自定触发run方法的执行,与面向对象中的魔法方法__call__类似"
    server.serve_forever()       # 永久启动
    # 模块封装了socket代码并将请求数据处理为K:V键值对
    

代码封装优化

1.wsgiref模块解决了两个问题
	1.1 socket代码重复编写造轮子
	1.2 针对请求数据格式的处理复杂且重复
2.思考如何再次实现根据不同的网址后缀返回不同的内容(函数化)
	先从大字典中查找出记录网址后缀的键值对
	2.1 不推荐使用连续的多个if判断
	2.2 针对面条版的代码首先应该考虑封装成函数
    
from wsgiref.simple_server import make_server


def register(request):
    return 'register'


def login(request):
    return 'login'


def error(request):
    return 'error 404 not found'


urls = (
    ('/register', register),
    ('/login', login),
)


def run(request, response):
    """

    :param request:  请求相关数据
    :param response: 响应相关数据
    :return: 返回给客户端展示的数据
    """
    response('200 ok', [])  # 固定编写
    # print(request)
    current_path = request.get("PATH_INFO")
    # if current_path == '/login':
    #     return [b'hello login html']
    # elif current_path == '/register':
    #     return [b'hello register html']
    # return [b'404 not found']
    func_name = None
    for url_tuple in urls:
        if url_tuple[0] == current_path:
            # 先存储匹配到的函数名
            func_name = url_tuple[1]
            # 匹配成功,后续的对应关系就无需循环比对了
            break
    # for循环运行完毕后,func_name也有可能是None,所以需要做一个if判断
    if func_name:
        res = func_name(request)
    else:
        res = error(request)
    return [res.encode('utf8')]  # 做统一编码处理,这样函数就只需要返回字符串即可,操作更加简单


if __name__ == '__main__':
    server = make_server('127.0.0.1', 8080, run)
    "监听本机端口8080,一旦有请求访问,则自定触发run方法的执行,与面向对象中的魔法方法__call__类似"
    server.serve_forever()  # 永久启动
    # 模块封装了socket代码并将请求数据处理为K:V键值对

    
    

3.根据py文件中功能的不同划分到不同的py文件(模块化)
	urls.py	 		 对应关系
 	views.py 		 功能函数
  	start.py 		 启动文件
 	templates文件夹   存储html

views.py

# 功能函数

def register(request):
    return 'register'


def login(request):
    return 'login'


def index(request):
    return 'index'


def error(request):
    return 'error 404 not found'


urls.py

from views import *

# 后缀匹配

urls = (
    ('/register', register),
    ('/login', login),
    ('/index', index),
)

start.py

from wsgiref.simple_server import make_server
from urls import urls
from views import error


def run(request, response):
    response('200 OK', []) 
    current_path = request.get("PATH_INFO")
    func_name = None
    for url_tuple in urls:  # ('/register', register)
        if current_path == url_tuple[0]:
            func_name = url_tuple[1]
            break
    if func_name:
        res = func_name(request)
    else:
        res = error(request) 
    return [res.encode('utf8')]


if __name__ == '__main__':
    server = simple_server.make_server('127.0.0.1', 8080, run)
    server.serve_forever()

总结

拆分后好处在于要想新增一个功能,只需要在views.py中编写函数,urls.py添加对应关系即可

动静态网页

动态网页
	页面上的数据不是全部写死的 有些是动态获取(后端传入)
静态网页
	页面上的数据直接写死的 要想改变只能修改源码
 
实际需求
	后端代码获取当前时间 然后让前端页面展示
	1.字符串替换
 	2.将字典数据传递给html页面并且想要在页面上操作字典数据
    	我们无法自己实现>>>:在html页面上使用类似于后端的语法操作数据

动态页面展示

def get_time(request):
    import time
    # 1.获取当前时间
    current_time = time.strftime('%Y-%m-%d %H:%M:%S')
    # 2.打开html页面
    with open(r'templates/myhtml03.html', 'r', encoding='utf8') as f:
        data = f.read()
    # 3.字符串替换
    data = data.replace('hahaha', current_time)
    return data


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
    <h1>hahaha</h1>
</body>
</html>

安装jinja2

pip3 install jinja2

jinja2模板语法

jinja2能够让我们在html文件内使用类似于后端的语法来操作各种数据类型

from jinja2 import Template
def get_dict(request):
    user_dict = {'name': 'jason', 'pwd': 123, 'hobby': ['read', 'run', 'music']}
    with open(r'templates/myhtml04.html','r',encoding='utf8') as f:
        data = f.read()
    temp = Template(data)
    res = temp.render(data=user_dict)  # 将字典传递给html页面 页面上通过data即可获取(data仅仅是一个变量名)
    return res



<h1>{{ data }}</h1>
<h1>{{ data['name'] }}</h1>
<h1>{{ data.get('pwd') }}</h1>
<h1>{{ data.hobby }}</h1> 

前后端与数据库互联实例

数据库层面操作

数据库操作

1.登录mysql,完成库、表、数据的写入
2.启动mysql
	net start mysql
3.登录mysql
	mysql -uroot -p
4.创建数据库
	create database 库名;
5.查看数据库
	show databases;
6.切换到指定的库
	use 库名;
7.创建表
	create table userinfo(id int primary key auto_increment, name varchar(32),age int);
8.查看表
	desc userinfo;
9.写入数据
	insert into userinfo(name,age) values('jason',18),('tony',23),('kevin',24),('jerry',32);
10.查看数据
	select * from userinfo;

前端页面操作

<!DOCTYPE html>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
    <div class="container">
        <div class="row">
            <h1 class="text-center">用户信息</h1>
            <div class="col-md-8 col-md-offset-2">
                <table class="table table-hover table-striped ">
                    <thead>
                        <tr>
                            <th>主键</th>
                            <th>姓名</th>
                            <th>年龄</th>
                        </tr>
                    </thead>
                    <tbody>
                        {% for user in user_data %}
                            <tr class="info">
                                <td>{{user.id}}</td>
                                <td>{{user.name}}</td>
                                <td>{{user.age}}</td>
                            </tr>
                        {% endfor %}
                    </tbody>
                </table>
            </div>

        </div>
    </div>

</body>
</html>

后端逻辑代码

from jinja2 import Template
import pymysql


def get_mysql(request):
    # 1.连接数据库
    conn = pymysql.connect(
        host='127.0.0.1',
        port=3306,
        user='root',
        password='123456',
        database='day55',
        charset='utf8',
        autocommit=True
    )
    # 2.创建一个游标对象
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    sql = 'select * from userinfo'
    cursor.execute(sql)
    user_data = cursor.fetchall()  # [{},{},{},{}]
    with open(r'templates/myhtml04.html', 'r', encoding='utf8') as f:
        data = f.read()
    temp = Template(data)
    res = temp.render(user_data=user_data)
    return res


结果验证

python主流web框架

django
    大而全 自带的功能非常的多 但是有时候会略显笨重,类似于'航空母舰'
  
flask
    小而精 自带的功能非常的少 但是第三方模块非常的多,类似于'游骑兵'
    flask的第三方模块加到一起甚至比django还多 并且也越来越像django
    flask由于过多的依赖于第三方模块 有时候也会受制于第三方模块
  
tornado
    异步非阻塞框架 速度极快 甚至可以用于充当游戏服务器
    缺陷:上手难度是三者最高的

还有一些占比较小 但是也很厉害的框架
    fastapi、sanic......
  
"""
框架的核心逻辑几乎是一致的 我们在学习的时候只需要先学会一种
之后就可以触类旁通 但是需要强调的是:千万不用同时学习!!!
"""

django框架版本

版本问题
    django3.X:自带异步功能
    django2.X:默认不支持异步
    django1.X:默认不支持异步
    
    '''
      与3.X最主要的区别在于新增了一个异步的功能
    '''

django下载及注意事项

1.下载安装
    pip3 install django==1.11.11
    '''如果之前下载了其他版本不用管 自动替换!!!'''
    
2.启动注意事项
	1.计算机名称尽量不要有中文
 	2.项目中所有的py文件名尽量不要用中文
 	3.不同版本的python解释器配合不同版本的django会有一些报错
	启动如果报错,根据提示找到代码,并修改widgets.py文件第152行源码,删除最后的逗号即可
  	4.一个pycharm窗口只允许有一个项目 不要做项目的嵌套

3.验证django是否下载成功,需要提前配置环境变量,否则会出现报错
	cmd终端输入django-admin

django基本使用

命令行操作Django

	1.创建django项目
    	django-admin startproject 项目名
 	2.启动django项目
    	1.先切换到项目目录下
        	cd 项目名
       2.执行启动目录
    		 python38 manage.py runserver ip:port
 	3.访问django服务端
    	浏览器直接访问:http://127.0.0.1:8000/
 	4.创建app应用
    	"""
    	django框架类似于是一个空壳子 给你提供所需的资源
    	至于到底要写哪些功能 需要通过创建app来划分
    		eg:django初始项目可以看成是一所大学
    		   app就相当于是大学里面的各个学院
    	"""
       python38 manage.py startapp 应用名
 
"""
在启动django项目的时候 一定要确保一个端口只有一个项目
"""

pycharm操作Django

命令行与pycharm操作的区别

1.命令行不会自动创建templates文件夹
2.命令行不会在配置文件编写关于templates文件夹的配置
	'DIRS': [os.path.join(BASE_DIR, 'templates')]
3.pycharm自动创建的第一个应用会自动注册到配置文件中
4.针对db.sqlite3文件不用去在乎它有没有创建 只要运行了django会自动出来

django目录结构

django项目目录

	项目同名文件夹
    __init__.py  			很少用 主要做一些冷门配置
    settings.py    			项目配置文件
    urls.py		   		    对应关系(目前简单的理解:网址后缀跟函数名)
    wsgi.py		  		    django服务 基本不用
    manage.py			    django入口文件
    templates文件夹		  存储项目所需的html文件
    
    应用名文件夹(可以有多个)
    
    migrations文件夹  		  orm相关(数据库打交道的记录)
    __init__.py  			很少用 主要做一些冷门配置
    admin.py		 		django自带的后台管理
    apps.py					创建应用之后用于应用的注册
    models.py				存储与数据库表相关的类
    tests.py				自带的测试文件
    views.py		 		存储业务相关的逻辑代码(函数、类)
    db.sqlite3			 	自带的小型数据库

    urls.py					路由层
    views.py				视图层
    templates				模板层
    models.py   			模型层

Django小白必会三板斧

urls.py

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

urlpatterns = [
    path('admin/', admin.site.urls),
    path('index/', views.index),
    path('function/', views.function),
    path('login/', views.login),
]

view.py

from django.shortcuts import render, HttpResponse, redirect

# Create your views here.

HttpResponse
	主要用于直接返回字符串类型的数据
   
    def index(request):
        return HttpResponse('山重水复疑无路,柳暗花明又一村')
    
render
	主要用于返回html页面 并且支持模板语法
    
    def function(request):
    user_dict = {'name': 'jason', 'pwd': 123}
    return render(request, 'myhtml.html', {'data': user_dict})


redirect
	主要用于页面重定向,如下所示:跳转页面到百度,地址可以自定义
    
    def login(request):
    return redirect('https://www.baidu.com')
   

myhtml

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
        <script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
    </head>
    <body>
        <h1 class="text-center">This is a Django2.2.22 version welcome to Django</h1>
        <h1>{{ data }}</h1>
        <h1>{{ data.name }}</h1>
        <h1>{{ data.pwd }}</h1>
    </body>
    </html>

基于Django获取数据库信息并展示到前端

urls.py

"""day55_Django URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/2.2/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('index/', views.index),
    path('function/', views.function),
    path('login/', views.login),
    path('mysql/', views.mysql),
]

views.py

from django.shortcuts import render, HttpResponse, redirect


# Create your views here.

def index(request):
    return HttpResponse('山重水复疑无路,柳暗花明又一村')


def function(request):
    user_dict = {'name': 'jason', 'pwd': 123}
    return render(request, 'myhtml.html', {'data': user_dict})


def login(request):
    return redirect('mysql')


from jinja2 import Template
import pymysql


def mysql(request):
    # 1.连接数据库
    conn = pymysql.connect(
        host='127.0.0.1',
        port=3306,
        user='root',
        password='123456',
        database='day55',
        charset='utf8',
        autocommit=True
    )
    # 2.创建一个游标对象
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    sql = 'select * from userinfo'
    cursor.execute(sql)
    user_data = cursor.fetchall()  # [{},{},{},{}]
    with open(r'templates/myhtml.html', 'r', encoding='utf8') as f:
        data = f.read()
    temp = Template(data)
    res = temp.render(user_data=user_data)
    # return res
    return HttpResponse(res)

myhtml

<!DOCTYPE html>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
    <div class="container">
        <div class="row">
            <h1 class="text-center">用户信息</h1>
            <div class="col-md-8 col-md-offset-2">
                <table class="table table-hover table-striped ">
                    <thead>
                        <tr>
                            <th>主键</th>
                            <th>姓名</th>
                            <th>年龄</th>
                        </tr>
                    </thead>
                    <tbody>
                        {% for user in user_data %}
                            <tr class="info">
                                <td>{{user.id}}</td>
                                <td>{{user.name}}</td>
                                <td>{{user.age}}</td>
                            </tr>
                        {% endfor %}
                    </tbody>
                </table>
            </div>

        </div>
    </div>

</body>
</html>

posted @   dy12138  阅读(124)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示