django(web框架推导、简介、数据库初识)

一 web框架推导

1 软件开发架构

cs架构
bs架构
bs本质是也是cs

# HTTP协议:无状态,无连接,基于请求,基于tcp/ip的应用层协议

# mysql:c/s架构,底层基于soket,自己封装的协议。mysql的其他客户,navicate(c++图形化界面,实现了请求和响应协议);pymysql(用python语言实现了请求和响应协议)

# redis:c/s架构,基于socket,自己封装的协议

# docker:c/s架构,基于HTTP协议,使用restfull规范

# elasticsearch:c/s架构,基于http协议,使用restfull规范

2 纯手撸web框架

# HTTP协议
'''
          网络协议
HTTP协议           数据传输是明文
HTTPS协议          数据传输是密文
websocket协议      数据传输是密文

四大特性
    1.基于请求响应
    2.基于TCP、IP作用于应用层之上的协议
    3、无状态
    4、短/无链接
    
数据格式
    请求首行
    请求头
        请求体
    
响应状态码
    1xx
    2xx
    3xx
    4xx
    5xx
    
如何做到后缀的不同返回不同的内容
   拿到用户输入的后缀,做判断
    
不足之处
1、代码重复
2、手动处理http格式的数据,并且只能拿到url后缀,其他数据获取繁琐
3、并发的问题
'''

例:

# 可以将web框架理解成服务端
import socket

server = socket.socket()  # TCP 三次握手四次握手 osi七层
server.bind(('127.0.0.1', 8080))  # IP协议 以太网协议 arp协议
server.listen(5)  #

'''
b'GET / HTTP/1.1\r\n
Host: 127.0.0.1:8080\r\n
Connection: keep-alive\r\n
Cache-Control: max-age=0\r\n
sec-ch-ua: "Google Chrome";v="107", "Chromium";v="107", "Not=A?Brand";v="24"\r\n
sec-ch-ua-mobile: ?0\r\n
sec-ch-ua-platform: "Windows"\r\n
Upgrade-Insecure-Requests: 1\r\n
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9\r\n
Sec-Fetch-Site: none\r\n
Sec-Fetch-Mode: navigate\r\n
Sec-Fetch-User: ?1\r\n
Sec-Fetch-Dest: document\r\n
Accept-Encoding: gzip, deflate, br\r\n
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8\r\n\r\n'
'''
while True:
    conn, addr = server.accept()
    data = conn.recv(1024)
    print(data)  # 二进制
    data = data.decode('utf-8')  # 字符串
    # 获取字符串中特定的内容      正则    如果字符串有规律也可以考虑用切割
    # 直接忽略favicon.ico
    conn.send(b'HTTP/1.1 200 ok\r\n\r\n')
    current_path = data.split(' ')[1]
    # print(current_path)
    if current_path == '/index':
        # conn.send(b'index ha ha')
        with open(r'templates/新闻页面.html', 'rb') as f:
            conn.send(f.read())
    elif current_path == '/login':
        conn.send(b'login ai ai')
    else:
        conn.send(b'Hello word')
    conn.close()

2 借助于wsgiref模块

'''
urls.py           路由和视图函数对应关系
views.py          视图函数(后端业务逻辑)
templates文件夹    专门用来存储html文件
'''
# 按照功能的不同拆分之后,后续添加功能只需要在urls.py书写对应关系然后去views.py书写业务逻辑即可

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


def run(env, response):
'''
:param env: 请求相关的所有数据
:param response: 响应相关的所有的数据
:return: 返回给浏览器的数据
'''
# print(env) # 大字典 wsgiref模块帮你处理好http格式的数据,字典格式
# 从env中获取
response('200 ok', []) # 响应首行 响应头
current_path = env.get('PATH_INFO')
# if current_path == '/index':
# return [b'hello index']
# elif current_path == '/login':
# return [b'hell login']
# return [b'404 error']

# 定义一个变量,存储匹配到的函数名
func = None
for url in urls:
if current_path == url[0]:
# 将url对应的函数名赋值给func
func = url[1]
break # 匹配一个之后,应该立刻结束

if func:
res = func(env)
else:
res = error(env)

