Python Web 开发及 Django 总结


title: Python Web 开发及 Django 总结

date: 2023-07-24 17:26:26

tags:


Python 基础部分见:Python 基础总结

1. 创建项目

1.1 命令行

1、下载安装 Django

在终端输入 pip install django,下载 Django。在 Python 的安装目录下存在如下两个目录

  • Lib
    • 包含一些内置模块
    • 以及 site-packages 文件夹:用于存放一些第三方模块
  • Scripts
    • pip.exe、pip3.exe 等,可以用来安装一些第三方模块

下载完 Django 后,会在 Lib\site-packages 目录下生成 django 文件夹,包含了 Django 的源码;除此之外,还会在 scripts 目录下生成一个 django-admin.exe 文件,用于创建 Django 项目中的文件和文件夹

2、创建项目

用上面的 django-admin.exe 工具来创建 Django 项目,django-admin startproject 项目名称

1.2 Pycharm

选择创建 Django 项目

1.3 区别

  • 命令行:创建的项目是标准的
  • Pycharm:在标准的基础上增加了一些东西
    • templates 目录,根目录下的模板目录(可删除)
    • settings.py'DIRS': [BASE_DIR / 'templates'],配置的是根目录下模板目录的路径,可将 DIRS 置为空 'DIRS': []

1.4 初始目录结构

  • 与项目名相同的包
    • __init__.py
    • asgi.py:接收网络请求,不需要动
    • settings.py:项目配置文件
    • urls.py:配置 URL 和 函数的对应关系
    • wsgi.py:接收网络请求,不需要动
  • templates:已删除
  • venv:虚拟环境
  • manage.py:用于项目的管理、启动项目、创建 app、数据管理等,不需要动

2. APP

一个 App 即一个独立的功能包,使用 manage.py 创建 app,python .\manage.py startapp app,初始目录结构如下

  • migrations:数据库变更记录,不需要动
    • __init__.py
  • templates:模板目录,后续可添加
  • static:静态文件目录,后续可添加
  • __init__.py
  • admin.py:Django 默认提供了 admin 后台管理,不需要动
  • apps.py:app 启动类,不需要动
  • models.py:对数据库进行操作
  • tests.py:单元测试,不需要动
  • views.py:与 URL 对应的函数

3. 基础使用

3.1 注册 App

添加 App 信息到 settings.py

python 复制代码
# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app.apps.AppConfig'
]

3.2 编写 URL 和视图函数

urls.py 文件里添加 url 信息,先注释掉默认示例,参照默认示例自定义一个 url,然后导入 app 的 views.py 文件,因为 url 对应的函数写在 app 的 views.py 文件里

python 复制代码
from django.contrib import admin
from django.urls import path

from app import views

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

views.py 文件里编写对应的函数

python 复制代码
from django.http import HttpResponse


def index(request):
    return HttpResponse('欢迎使用')

3.3 启动项目

  • 命令行启动,python ./manage.py runserver
  • Pycharm 启动,直接点启动按钮即可

项目启动后,访问项目的默认地址,http://127.0.0.1:8000/,可以看到列出了项目的 url

加上 url 再访问,http://127.0.0.1:8000/index,可以看到我们在函数里返回的信息

4. 模板和静态文件

4.1 模板渲染

在 app 中创建 templates 文件夹,注意是在 app 里创建,而不是 1.3 的顶层 templates 文件夹,然后创建 index.html 文件

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
欢迎
</body>
</html>

修改 views.py 文件的 index() 函数,将原本返回的 http 响应改为模板渲染,使用 render() 函数

python 复制代码
from django.shortcuts import render


def index(request):
    # return HttpResponse('欢迎使用')
    return render(request, 'index.html')

Pycharm 会自动更新修改,再访问 http://127.0.0.1:8000/index,显示的就是 index.html 文件的内容