return [res.encode('utf-8')]


if __name__ == '__main__':
server = make_server('127.0.0.1', 8080, run)
'''
会实时监听127.0.0.1:8080地址,只要有客户端来了
都会交给run函数处理(加括号触发run函数的运行)

flask启动源码
make_server('127.0.0.1',8080,obj)
'''
server.serve_forever() # 启动服务端
 

3 动静态网页

静态网页
  页面上的数据是直接写死的,一直不变(不需要数据库操作)
动态网页
  数据是实时获取的(就需要进行数据库操作)
  ps:
    1、后端获取当前时间展示到html页面上
    2、数据是从数据库中获取的展示到html页面上

# 动态网页制作
import datetime
def get_time(env):
    current_time = datetime.datetime.now().strftime('%Y-%m-%d %x')
    # 如何将后端获取的数据“传递”给html文件?
    with open(r'templates/03 mytime.html', 'r', encoding='utf-8') as f:
        data = f.read()
        # data就是一堆字符串(html文件是一对字符串)
    data = data.replace('lq', current_time)    # 在后端将html页面处理好之后再返回给前端,操作字符串
    return data

# 后端获取数据库中数据展示到前端页面
# 利用wsgiref模块封装的web框架加上jinja2模板语法,结合前端后端数据库

4 模板语法之jinja2模块

# 将一个字典传递给html文件,并且可以在文件上方便快捷的操作字典数据
pip3 install jinja2
'''模版语法是在后端起作用的'''
from jinja2 import Template

def get_dict(env):
    user_dic = {'username': 'lq', 'age': 18, 'hobby': 'read'}
    with open(r'templates/04 get_dict.html', 'r', encoding='utf-8') as f:
        data = f.read()
    tmp = Template(data)
    res = tmp.render(user=user_dic)
    # 给get_dict.html传递了一个值,页面上通过变量名user就能够拿到user_dict
    return res

# 模板语法(非常贴近python语法)
{{user}}
{{user.get('username')}}
{{user.age}}
{{user['hobby']}}

{% for user_dict in user_info %}
    <tr>
        <td>{{ user_dict.id }}</td>
        <td>{{ user_dict.name }}</td>
        <td>{{ user_dict.password }}</td>
        <td>{{ user_dict.hobby }}</td>
    </tr>
{% endfor %}

5 借助pymysql实现和数据库链接

import pymysql


def get_user(env): # 视图文件中的视图函数
    # 去数据库中获取数据,传递给html页面,借助于模版语法,发送给浏览器
    conn = pymysql.connect(
        host='127.0.0.1',
        port=3306,
        user='root',
        password='123',
        db='day59',
        charset='utf8',
        autocommit=True
    )

    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    sql = 'select * from userinfo'
    affect_rows = cursor.execute(sql)
    data_list = cursor.fetchall()   # data_list,列表套字典格式
    # print(data_list)
    with open(r'templates/05 get_user.html', 'r', encoding='utf-8') as f:
        data = f.read()
    print(data)
    tmp = Template(data)
    res = tmp.render(user_info=data_list)
    return res

6 自定义简易版本web框架请求流程图

 

wsgiref模块
  1、请求来的时候解析http格式的数据,封装成大字典
  2、响应走的时候给数据打包成符合http格式,再返回给浏览器

二 django简介

1 python三大主流web框架

'''
django
    特点:大而全,自带的功能特别多
    不足之处:
        有时候过于笨重
django是一个同步框架,django3.x异步框架 flask 特点:小而精,自带的功能特别少 第三方的模块特别多,越来越来像django 不足之处: 比较依赖第三方的开发者 tornado 特点:异步非阻塞,支持高并发
''' A:socket部分 B:路由与视图函数对应关系(路由匹配) C:模板语法 django A用的别人的 wsgiref模块 B用的是自己的 C用的是自己的(没有jinja2好用,但是很方便) flask A用的是别人的 werkzeug(内部还是wsgiref模块) B自己写的 C用的别人的(jinja2) tornado A B C都是自己写的

2 注意事项

# 如何让你的计算机能够正常的启动django项目
1、计算机的名称不能有中文
2、一个pycharm窗口只开一个项目
3、项目里面所有的文件也尽量不要出现中文
4、python解释器尽量使用3.4-3.6之间的版本
(如果你的项目报错,点击最后一个报错信息去
源码中把逗号删除)

# django版本问题
1.x 2.x 3.x(直接忽略)
1.x 和 2.x 本身差距不大,以1.x为例
LTS维护时间

# django安装
pip3 install django==1.11.11
如果已经安装了其他版本,无需自己卸载
直接重装,会自动卸载安装新的

验证是否安装成功的方式
    终端输入django-admin看看有没有反应

3 django 基本操作

命令行操作

# 命令行操作
    1、创建django项目
    windows可以先切换到对应的需要建项目存储位置,然后再创建
    
    django-admin startproject mysite
    
    mysite文件
        manage.py
        mysite文件夹
            __init__.py
            setting.py
            urls.py
            wsgi.py
# 2、启动django项目
'''
 一定要先切换到项目下
    cd /mysite
'''
python3 manage.py runserver
    http://127.0.0.1:8000/
   
# 3、创建应用
'''
Next, start your first app by running python manage.py startapp [app_label].
'''
python3 manage.py startapp app01
应用名应该做到见名知意
    user
    order
    web

教学统一用app01/02/03
有很多文件    

pycharm操作

# 1、new project 选择左侧第二个django即可
# 2、启动
    1)还是用命令行
    2)点击绿色小箭头即可
# 3、创建应用
    1)pycharm提供的终端直接输入完整命令
    python3  manage.py startapp app01
    2)pycharm  
    tools  run manage.py task提示
# 4、修改端口号以及创建server
    edit confi  

4 应用

'''
django是一款专门用来开发app(功能)的web框架
比如淘宝
    订单功能
    用户相关
    投诉相关
创建不同的app对应不同的功能

还比如选课系统
    学生功能
    老师功能
    
一个app就是一个独立的功能模块
'''

**************创建的应用一定要去配置文件中注册*************
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app01.apps.App01Config',   # 全写
'app02',    # 简写
]
# 创建出来的应用第一步先去配置文件中注册
ps:在用pycharm创建项目的时候,Pycharm可以帮你创建一个app并且自动注册

5 主要文件介绍

-mysite项目文件夹
    --mysite文件夹
        --settings.py       配置文件
        --urls.py           路由与视图函数对应关系(路由层)
        --wsgi.py           wsgiref模块(不考虑)
    --manage.py             django的入口文件
    --db.sqlite3            django自带的sqlite3数据库(小型数据库,功能不多有bug)
    --app01文件夹
        --admin.py          django后台管理
        --apps.py           注册使用
        --migrations文件夹   数据库迁移记录
        --models.py         数据库相关的 模型类(orm)
        --tests.py          测试文件
        --views.py          视图函数(视图层)

6 命令行与pycharm创建的区别

# 命令行创建不会自动有templates文件,需要自己手动创建,而pycharm会自动帮你创建,并且自动在配置文件中配置对应的路径。

# 命令行创建
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
    },
]

# pycharm创建
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
    },
]

'''
命令行创建django项目的是空,不仅要创建templates文件,还要配置templates文件路径
'DIRS': [os.path.join(BASE_DIR, 'templates')
'''

7 django小白必会三把斧

app应用下面views.py中
from django.shortuts import HttpResonse,render,redirect

HttpResponse
    返回字符串类型的数据
    return HttpResponse('我不想值班,好累')

render
    返回html文件   
    return render(request, 'first.html')  # setting文件里路径已帮忙设置好
      
def ab_render(request):
    # 视图函数必须要接受一个形参request
    user_dict = {'username': 'lq', 'age': 18}
    # 第一种传值方式:更加的精准,节省资源
    # return render(request, '01 ab_render.html', {'data': user_dict})
    # 第二种传值方式:当你要传的数据特别多的时候
    # locals会将所在的名称空间中所有的名字全部传递给html页面
    return render(request, '01 ab_render.html', locals())
  
redirect
    重定向
    return redirect('https://www.xiaomi.com/')
    return redirect('/home/') # 跳自己的网址