这里的模板加载顺序为

  1. 优先去项目根目录的 templates 文件夹中寻找(即 1.3 的配置),不配置的话无效
  2. 第一点未配置的话,默认会根据 app 的注册顺序,依次在每个 app 下的 templates 目录中寻找

4.2 静态文件目录

默认的静态文件目录为 app 目录下的 static 目录,该项配置可在 settings.py 中修改,STATIC_URL = 'static/'

对应的静态文件相关目录结构为

  • static
    • CSS
    • img
    • js
    • plugins

对应的 HTML 文件中加载静态目录可以使用绝对路径,即写死文件的目录名,如 /static/img/1.jpg,缺点是假如修改了目录名或结构变化,对应的路径全都要修改;推荐使用相对路径(动态路径),如下

html 复制代码
{% load static %}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
欢迎
<img src="{% static 'img/1.jpg' %}">s
</body>
</html>

动态加载静态文件目录,这时会去读取 settings.py 文件配置的静态文件目录

4.3 模板语法

1、传参

修改 views.py 文件的视图函数,传入的参数格式为字典

python 复制代码
from django.shortcuts import render


def index(request):
    name = '张三'
    roles = ['管理员', '测试']
    user_info = {'name': '张三', 'age': 28}
    return render(request, 'index.html', {'n1': name, 'n2': roles, 'n3': user_info})

2、模板语法,由 Django 提供

  • render() 函数内部先会读取含有模板语法的 HTML 文件
  • 然后内部进行渲染,执行模板语法并替换数据,最终得到只包含 HTML 标签的字符串
  • 将渲染(替换)完成的字符串返回给用户浏览器
html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<p> 直接取值 </p>
<ul>
    <li> {{ n1 }} </li>
    <li> {{ n2 }} </li>
</ul>

<p> 取列表值 </p>
<ul>
    <li> {{ n2.0 }} </li>
    <li> {{ n2.1 }} </li>
</ul>

<p> 循环展示 </p>
<ul>
    {% for item in n2 %}
        <li> {{ item }} </li>
    {% endfor %}
</ul>

<ul>
    {% for k, v in n3.items %}
        <li> {{ k }} = {{ v }} </li>
    {% endfor %}
</ul>

<p> 条件 </p>
{% if n1 == 'xxx'%}
    <h1> V1 </h1>
{% elif n1 == 'xx' %}
    <h1> V2 </h1>
{% else %}
    <h1> V3 </h1>
{% endif %}
</body>
</html>

页面展示为

5. 请求与响应

1、请求

views.py 文件中视图函数如下,request 为封装了用户发送过来的所有请求相关数据的对象

python 复制代码
from django.http import HttpResponse
from django.shortcuts import redirect


def index(request):
    # 获取请求方式
    print(request.method)
    # 获取请求路径
    print(request.path)
    # 获取 URL 上传递的值
    print(request.GET)
    # 获取请求体中提交的数据
    print(request.POST)
    return redirect('https://www.baidu.com')

如浏览器请求:http://127.0.0.1:8000/index/?id=1

GET

/index/

<QueryDict: {'id': ['1']}>

<QueryDict: {}>

2、响应

响应分为三种

  • HttpResponse,直接返回响应数据
  • render,返回 HTML 页面
  • redirect,返回重定向地址

6. ORM

6.1 环境及配置

1、安装 mysqlclient,pip install mysqlclient

2、准备好对应的数据库环境,然后创建数据库,这里不多赘叙

3、Django 连接数据库,修改 settings.py 数据库配置,注释掉原有的数据库配置,添加新配置如下,可根据自己的数据库类型进行相应的改动

python 复制代码
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'fan-web',
        'USER': 'root',
        'PASSWORD': 'password',
        'HOST': '127.0.0.1',
        'PORT': '3306'
    }
}

6.2 数据库表操作

6.2.1 创建表

修改 modles.py 文件,添加数据库表对应的实体类

python 复制代码
from django.db import models


class Userinfo(models.Model):
    name = models.CharField(max_length=32)
    password = models.CharField(max_length=64)
    age = models.IntegerField()