8 静态文件配置

# 登录功能
html文件默认都放在templates文件下
将网站所使用的静态文件默认都放在static文件夹下

静态文件
    前端已经写好了的,能够直接调用使用的文件
        网站写好的js文件
        网站写好的css文件
        网站用到的图片文件
        第三方前端框架
        
        拿来就可以直接使用的
        
# django默认是不会自动创建static文件夹,需要自己手动创建
一般情况下我们在static文件夹内还会做进一步的划分处理
    -static
        --js
        --css
        --img
        其他三方文件
        
'''
在浏览器中输入url能够看到对应的资源
是因为后端提前开设了该资源的接口
如果访问不到资源,说明后端没有开设该资源的接口
http://127.0.0.1:8000/static/bootstrap-3.4.1-dist/css/bootstrap.min.css
'''

********************************************************
# 静态文件配置
STATIC_URL = '/static/'  # 类似于访问静态文件的令牌

# 要想访问静态文件,必须以static开头
# /static/bootstrap-3.4.1-dist/js/bootstrap.min.js
# /static/令牌
# 取列表里面从上往下依次查找
#   bootstrap-3.4.1-dist/js/bootstrap.min.js
#       都没有才报错

# 配置
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'static'),
    os.path.join(BASE_DIR, 'static1'),
    os.path.join(BASE_DIR, 'static2'),
]
# 从上往下找

********************************************************
当你在写django项目的时候,可能会出现后端代码修改了但是前端页面没有变化的情况
    1.你在同一个端口开了好几个django项目
    一直在跑的其实是第一个django项目
    
    2.浏览器缓存的问题
        settings
            network
                disable cache 勾线上
 ********************************************************  # 静态文件动态解析
在html文件中
{% load static %}
<link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js'%}">

# form表单默认是get请求数据
http://127.0.0.1:8000/login/?username=lq&password=123

'''
form表单action参数
    1、不写 默认朝当前所在的url提交数据
    2、全写 指名道姓
    3、只写后缀 /login/  自动补全ip和端口
'''

# 在前期使用django提交post请求的时候,需要取配置文件中注释掉一行代码
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

9 request对象方法初识

request.method   # 返回请求方式,并且是全大写的字符串类型  < class 'str'>

request.POST     # 获取用户POST请求提交的普通数据不包含文件
print(request.POST)
# 字典嵌套列表的格式
# <QueryDict: {'username': ['lq'], 'password': ['123'], 'hobby': ['111', '222', '333']}>

request.POST.get() # 获取列表最后一个元素,获取类型是字符串 request.POST.getlist() # 直接将列表取出,类型是列表 request.GET # 获取用户GET请求提交的普通数据不包含文件
print(request.GET)
#
字典嵌套列表的格式
# <QueryDict: {'username': ['lq'], 'password': ['123'], 'hobby': ['111', '222', '333']}>
    request.GET.get()  # 获取列表最后一个元素
    request.GET.getlist()  # 直接将列表取出

'''
GET请求携带的数据是有大小限制的,大概只有4kb左右
POST请求则没有限制
'''
def login(request):
    # 返回一个登录界面
    '''
    get请求和post请求应该有不同的处理机制
    :param request: 请求相关的数据对象,里面有很多简易的方法
    :return:
    '''
    # print(request.method)  # 返回请求方式,并且是全大写的字符串形式
    if request.method == 'GET':
        print(request.GET)
        # return HttpResponse('收到,宝贝')
    # elif request.method == 'POST':
    #     return HttpResponse('收到,宝贝')
    # 推荐写法
    if request.method == 'POST':
        # 获取用户数据
        print(request.POST)  # 获取用户提交的post请求数据(不包含文件)
        # <QueryDict: {'username': ['lq'], 'password': ['123']}>
        # username = request.POST.get('username')
        # print(username, type(username))  # lq<class 'str'>
        # get只会获取列表最后一个元素,所以获取的值是字符串类型
        # hobby = request.POST.getlist('hobby') # 列表
        hobby = request.POST.get('hobby')  # 字符串
        print(hobby, type(hobby))
        # getlist 获取的值就是个列表

        # 获取用户的用户名和密码,然后利用orm操作数据,校验数据是否正确
        username = request.POST.get('username')
        password = request.POST.get('password')
        # print(password, type(password))
        # 去数据库中查询数据
        res = models.User.objects.filter()
        print(res)
        # <QuerySet [<User: User object>]>  [数据对象1,数据对象2...],表中的一行一行的数据
        user_obj = models.User.objects.filter().first()
        user_obj = res[1]
        print(user_obj)
        print(user_obj.username)
        print(user_obj.password, type(user_obj.password))
        if user_obj:
            # 比对密码是否一直
            if password == str(user_obj.password):
                return HttpResponse('登录成功')
            else:
                return HttpResponse('密码错误')
        else:
            return HttpResponse('用户不存在')
    # print(request.GET)  # 获取用户提交的get请求数据
    # # <QueryDict: {'username': ['lq'], 'password': ['123'], 'hobby': ['111', '222', '333']}>
    # hobby = request.GET.get('username')
    # print(hobby, type(hobby))
    # print(request)
    return render(request, 'login.html')

 

 

三 数据库

pycharm链接数据库(MySQL)

'''
三个位置查找数据库相关
    右侧上方database
    左下方database
    配置里面的plugins插件搜索安装
    
    再没有,只有卸载pycharm
    
pycharm可以充当很多款数据库软件的客户端
'''
# 需要提前创建好库

# 明明链接上了数据库,但是看不到表无法操作这个时候只需要将刚刚创建的链接删除,重新链接一次即可

django链接数据库(MySQL)

# 默认用的是sqkite3
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

# django链接MySQL
    1、第一步配置文件中配置
    DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'day60',
        'USER': 'root',
        'PASSWORD': '123',
        'HOST': '127.0.0.1',
        'PORT': 3306,
        'CHARSET': 'utf8',
        'OPTIONS':{'init_command':'SET sql_mode="STRICT_TRANS_TABLES",storage_engine=INNODB;'}  #设置数据库为INNODB,为第三方数据库登录用
    }
}
    2、代码声明
    django默认用得是mysqldb模块链接MySQL
    但是该模块的兼容性不好,需要手动改为用pymysql链接
    
    需要告诉django不要用默认的mysqldb,而是用pymysql
    
    # 在项目名下的init或者任意的应用名下的init文件中书写以下代码即可
    import pymysql
    pymysql.install_as_MySQLdb()

Django ORM

*******ORM不会帮你创建库,只能创建到表的层面**********
'''
ORM   叫对象关系映射
作用:能够让一个不会sql语句的小白也能够通过python,面向对象的代码简单快捷的操作数据库
不足之处:封装程度太高,有时候sql语句的效率偏低,需要自己写SQL语句

类                表
对象              记录
对象属性           记录某个字段对应的值
'''

应用下面的models.py文件

# 1.先去models.py中书写一个类(类<--->模型类  表<--->模型表)
class User(models.Model):
    # id int primary_key auto_increment
    id = models.AutoField(primary_key=True)
    # 等价sql语句,username varchar(32)
    username=models.CharField(max_length=32)
    # 等价sql语句,password int
    password=models.IntegerField()

*******************2.数据库迁移命令**********************
'''
python3 manage.py makemigrations 将操作记录到(migrations文件夹)
python3 manage.py migrate    将操作真正的同步到数据库中

pycharm简单快捷输入
    tools
        run manage.py tassk
            自动提示
'''
****只要你修改了models.py中跟数据库相关的代码,就必须重新执行上述的两条命令****

class User(models.Model):
    # id int primary_key auto_increment
    id = models.AutoField(primary_key=True)
    username = models.CharField(max_length=32, verbose_name='用户名')
    '''
    CharField必须要指定max_length参数,不指定会直接报错
    verbose_name该参数是所有的字段都有的,就是用来对字段的解释
    '''
    password = models.IntegerField(verbose_name='密码')

class Author(models.Model):
    '''
    由于一张表中必须要有一个主键字段,并且一般情况下都叫id字段
    所以orm不定义主键字段的时候,orm会自动帮你创建一个名为id主键字段
    后续在创建模型表的时候,主键字段名没有额外的叫法,那么主键字段可以省略不写
    '''
    username = models.CharField(max_length=32)
    password = models.IntegerField()