依次执行如下命令,Django 会自动创建对应的数据库表,这里不需要加主键 ID,Django 会自动加

  • python .\manage.py makemigrations
  • python .\manage.py migrate

执行完成后,可以看到 Django 默认创建了一些表,而我们自定义的表也创建好了,并且自动加上了主键 ID

6.2.2 新增/删除表、删除表原有的字段

新增表直接在下面新加一个实体类即可,删除表则将对应的实体类删除,删除表原有的字段同样去掉实体类的字段即可

python 复制代码
from django.db import models


# class Userinfo(models.Model):
#     name = models.CharField(max_length=32)
#     password = models.CharField(max_length=64)
#     age = models.IntegerField()


class Role(models.Model):
    name = models.CharField(max_length=32)
    code = models.CharField(max_length=64)

然后执行前面的两行命令

  • python .\manage.py makemigrations
  • python .\manage.py migrate

6.2.3 给表添加字段

同样的给实体类加上字段后,执行 python .\manage.py makemigrations 命令时,会要求进行选择,在命令行给字段赋默认值;还是先退出,修改实体类加上默认值后,再来执行命令

1、这里先选择直接在命令行赋值,选择 1,接下来会要求你输入赋的默认值

输入后,再执行 python .\manage.py migrate

到表里看,新增的字段已经都赋了默认值

2、直接在实体类中赋默认值,或者设置成允许为空

python 复制代码
from django.db import models


class Userinfo(models.Model):
    name = models.CharField(max_length=32)
    password = models.CharField(max_length=64)
    age = models.IntegerField(default=2)
    data = models.IntegerField(null=True, blank=True)

6.2.4 修改表的字段

相当于先删除原有的字段,然后再新增一个字段,即同样需要赋默认值,操作与上同

6.3 数据库数据操作

6.3.1 添加数据

通过 modles.py 的实体类执行 create(key=value,...) 方法即可,Userinfo.objects.create(name='张三', password='123', age=18)

可以将其放到视图函数里,然后通过 url 来请求创建。在 views.py 文件里引入 modles.py,从而获取到实体类,执行其 create() 方法

python 复制代码
from django.http import HttpResponse

from app import models


def index(request):
    models.Userinfo.objects.create(name='张三', password='123', age=18)
    return HttpResponse('成功')

然后访问 http://127.0.0.1:8000/index/,则可看到数据库中添加了一条数据

6.3.2 获取数据

  • 获取全部数据:通过 modles.py 的实体类执行 all() 方法,models.Userinfo.objects.all(),获取到的数据是一个 QuerySet 类型
  • 条件获取:通过 modles.py 的实体类执行 filter() 方法,获取到的也是一个 QuerySet 类型
    • 不过通过主键 ID 来获取的话,主键 ID 是唯一的,这时肯定只有一行数据,可以加上 first() 方法来获取第一行数据,返回的是一个对象

其他的同上

python 复制代码
from django.http import HttpResponse

from app import models


def index(request):
    data_list = models.Userinfo.objects.all()
    print(data_list, type(data_list))

    for obj in data_list:
        print(obj.id, obj.name, obj.password, obj.age)

    filter_list = models.Userinfo.objects.filter(id=1)
    print(filter_list)

    obj = models.Userinfo.objects.filter(id=1).first()
    print(obj.id, obj.name, obj.password, obj.age)
    return HttpResponse('欢迎')

<QuerySet [<Userinfo: Userinfo object (1)>, <Userinfo: Userinfo object (2)>]> <class 'django.db.models.query.QuerySet'>

1 张三 123 1

2 李四 123 1

<QuerySet [<Userinfo: Userinfo object (1)>]>

1 张三 123 1

6.3.3 删除数据

即在获取数据的基础上加上 delete() 方法

  • 条件删除:条件获取数据后再执行 delete() 方法,models.Userinfo.objects.filter(id=4).delete()
  • 全部删除:获取全部数据后再执行 delete() 方法,models.Userinfo.objects.all().delete()

其他的同上

python 复制代码
from django.http import HttpResponse

from app import models


def index(request):
    models.Userinfo.objects.filter(id=4).delete()
    # models.Userinfo.objects.all().delete()
    return HttpResponse('成功')

6.3.4 修改数据

在获取数据的基础上执行 update(key=value,...) 方法,与删除数据类似

python 复制代码
from django.http import HttpResponse

from app import models


def index(request):
    models.Userinfo.objects.filter(id=4).update(age=18)
    # models.Userinfo.objects.all().update(age=15)
    return HttpResponse('成功')

7. 前后端分离

前后端之间通常采用 JSON 格式来传递数据,可以利用 Django 封装的 JsonResponse 向浏览器返回 JSON 格式的数据

需要注意的是,JSON 格式也是一种 key:value 格式,所以返回为字典时,不会有问题,假如不是字典,要加上 参数 safe=False,否则会报 TypeError 异常

1、GET 请求

发送请求,http://localhost:8000/index?current=1&size=5

python 复制代码
from django.http import JsonResponse


def index(request):
    print(request.GET)
    print(request.POST)
    # return JsonResponse({'message': '返回成功'})
    return JsonResponse('返回成功', safe=False)

<QueryDict: {'current': ['1'], 'size': ['5']}>

<QueryDict: {}>

2、POST 请求

为了防止跨站请求伪造(CSRF),Django 全局发送 POST 请求均需要字符串验证,否则会报 Forbidden (CSRF cookie not set.)

解决方案如下

  • 注释 settings.py 文件中的 'django.middleware.csrf.CsrfViewMiddleware',
  • 在单个视图函数上加上 @csrf_exempt,需要引入 from django.views.decorators.csrf import csrf_exempt

发送请求,http://localhost:8000/index/,需要注意的是,POST 请求结尾要加上 /,并且 JSON 格式的数据会解析到 request.body 里,而非 request.POST

由于传递过来的数据为 bytes 类型数据,因此需要用 Python 提供的 json 库的 loads() 方法来加载数据,得到的是一个对象

python 复制代码
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
import json


@csrf_exempt
def index(request):
    print(request.GET)
    print(request.POST)

    json_data = json.loads(request.body)
    print(json_data)
    print(json_data.get('data')[0].get('name'))

    # return JsonResponse('返回成功', safe=False)
    return JsonResponse({'message': '返回成功'})

<QueryDict: {}>

<QueryDict: {}>

{'id': '1100', 'data': [{'name': '张三', 'age': 19, 'address': '上海', 'gender': '男'}]}

张三

相关推荐
哎呦你好几秒前
CSS 盒子模型:一文了解padding和margin,使用内边距、外边距和边框随心所欲实现布局!
前端·css
yj15582 分钟前
前置过滤器和净水机安哪个?
python
前端 贾公子10 分钟前
小程序使用web-view 修改顶部标题 && 安全认证文件部署在nginx
开发语言·前端·javascript
流星蝴蝶没有剑17 分钟前
Python 电脑桌面——工作量监控大屏
开发语言·python
悟能不能悟33 分钟前
使用中文作为map的可以,需要注意什么
开发语言·python
胖墩会武术1 小时前
通过Auto平台与VScode搭建远程开发环境(以Stable Diffusion Web UI为例)
前端·vscode·stable diffusion
人猿泰飞1 小时前
【大模型应用开发】Qwen2.5-VL-3B识别视频
python·大模型·qwen·视觉模型·ai应用开发
尼恩久2 小时前
记录python在excel中添加一列新的列
windows·python·excel
未来之窗软件服务2 小时前
封装拍照模块,拓展功能边界—仙盟创梦IDE
前端·javascript·html·摄像头·仙盟创梦ide
Dxy12393102162 小时前
Python经典算法实战
开发语言·python·算法