字段的增删改查

# 字段的增加
    1、可以在终端内直接给出默认值
    2、该字段可以为空
    info = models.CharField(max_length=32, verbose_name='个人简介', null=True)
    3、直接给字段设置默认值
    hobby = models.CharField(max_length=32, verbose_name='兴趣爱好', default='study')

# 字段的修改
直接修改字段代码然后执行数据库迁移的两条命令即可

# 字段的删
直接注释对应的字段,再执行数据库迁移的两条命令即可
执行完毕后字段对应的数据也都没有了

'''
在操作models.py的时候一定要细心
    千万不要注释一些字段
    执行迁移命令之前最好先检查一下自己写的代码
'''

数据的增删改查(表中一行一行的数据为对象)

#
res=models.User.objects.filter(username=username)
print(res)
# <QuerySet [<User: User object>]>  [数据对象1,数据对象2...],表中的一行一行的数据
'''
返回值是一个querySet对象,你先看成是列表套数据对象的格式  [数据对象1,数据对象2....],表中的一行一行的数据
它支持索引取值,切片操作,但是不支持负数索引
同样不支持索引取值
'''
user_obj = res[0]
print(user_obj)
print(user_obj.username)
print(user_obj.password, type(user_obj.password))

# 推荐的取值方式
user_obj=models.User.objects.filter(username=username).first()
# first()对应的就是索引为0的数据对象,在mysql表中,也是取主键值为1的一行数据集合对象
'''
filter括号内可以携带多个参数,参数与参数之间默认是and关系,筛选出那一行数据
可以把filter联想成where记忆
'''

数据的增

# 直接获取用户数据存入数据库,
insert into t1(age,name) values(18,'jason');  # mysql中插入数据

def reg(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        # 直接获取用户数据存入数据库
        # 第一种增加方式
        # res = models.User.objects.create(username=username, password=password)
        # 返回值就是当前被创建的对象本身
        # print(res, res.username, res.password)

        # 第二种增加方式
        user_obj = models.User(username=username, password=password)
        user_obj.save()
    # 先给用户返回一个注册页面
    return render(request, 'reg.html')


# 第一种方式增加
    from app01 import models
    res = models.User.objects.create(username=username, password=password)
    # 返回值就是当前被创建的对象本身
    print(res, res.username, res.password)
    
# 第二种方式增加    
  user_obj=models.User(username=username,password=password)
user_obj.save()

数据的查、改、删(实例)

需求:先讲数据库中的数据全部展示到前端,然后给每一个数据两个按钮,一个编辑,一个删除

#
def userlist(request):
    # 查询用户表里面所有的数据
    # 方式一
    # data=models.User.objects.filter()
    # print(data)

    # 方式二
    user_queryset = models.User.objects.all()
    # print(data)    # <QuerySet [<User: User object>, <User: User object>]>

    # return render(request,'userlist.html',{'user_queryset':user_queryset})
    return render(request, 'userlist.html', locals())

useerlist.html

<body>
<h1 class="text-center">数据展示</h1>
<div class="row">
    <div class="col-md-8 col-md-offset-2">
        <table class="table table-striped table-hover">
            <thead>
            <tr>
                <th>ID</th>
                <th>username</th>
                <th>password</th>
                <th>action</th>
            </tr>
            </thead>
            <tbody>
            {% for user_obj in user_queryset %}
                <tr>
                    <td>{{ user_obj.id }}</td>
                    <td>{{ user_obj.username }}</td>
                    <td>{{ user_obj.password }}</td>
                    <td>
                        <a href="/edit_user/?user_id={{ user_obj.id }}" class="btn btn-primary btn-xs">编辑</a>
                        <a href="/delete_user/?user_id={{ user_obj.id }}" class="btn btn-danger btn-xs">删除</a>
                    </td>
                </tr>

            {% endfor %}

            </tbody>
        </table>
    </div>
</div>
</body>

流程:

  点击userlist.html中的编辑a标签,是用get的方式,通过urls.py中的/edit/到视图函数edit(),根据选择的edit_id,

从数据库中查询到要编辑的数据,展现到edit.html文件中,修改后,点击提交,from表单中的action没有值,

提交的数据的地址任是/edit/,这次是post请求,就把数据传给数据库,并修改,redirect(/userlist/),再执行视图函数

uselist(),查询新的更新后的数据库数据,展示到userlist.html。

# 编辑功能
    # 点击编辑按钮朝后端发送编辑数据的请求
    '''
    如何告诉后端用户想要编辑那一条数据?
        将编辑按钮所在的那一行数据的主键值发送给后端
        利用url问号后面携带参数的方式      
    '''
     后端查询出用户想要编辑的数据对象,展示到前端页面供用户查看和编辑
  
def edit(request): # 获取url问号后面的参数 edit_id = request.GET.get('user_id') # 查询当前用户想要编辑的数据对象 # edit_obj = models.User.objects.filter(id=edit_id).first() if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') # 修改数据库中对应的数据内容 # 修改数据方式1 models.User.objects.filter(id=edit_id).update(username=username, password=password) ''' 将filter查询出来的列表中的所有的对象全部更新 批量更新操作 只修改被修改的字段 ''' # 修改数据方式2 # edit_obj.username=username # edit_obj.password=password # edit_obj.save() ''' 上述方法当字段特别多的时候效率会非常底 从头到尾将数据的所有字段全部更新一遍,无论该字段是否被修改 ''' # 跳转到数据的展示页面 return redirect('/userlist/') # 查询当前用户想要编辑的数据对象 edit_obj = models.User.objects.filter(id=edit_id).first() # 返回编辑页面 return render(request, 'edit_user.html', locals())

edit_user.html

<body>
<h1 class="text-center">编辑</h1>
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <form action="" method="post">
                <p>username:<input type="text" name="username" class="form-control" value="{{ edit_obj.username }}"></p>
                <p>password:<input type="text" name="password" class="form-control" value="{{ edit_obj.password }}"></p>
                <input type="submit" class="btn btn-info btn-block" value="编辑">
            </form>
        </div>
    </div>
</div>
</body>
# 删除功能
def delete_user(request):
    # 获取用户想要删除的数据id值
    delete_id=request.GET.get('user_id')
    # 直接去数据库中找到对应的数据删除即可
    models.User.objects.filter(id=delete_id).delete()
    '''
    批量删除
    '''
    # 跳转到展示页面
    return redirect('/userlist/')
'''
真正的删除功能应该要二次确认,后面再讲
删除数据内部不是真正的删除,会给数据添加一个标识字段用来表示当前数据是否被删除了,
如果数据被删了仅仅只是将字段修改一个字段
'''

    username   password   is_delete
    lq             123       0
    zd             123       1 

django orm中如何创建表关系

'''
表与表之间的关系
    一对多
    
    多对多
    
    一对一
判断表关系的方法:换位思考
'''
图书表

出版社表

作者表

作者详情表
'''
图书和出版社是一对多的关系,外键字段建在多的那一方,book

图书和作者是多对多的关系,需创建第三张表专门储存

作者和作责详情表是一对一 
'''
# 创建表关系,先将基表创建出来,然后再添加外键字段
class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8, decimal_places=2)
    # 总共八位,小数点后面占两位
    '''
    图书和出版社是一对多,并且书是多的一方,所以外键字段放在书表后面
    '''
    publish = models.ForeignKey(to='Publish')  # 默认就是与出版社表的主键字段做外键关联
    '''
    如果字段对应的是ForeignKey,那么orm会自动在字段的后面加_id
    如果加了_id,后面还是会加_id
    '''
    '''
    图书和作者是多对多的关系,外键字段键在任意一方均可,但是推荐在查询频率较高的一方
    '''
    authors = models.ManyToManyField(to='Author')
    '''
    authors是一个虚拟字段,主要用来告诉ORM,书籍表和作者表是多对多关系
    让ORM自动帮你创建第三张关系表
    '''
class Publish(models.Model):
    name = models.CharField(max_length=32)
    addr = models.CharField(max_length=32)


class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    '''
    作者与作者详情是一对一的关系,外键字段在任意一方都可以,当时推荐建在查询频率较高的表中
    '''
    author_detail = models.OneToOneField(to='AuthorDetail')
    '''
    OneToOneField也会自动给字段加_id后缀
    所以也不要在在后面加_id
    '''


class AuthorDetail(models.Model):
    phone = models.BigIntegerField()
    addr = models.CharField(max_length=32)
    
    
'''
ORM中如何定义三种关系
    publish = models.ForeignKey(to='Publish')
    authors = models.ManyToManyField(to='Author')
    author_detail = models.OneToOneField(to='AuthorDetail')
    
    ForeignKey
    oneToOneField
        会自动在字段后面加_id后缀
'''
# 在django1.x版本中外键默认都是级联更新级联删除
# 多对多的表关系可以有好几种创建方式,暂且介绍一种
# 针对外键字段里面的其他参数,暂时不考虑,自己可以百度

django请求生命周期流程图(必会)

扩展知识

缓存数据库

提前已经将你想要的数据准备好了,你来直接拿就可以

提高效率和响应时间

当你在web页面修改数据时,并没有立刻修改,要等段时间才修改 是因为请求数据还是在访问缓存数据库,没有访问后端数据库

四 虚拟环境(了解)

在正常开发中,我们给每一个项目配备一个该项目独有的解释器环境
该环境只有该项目用到的模块,用不到一概不装

linux缺什么才装什么

虚拟环境
  每创建一个虚拟环境就类似于重新下载了一个纯净的python解释器
  但是虚拟环境不要创建太多,是需要消耗硬盘空间

扩展:
  每一个项目要用到很多模块,能不能一次装好

  开发中,给每一个项目配备一个requirement.txt文件
  里面书写该项目所有的模块既版本
  直接输入一条命令即可一键安装所有模块既版本

创建虚拟环境的步骤,new project---pure python---点击new environment ---点击make available to all projects---create---退出

---setting---interpreter---安装包---django---退出---new project---选择虚拟环境的解释器

五 django版本''django1.x路由层使用的是url方法

而django2.x和3.x版本中路由使用的是path方法
    url()第一个参数支持正则
    path()第一个参数是不支持正则,写什么就匹配什么
    
    如果习惯使用path那么再提供另外一种方法
'''
    from django.urls import path, re_path
    from django.conf.urls import url
    
    re_path(r'^index/',views.index)
    url(r'^login/',login)
    
# 2.x和3.x版本里的re_path等价一1.x里的url

#  虽然path不支持正则,但是它内部支持五种转换器
path('index/<int:id>/', views.index)
# 将第二个路由里面的内容先转成整型,然后以关键字的形式传递给视图函数     

def index(request, id):
    print(id,type(id))
    return HttpResponse('index')

'''
str,匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
int,匹配正整数,包含0。
slug,匹配字母、数字以及横杠、下划线组成的字符串。
uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
path,匹配任何非空字符串,包含了路径分隔符(/)(不能用?)
'''

# 除了有默认的五个转换器之外,还支持自定义转换器(了解)
class MonthConverter:
    regex='\d{2}' # 属性名必须为regex

    def to_python(self, value):
        return int(value)

    def to_url(self, value):
        return value # 匹配的regex是两个数字,返回的结果也必须是两个数字
    
from django.urls import path,register_converter
from app01.path_converts import MonthConverter

register_converter(MonthConverter,'mon')

from app01 import views


urlpatterns = [
    path('articles/<int:year>/<mon:month>/<slug:other>/', views.article_detail, name='aaa'),

]


# 模型层里面1.x外键默认都是级联更新删除的,但是到了2.x和3.x中需要你手动匹配参数
    models.ForeignKey(to='Publish')
    
    models.ForeignKey(to='Publish',on_delete=models.CASCADE,
on_update=models.CASCADE)

django2.0版的re_path与path,更多详细看下面链接

https://www.cnblogs.com/xiaoyuanqujing/articles/11642628.html
posted @ 2023-07-28 00:52  coder雪山  阅读(335)  评论(0编辑  收藏  举报