首页 > 其他分享 >速通 Django

速通 Django

时间:2023-07-27 21:13:11浏览次数:43  
标签:速通 models py request Django user django name

0x01 入门

(1)简介

  • 官方网站链接
  • Django 是一个开放源代码的Web应用框架,由Python写成
  • Django 采用 MTV 的框架模式,即模型 M,视图 V 和模版 T

(2)安装

a. 创建虚拟环境

  • 安装 virtualenv:pip install virtualenv virtualenvwrapper-win
  • 查看虚拟环境:workon
  • 创建新的虚拟环境 env:mkvirtualenv env
  • 进入虚拟环境 env:workon env
  • 删除虚拟环境 env:rmvirtualenv env

b. 安装 Django

  • 安装 Django:pip install django=4.2 -i
  • 查看安装结果:pip show django

也可以在 Pycharm 新建 Django 项目时自动安装 Django

(3)创建项目

  • 方法一:在 cmd 中使用命令 django-admin startproject Projectname
  • 方法二:在 Pycharm 中创建 Django 项目

(4)项目目录与配置文件

a. 项目目录

  • manage.py:管理项目的命令行工具,进行站点运行以及数据库自动生成都通过本文件
  • ProjectName
    • __ init__.py:用于工具初始化
    • asgi.py:Python 异步服务器网关接口
    • settings.py:项目配置文件,定义了项目引用的组件、项目名、数据库、静态资源等
    • urls.py:维护项目的 URL 路由映射
    • wsgi.py:Python 服务器网关接口

b. 配置文件

  • settings.py

    # 项目根目录
    BASE_DIR = Path(__file__).resolve().parent.parent
    
    # 加密解密的密钥
    SECRET_KEY = 'django-insecure-xxxxxx'
    
    # 是否开启调试模式
    DEBUG = True
    
    # 被允许的域名、IP
    ALLOWED_HOSTS = []
    
    # 插入自定义引用名称
    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        ...
    ]
    
    # 中间件
    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        ...
    ]
    
    # 根路由文件
    ROOT_URLCONF = 'djangoProject.urls'
    
    # 模板
    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [],
            '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',
                ],
            },
        },
    ]
    
    # WSGI 目录
    WSGI_APPLICATION = 'djangoProject.wsgi.application'
    
    
    # 数据库
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': BASE_DIR / 'db.sqlite3',
        }
    }
    
    # 密码验证
    AUTH_PASSWORD_VALIDATORS = [
        {
            'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
        },
        ...
    ]
    
    # 国际化信息配置
    LANGUAGE_CODE = 'en-us'
    TIME_ZONE = 'UTC'
    USE_I18N = True
    USE_TZ = True
    
    # 静态资源目录
    STATIC_URL = 'static/'
    
    # 默认主键字段类型
    DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
    

(5)运行项目

  • 设置 settings.py 中 ALLOWED_HOSTS = ['*']
  • 使用命令 python manage.py runserver [IP Address]:[Port]

(6)数据迁移

  • 迁移就是将模型映射到数据库的过程
  • 使用命令 python manage.py makemigrations 生成迁移文件
  • 使用命令 python manage.py migrate 执行迁移

不需要初始化迁移文件夹,每个应用默认有迁移文件夹 migrations

(7)创建应用 App

  • 使用命令 python manager.py startapp App 创建名为 App 的应用
  • 使用应用前需要将应用配置到 settings.py 的 INSTALLED_APPS
  • 应用目录:
    • migrations 包:生成迁移文件
    • __ init__.py:初始化包,暂空
    • admin.py:管理站点模型的声明文件,默认空
    • apps.py:应用信息定义文件
    • models.py:添加模型层数据类文件
    • tests.py:代码测试文件
    • views.py:定义 URL 相应函数

(8)HTTP 前后端交互

graph TB A(服务器端 Server)--响应 Response-->B(客户端 Client) B--请求 Request-->A

(9)Django 框架流程

graph LR 浏览器-->A(后端) A-->B(路由 urls) -->C(视图 views) --增删改查-->D(模型 models) D-->C C--模板渲染-->E(模板 Templates) -->浏览器 D--ORM-->F(数据库 MySQL) -->D

(10)视图函数基本使用

  • 在 views.py 中建立一个路由响应函数

    from django.http import HttpResponse
    
    def hello(request):
        return HttpResponse('Hello')
    
  • 在 urls.py 中注册

    from App.views import *
    
    urlpatterns = [
        path('hello/', hello)
    ]
    
  • 启动项目并访问 127.0.0.1:8000/hello

(11)路由基本使用

  • 子路由 App/urls.py

    from django.urls import path
    from App.views import *
    
    urlpatterns = [
        path('/hello', hello)
    ]
    
  • 根路由 urls.py

    from django.urls import path, include
    
    urlpatterns = [
        path('app/', include('App.urls')),
    ]
    
  • 启动项目并访问 127.0.0.1:8000/app/hello

(12)模板基本使用

  • 模板是 HTML 写好的页面
  • 创建模板文件夹 templates,并在其中创建模板文件
  • 在 views.py 中通过 return render(request, 'xxx.html') 来加载并渲染模板

(13)模型基本使用

  • 在 models.py 中引入 models:from django.db import models

  • 创建继承于 models.Model 的自定义模型类:如用户类

    class User(models.Model):
        name = models.CharField(max_length=30)  # 对应 SQL 的 name varchar(30)
        age = models.IntegerField(20)  # 对应 SQL 的 age int default 20
    
  • 模型 models 表结构一旦改变就需要进行数据迁移

  • 使用模型

    • views.py

      from App.models import *
      
      def get_users(request):
          users = UserModel.objects.all()
          return render(request, 'users.html', {'users': users})
      
    • users.html

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>Title</title>
      </head>
      <body>
          <ul>
              {% for user in users %}
                  <li>{{ user.name }}, {{ user.age }}</li>
              {% endfor %}
          </ul>
      </body>
      </html>
      

(14)后台管理基本使用

  • 在 admin.py 中将 model 加入后台管理:admin.site.register(Grade)
  • 创建超级用户:python manage.py createsuperuser
  • 访问 admin 后台:127.0.0.1:8000/admin

0x02 路由

(1)简介

  • 在项目开发过程中,通常在每个应用中创建各自的 urls.py 路由模块
  • 路由的分发:从根路由出发,将每个应用所属的 url 请求转发到各自的路由模块中的过程

(2)创建用户模型

  • models.py

    class UserModel(models.Model):
        name = models.CharField(max_length=30)
        age = models.PositiveIntegerField()  # 非负数
    
  • 数据迁移

    python manage.py makemigrations
    python manage.py migrate
    
  • 与数据库连接

    • 新建 SQLite 数据源
    • 常规 -> 文件:打开项目根目录下的 db.sqlite3
    • 确认已配置相关数据库驱动即可完成连接

(3)添加子路由

  • 添加模板:App/templates/index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>首页</title>
    </head>
    <body>
        <h2>首页</h2>
        <hr />
    
    </body>
    </html>
    
  • 添加视图:views.py

    from django.shortcuts import render
    
    def index(request):
        return render(request, 'index.html')
    
  • 根路由:urls.py

    from django.urls import path, include
    
    urlpatterns = [
        path('user/', include('App.urls'))
    ]
    
  • 子路由:App/urls.py

    from django.urls import path
    from App.views import *
    
    urlpatterns = [
        path('index/', index)
    ]
    
  • 启动项目并访问 http://127.0.0.1:8000/user/index/

(4)反向解析和命名空间

a. 基本概念

  • 反向解析:使用路由别名替代 URL 路径,避免在修改 URL 时产生硬编码依赖

  • 命名空间:一种将路由命名为层次结构的方式,使得查询路由时可以限定在该命名空间内,防止路由冲突

b. 项目应用-页面跳转

  • 添加模板:App/templates/user_list.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>用户列表</title>
    </head>
    <body>
        <h2>用户列表</h2>
        <hr />
    </body>
    </html>
    
  • 修改视图:views.py

    def user_list(request):
        return render(request, 'user_list.html')
    
  • 修改子路由:App/urls.py

    path('userList/', user_list, name='userListName')
    
  • 修改模板:App/templates/index.html

    <a href="/user/userList/">URL 路由方式</a>
    <hr />
    <a href="{% url 'userListName' %}">反向解析方式</a>
    <hr />
    <a href="{% url 'App:userListName' %}">使用命名空间的反向解析方式</a>
    
    • 使用命名空间的反向解析方式前需要修改根路由:urls.py

      path('user/', include(('App.urls', 'App'), namespace='App'))
      
    • “反向解析方式”和“使用命名空间的反向解析方式”不能同时作用于同一个页面

(5)路由传参

a. 单个参数

  • 添加模板:App/templates/user_detail.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>用户详情</title>
    </head>
    <body>
        <h2>用户详情</h2>
        <hr />
        <h3>{{ user.name }} 的年龄是 {{ user.age }}</h3>
    </body>
    </html>
    
  • 修改视图:views.py

    from App.models import *
    
    def user_list(request):
        users = UserModel.objects.all()
        return render(request, 'user_list.html', {'users': users})
    
    def user_detail(request, uid):
        user = UserModel.objects.get(pk=uid)
        return render(request, 'user_detail.html', {'user': user})
    
  • 修改子路由:App/urls.py

    path('userDetail/<int:uid>/', user_detail, name='userDetailName')
    
  • 修改模板:App/templates/user_list.html

    <ul>
        {% for user in users %}
        <li>
            <a href="{% url 'App:userDetailName' user.id %}">
                {{ user.name }}
            </a>
        </li>
        {% endfor %}
    </ul>
    

b. 多个参数

  • 修改视图:views.py

    def user_ab(request, a, b):
        return HttpResponse(f"{a} - {b}")
    
  • 修改子路由:App/urls.py

    path('userAB/<int:a>/<int:b>', user_ab, name='userABName')
    
  • 启动项目并访问 http://127.0.0.1:8000/user/userAB/1/2

(6)重定向 Redirect

  • 修改子路由:App/urls.py

    path('redirect/', my_redirect)
    
  • 修改视图:views.py

    • 重定向到指定链接

      def my_redirect(request):
          return redirect('https://www.baidu.com')
      
    • 重定向并反向解析传值

      • 依序传值

        def my_redirect(request):
            return redirect(reverse('App:userDetailName', args=(2,)))
        
      • 对象传值

        def my_redirect(request):
            return redirect(reverse('App:userDetailName', kwargs={'uid': 2}))
        

0x03 模板

(1)简介

  • 模板用于帮助开发者快速呈现给用户页面的工具
  • 模板处理分为两个过程:加载 HTML、渲染数据
  • 模板主要有两个部分:HTMl 静态代码、模板语言和动态代码段
    • 动态代码段可以做基本的静态填充和运算、转换、逻辑
  • 页面可以按页面数据来源进行分类
    • 静态页面:数据来源于本地固定数据
    • 动态页面:数据来源于后台服务器

(2)动态代码段

a. 变量

  • 模板中的变量是视图传递给模板的,遵守标识符规则
  • 一般变量的语法:{{ var }}
    • 如果变量不存在,则插入空字符串
  • 当变量是方法时,不能有参数
  • 当变量是列表时,使用正索引
    • python 中:items = ["a", "b", "c"]
    • HTML 中:{{ items.1 }}

b. 标签

  • 模板中的标签语法:{% tag %}
  • 作用:
    • 加载外部传入的变量
    • 在输出中创建文本
    • 控制循环或逻辑

c. 注释

  • 单行注释

    {# 注释 #}
    
  • 多行注释

    {% comment %}
    	注释1
    	注释2
    {% endcomment %}
    

(3)if 语句

a. 格式

  • 单分支

    {% if 表达式 %}
    	语句
    {% endif %}
    
  • 双分支

    {% if 表达式 %}
    	语句
    {% else %}
    	语句
    {% endif %}
    
  • 多分支

    {% if 表达式 %}
    	语句
    {% else if %}
    	语句
    {% else %}
    	语句
    {% endif %}
    

b. 举例

  • 无逻辑条件判断

    {% if isDelete %}
    	<h2>Boolean</h2>
    {% endif %}
    
  • 与或非判断

    {% if a and b %}
    	<p>and</p>
    {% else if a or b %}
    	<p>or</p>
    {% else if not a %}
    	<p>not</p>
    {% endif %}
    
  • 成员判断

    {% if "a" in "bcd" %}
    	<p>bcd</p>
    {% else if "a" not in "efg" %}
    	<p>a</p>
    {% endif %}
    

(4)for 语句

  • 一般格式:

    {% for 变量 in 列表 %}
    	语句1
    {% empty %}
    	语句2
    {% endfor %}
    
    • 当列表为空或不存在时,执行 empty 语句
  • forloop

    {% for 变量 in 列表 %}
    	<p>{{ forloop.counter }}</p>
    {% endfor %}
    
    • {{ forloop.counter }}:表示当前是第几次循环,从 1 开始
    • {{ forloop.counter0 }}:表示当前是第几次循环,从 0 开始
    • {{ forloop.revcounter }}:表示当前是第几次循环,倒序数,至 1 停
    • {{ forloop.revcounter0 }}:表示当前是第几次循环,倒序数,至 0 停
    • {{ forloop.first }}:表示是否是第一个元素,返回布尔值
    • {{ forloop.last }}:表示是否是最后一个元素,返回布尔值

(5)过滤器

  • 一般过滤器格式:{{ var | 过滤器 }}

    • 作用:在变量显示前修改
  • 加法过滤器:`{{ value | add:2 }}

  • 大写过滤器:{{ name | upper }}

    • 首字母大写:{{ name | first | upper }}
    • 尾字母大写:{{ name | last | upper }}
  • 小写过滤器:{{ name | lower }}

  • 截断过滤器:{{ name | truncatechars: 30 }}

  • 连接过滤器:{{ name | join: '=' }}

  • 默认过滤器:{{ var | default: value }}

  • 日期过滤器:{{ day | date: 'y-m-d' }}

  • 转义过滤器:{{ code | safe }}

    • 打开/关闭自动转义

      {% autoescape on/off %}
      	语句
      {% endautoescape %}
      

(6)继承

  • block:

    {% block XXX %}
    	语句
    {% endblock %}
    
    • XXX 为该 block 的名称
  • extends:继承

    {% extends '父模块路径' %}
    
  • include:加载模板进行渲染

    {% include '模板文件' %}
    
  • {{ block.super }}:获取父模版中 block 中的内容

  • 举例:

    • 父模板:block.html

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>Title</title>
      </head>
      <body>
          <h2>父模版</h2>
          <hr />
      
          {% block head %}
              <div>
                  <button>Head</button>
              </div>
          {% endblock %}
      </body>
      </html>
      
    • 其他模板:other.html

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>Title</title>
      </head>
      <body>
          <h2>其他模板</h2>
          <hr />
      </body>
      </html>
      
    • 子模版:child.html

      {# 继承父模版 #}
      {% extends 'block.html' %}
      
      {% block head %}
          <div>
              <button>head</button>
          </div>
          
          {# 保留父模版内容 #}
          {{ block.super }}
      
          {# 导入其他模板 #}
          {% include 'other.html' %}
      {% endblock %}
      

(7)Jinja2 模板引擎

a. 简介

  • Jinja2 是一个模板引擎,在 Flask 中也有应用
  • Jinja2 基于 Django 默认模板引擎开发,性能更好,功能更全

b. 安装与配置

  • 使用命令 pip install jinja2 安装

  • 在 settings.py 同目录下新建 jinja2_env.py 文件配置 Jinja2

    from django.templates.static import static
    from django.urls import reverse
    from jinja2 import Environment
    
    def environment(**options):
        env = Environment(**options)
        env.globals.update({
            'static': static,
            'url': reverse
        })
        return env
    
  • 在 settings.py 中配置 Jinja2 模板引擎

    TEMPLATES = [
        # 新增 Jinja2 模板引擎
        {
            'BACKEND': 'django.template.backends.jinja2.Jinja2',
            'DIRS': [],
            'APP_DIRS': True,
            'OPTIONS': {
                'environment': 'DjangoPro2.jinja2_env.environment',
                'context_processors': [
                    'django.template.context_processors.debug',
                    'django.template.context_processors.request',
                    'django.contrib.auth.context_processors.auth',
                    'django.contrib.messages.context_processors.messages',
                ],
            },
        },
        
        # 原 Django 引擎模板
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [],
            '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',
                ],
            },
        },
    ]
    
  • 在设置中修改模板语言为 Jinja2

c. 使用

  • Jinja2 可以使用函数调用

    {% for i in range(1, 4) %}
    	<h3>{{ i }}</h3>
    {% endfor %}
    
  • 循环下标读取方法改变

    {% for i in range(1, 4) %}
    	<h3>{{ loop.index }}</h3>
    {% endfor %}
    
  • ……

0x04 模型基础

(1)简介

  • Django 根据属性的类型确认以下信息

    • 当前选择的数据库支持字段的类型
    • 渲染管理表单时使用的默认 HTML 控件
    • 在管理站点最低限度的验证
  • Django 会为表增加自动增长的主键列,当设置过主键列后,默认主键列不会生成

  • 属性名遵循标识符命名规则,但由于 Django 的查询方式,不允许使用连续的下划线

    • 定义属性时需要设置字段类型
  • 使用模型:

    • 导入模型:from django.db import models
    • 通过 models.Field 创建字段类型的对象并赋值给属性
  • 逻辑删除和物理删除

    • 对于重要数据仅作逻辑删除

      • 实现方法:设置 is_delete 属性为 False
      is_delete = models.BooleanField(default=False)
      
  • 基本操作

    • Django 自动生成与模型相应的 SQL 语句并执行

    • Django 使用对象关系映射框架操控数据库

      • 对象关系映射(Object Relational Mapping,简称 ORM):一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换

      • ORM 关系:

        graph LR 模型-->表 -->模型 类对象-->表结构 对象-->表的一条数据 类属性-->表的字段

(2)字段类型

a. 常用字段类型

  • AutoField:根据实际 ID 自动增长的 IntegerField,通常不指定
  • CharField(max_length=字符长度):字符串,默认表单控件为 Input
  • TextField:文本字段,默认表单控件为 Textarea
  • IntegerField:整数
  • DecimalField(max_digits=None, decimal_places=None):使用 Python 的 Decimal 实例表示十进制浮点数
    • max_digits:位数总数
    • decimal_places:小数点后的位数
  • FloatField:使用 Python 的 float 实例表示浮点数
  • BooleanField:布尔值,默认表单控件为 CheckboxInput
  • DateField([auto_now=None, auto_now_add=False]):使用 Python 的 datetime.date 实例表示日期
    • auto_now:保存对象时设置为当前时间时间戳,一般用于表示最后一次修改的时间
    • auto_now_add:保存对象创建的时间戳
  • TimeField:使用 Python 的 datetime.time 实例表示时间,参数同 DateField
  • DateTimeField:使用 Python 的 datetime.datetime 实例表示日期和时间,参数同 DateField
  • FileField:上传文件的字段
  • ImageField:继承自 FileField,但会对文件进行校验
    • 需要安装 Pillow:pip install Pillow

b. 常用字段参数

  • null=True:数据库字段是否可以为空

  • blank=True:Django 的 Admin 中添加数据时是否可以为空

  • primary_key=True:设置主键

  • auto_nowauto_now_add:详见 DateField 中的说明

  • choices:设置 Admin 下拉菜单

    • 举例:设置用户类型下拉菜单

      USER_TYPE_LIST = (
          (1, '一般用户'),
          (2, 'Vip 客户'),
          (3, '超级用户')
      )
      user_type = models.IntegerField(choices=USER_TYPE_LIST, default=1, verbose_name='用户类型')
      
  • max_length:最大长度

  • default:默认值

  • verbose_name:Admin 中字段的显示名称

  • name|db_column:数据库中字段的名称

  • unique=True:是否不允许重复

  • db_index=True:数据库索引

  • editable=True:是否允许 Admin 编辑,否则不显示

  • 设置表名

    class Meta:
        db_table = 'person'
    

(3)单表操作

a. 增加数据

  • 方法一:创建对象实例并调用 save 方法

    obj = Author()
    obj.first_name = 'zhang'
    obj.last_name = 'san'
    obj.save()
    
  • 方法二:创建对象并初始化后调用 save 方法

    obj = Author(first_name='zhang', last_name='san')
    obj.save()
    
  • 方法三:调用 create 方法

    Author.objects.create(first_name='zhang', last_name='san')
    
    • 调用 get_or_create 方法防止重复创建

      Author.objects.get_or_create(first_name='zhang', last_name='san')
      

b. 删除数据

  • 方法一:使用 Queryset 的 delete 方法

    • 删除指定条件的数据

      Author.objects.filter(first_name='zhang').delete()
      
    • 删除所有数据

      Author.objects.all().delete()
      
  • 方法二:使用模型对象的 delete 方法

    obj = Author.objects.get(id=1)
    obj.delete()
    

c. 修改数据

  • 方法一:使用模型对象的 update 方法

    Author.objects.filter(last_name='san').update(last_name='si')
    
  • 方法二:重新赋值后使用 save 方法保存

    obj = Author.objects.get(id=1)
    obj.first_name = 'li'
    obj.save()
    
    • 如果只更新某个字段,则使用以下方法

      obj = Author.objects.get(id=1)
      obj.first_name = 'li'
      obj.save(update_fields=['first_name'])
      

d. 查找数据

I. 基础查询

  • get():获取单条数据,如 get(id=1)
    • 如果没有符合的结果:DoesNotExist 异常
    • 如果有多个符合的结果:MultipleObjectsReturned 异常
  • first():返回查询集中的第一个对象
  • last():返回查询集最后一个对象
  • count():返回查询集中对象的个数
  • exists():判断查询集中是否有数据
  • all():获取全部数据
  • values():获取指定列的值,可传多个参数,返回形式是字典
  • values_list():获取指定列的值,可传多个参数,返回形式是元组

II. 条件过滤

  • filter(id__gt=2):获取 id 大于 2 的值
  • filter(id__gte=2):获取 id 大于等于 2 的值
  • filter(id__lt=2):获取 id 小于 2 的值
  • filter(id__lte=2):获取 id 小于等于 2 的值
  • filter(id__lt=4, id__gt=2):获取 id 大于 2 且 小于 4 的值
  • filter(id__in=[1, 2, 4]):获取 id 在 [1, 2, 4] 之间的值
  • exclude(id__in=[1, 2, 4]):获取 id 不在 [1, 2, 4] 之间的值
  • filter(age__range=[10, 20]):获取整数 age 在 10~20 之间的值
  • filter(name__contains="van"):获取 name 中含 van 的值
  • filter(name__icontains="van"):获取 name 中含 van 的值(大小写不敏感)
  • filter(name__regex="van"):正则匹配
  • filter(name__iregex="van"):正则匹配(大小写不敏感)

III. 排序

  • filter(name='zhangsan').order_by('id'):升序排序
  • filter(name='zhangsan').order_by('-id'):降序排序
    • 按年龄排序,相同则按 id 排序:filter(name='zhangsan').order_by('age', 'id')

IV. 聚合

  • aggregate(Max('age')):最大值
  • aggregate(Min('age')):最小值
  • aggregate(Sum('age')):求和
  • aggregate(Avg('age')):平均值
  • aggregate(Count('age')):计数

(4)手动分页

  • all()[10:20]:切片,取所有数据的 10 条到 20 条,下标从 0 开始,不为负

  • 在 views.py 中通过切片进行分页

    def paginate(request, page=1):
        per_page = 10
        items = Model.objects.all()[(page-1) * per_page : page * per_page]
        total = Model.objects.count()
        total_page = math.ceil(total / 10)
        pages = range(1, total_page+1)
        return render(request, 'paginate.html', {'items': items, 'pages': pages})
    
  • 添加子路由

    path('paginate/<int:page>', paginate)
    
  • 网页中添加按钮访问指定页

    <ul>
        {% for page in pages %}
        <li><a href="{% url 'paginate' page %}"><button>{{ page }}</button></a></li>
        {% endfor %}
    </ul>
    

(5)分页器

  • Django 中有自动分页器

  • views.py

    from django.core.paginator import Paginator
    
    def paginate(request, page=1):
        per_page = 10
        datas = Model.objects.all()
        
        # 分页器
        paginator = Paginator(datas, per_page)
        # 获取第 page 页的数据
        items = paginator.page(page)
        # 获取页码范围
        pages = paginator.page_range
        
        return render(request, 'paginate.html', {'items': items, 'pages': pages})
    

0x05 模型进阶

(1)配置 MySQL 数据库

  • 安装 MySQL

  • 安装 MySQL 驱动:pip install mysqlclient

  • 在 Django 中配置和使用 MySQL

    • settings.py

      DATABASES = {
          'default': {
              'ENGINE': 'django.db.backends.mysql',
              'NAME': 'django',
              'USER': 'root',
              'PASSWORD': 'password',
              'HOST': '127.0.0.1',
              'PORT': '3306'
          }
      }
      

(2)多表关系

  • OneToOneField:一对一(学号对学生),将字段定义在任意一端
  • ForeignKey:一对多(班级对学生),将字段定义在“多”的一端
  • ManyToManyField:多对多(老师对学生),将字段定义在任意一端

(3)一对多关系

  • 举例:一个班级有多个学生,一个学生只属于一个班级

    class Grade(models.Model):
        name = models.CharField(max_length=20)
    class Student(models.Model):
        name = models.CharField(max_length=20)
        grade = models.ForeignKey(Grade)
    
  • 对象的使用

    • 正向,Student 视角,包含外键
      • 获取学生所在班级(对象):student.grade
      • 获取学生所在班级名称:student.grade.name
    • 反向,Grade 视角,不包含外键
      • 获取班级所有学生(Manager 对象):grade.student_set
      • 获取班级所有学生(QuerySet 查询集):grade.student_set.all()

a. 增加数据

I. 正向

  • 方法一:创建对象实例并使用 save 方法

    obj = Student(name='zhangsan', grade_id=1)
    obj.save()
    
  • 方法二:对象初始化后使用 create 方法

    Student.objects.create(name='zhangsan', grade_id=1)
    
    • 使用 get_or_create 方法防止重复创建

      Student.objects.get_or_create(name='zhangsan', grade_id=1)
      
    • 使用字典

      dic = {'name': 'zhangsan', 'grade_id': 1}
      Student.objects.create(**dic)
      
    • 使用对象

      grade = Grade.objects.get(id=1)
      Student.objects.get_or_create(name='zhangsan', grade=grade)
      

II. 反向

  • 同正向增加数据操作

b. 删除数据

I. 正向

  • 一般操作:Student.objects.filter(id=1).delete()

II. 反向

  • 删除操作可以在定义外键时,通过 on_delete 参数来配置
    • models.CASCADE:默认值,级联删除
    • models.PROJECT:保护模式,组织级联删除
    • models.SET_NULL:置空模式,null=True 参数必备
    • models.SET_DEFAULT:置默认值,default 参数必备
    • models.SET():删除时重新动态指定一个实体访问元素
    • models.DO_NOTHING:无操作

c. 修改数据

I. 正向

  • 一般操作:Student.objects.filter(id=1).delete(grade_id=2)

II. 反向

  • 同正向修改数据操作

d. 查询数据

I. 正向

  • 一般操作

    students = Student.objects.filter(name='zhangsan')
    grade = students[0].grade_id.name
    

II. 反向

  • 同正向查询数据操作

  • 可以在定义外键时,通过指定 related_name 参数来配置

    grade = models.ForeignKey('Grade', related_name="info")
    
    obj,info.all()
    
  • 可以通过 Student 提供的信息查看

    obj = Student.objects.get(grade__name)
    

(4)多对多关系

  • 对于多对多关系,Django 会自动创建第三张表,也可以通过 through 参数指定

  • 举例:用户与小组

    class Group(models.Model):
        name = models.CharField(max_length=20)
        
        def __str__(self):
            return self.name
    
    class User(models.Model):
        name = models.CharField(max_length=20)
        groups = models.ManyToManyField(Group)
        
        def __str__(self):
            return self.name
    

a. 增加数据

  • 分别创建 user 和 group

    user = User(name='zhangsan')
    user.save()
    group = Group(name="zuiyi")
    g.save()
    
  • 通过 Manager 对象使用 add() 方法

    user.groups.add(group)
    # 或者
    group,user_set.add(user)
    

b. 删除数据与修改数据

  • 同一对多类似

c. 查询数据

I. 正向

  • 查询 id 为 1 的用户所在的所有组

    user = User.objects.get(id=1)
    user.groups.all()
    

II. 反向

  • 查询 id 为 1 的组中包含的用户

    group = Group.objects.get(id=1)
    group.user_set.all()
    

(5)一对一关系

  • 一对一关系是 Django 独有的一个连表操作,是特殊的一对多关系,相当于加了 unique=True

  • 举例:身份证号和人

    class IdCard(models.Model):
        num = models.IntegerField()
        
        def __str__(self):
            return str(self.num)
    
    class Person(models.Model):
        idcard = models.OneToOneField(IdCard)
        name = models.CharField(max_length=20)
        
        def __str__(self):
            return self.name
    

0x06 视图

(1)简介

  • Django 中的视图主要用来接受 Web 的请求并作出响应

  • 视图的本质是 Python 中的函数

  • 视图的响应分为两大类:

    • 以 JSON 数据形式返回(JsonResponse)
    • 以网页的形式返回
      • 重定向到另一个网页(HttpResponseRedirect)
      • 错误视图(HttpResponseNotFound/HttpResponseForbidden/HttpResponseNotAllowed)
  • 视图响应过程:

    graph LR 浏览器输入-->A(URLs 路由匹配) -->视图响应 -->回馈到浏览器
  • 视图参数

    • HttpRequest 的实例
    • 通过 URL 正则表达式传参
  • 位置:通常在应用下的 views.py 中定义

(2)HttpRequest 请求对象

  • Django 框架接收到 http 请求后会将 http 请求包装为 HttpRequest 对象并传递给视图

  • 常用属性与方法

    • 属性
      • path:请求的完整路径
      • method:请求的方法,如 GET、POST 等
      • GET/POST:类似字典,包含了 GET/POST 的所有参数
      • FILES:类似字典,包含了上传的文件
      • COOKIES:字典,包含了所有 COOKIE
      • session:类似字典,表示会话
    • 方法
      • is_ajax():判断是否是 Ajax
      • get_full_path():返回包含参数字符串的请求路径
  • QueryDict:类字典对象,与字典区别在于可以有相同的键

    • 获取数据

      dict['name']dict.get('name')

    • 获取指定键对应的所有值

      dict.getlist('name')

(3)HttpResponse 响应对象

  • 服务器返回给客户端的数据,HttpResponse 由开发者自行创建

    • 方法一:不使用模板,直接调用 HttpResponse(),返回 HttpResponse 对象
    • 方法二:使用模板进行渲染
      • 使用 render:render(request, template_name[, context])
        • request:请求体对象
        • template_name:模板路径
        • context:字典参数
  • 常用属性与方法

    • 属性
      • content:返回的内容
      • charset:编码格式
      • status_code:响应状态码
    • 方法
      • write(xxx):写出文本
      • flush():冲刷缓冲区
      • set_cookie(key, vale='xxx', max_age=None):设置 Cookie
      • delete_cookie(key):删除 Cookie
  • 子类

    • HttpResponseRedirect

      • 响应重定向,可以实现服务器内部跳转
      • 使用时一般需要反向解析
      return HttpResponseRedircet('/page/1')
      
    • JsonResponse

      • 返回 JSON 数据的请求,一般用于异步请求上
      • 返回 JSON 数据时 Content-typeapplication/json
      JsonResponse(dict)
      

0x07 会话技术

(1)Cookie 简介

  • Cookie实际上是一小段的文本信息

    • 客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie
    • 客户端浏览器会把Cookie保存起来,当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器
    • 服务器检查该Cookie,以此来辨认用户状态
      • 服务器还可以根据需要修改Cookie的内容
  • Cookie 本身由服务器生成,通过 Response 将 Cookie 写到浏览器上,当再次访问时浏览器会根据不同的规则携带 Cookie

    • Cookie 既不能跨浏览器,也不能跨域
  • 通过 response 设置 Cookie:response.set_cookie(key, value[, max_age=None, expires=None])

    • max_age:整数,单位为秒,指定 Cookie 过期时间,默认值为None,表示关闭

    • expires:指定过期时间,支持 datetime 或 timedelta,可以指定一个具体日期和时间

      expires=datetime.datetime(2000, 1, 1, 0, 0, 0)
      # or
      expires=datetime.datetime.now()+datetime.timedelta(days=10)
      
  • 通过 request 获取 Cookie:request.COOKIES.get('username')

  • 通过 response 删除 Cookie:response.delete_cookie('username')

  • Cookie 存储于客户端

    • 优点:减轻服务器压力,提高网站性能
    • 缺点:安全性不高

(2)创建模型与模板

  • models.py

    class UserModel(models.Model):
        username = models.CharField(max_length=30, unique=True)
        password = models.CharField(max_length=225)
        age = models.IntegerField(default=20)
    
  • templates

    • index.html

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>首页</title>
      </head>
      <body>
      <a href="{% url 'login' %}">登录</a>
      <a href="{% url 'register' %}">注册</a>
      </body>
      </html>
      
    • register.html

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>注册</title>
      </head>
      <body>
      </body>
      </html>
      
    • login.html

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>登录</title>
      </head>
      <body>
      </body>
      </html>
      
  • views.py

    from django.shortcuts import render
    
    def index(request):
        return render(request, 'index.html')
    
    def register(request):
        return render(request, 'register.html')
    
    def login(request):
        return render(request, 'login.html')
    
  • urls.py

    from django.urls import path, include
    
    urlpatterns = [
        path('user/', include('App.urls'))
    ]
    
  • App/urls.py

    from django.urls import path
    from App.views import *
    
    urlpatterns = [
        path('index/', index, name='index'),
        path('register/', register, name='register'),
        path('login/', login, name='login'),
    ]
    

(3)实现用户注册

  • 修改 register.html

    <body>
    <form method="post" action="">
        <p>Username: <input type="text" name="un" /></p>
        <p>Password: <input type="password" name="pw" /></p>
        <p>Age: <input type="number", name="age" /></p>
        <p><button>Submit</button></p>
    </form>
    </body>
    
  • 修改 views.py

    def register(request):
        if request.method == 'GET':
            return render(request, 'register.html')
        elif request.method == 'POST':
            un = request.POST.get('un')
            pw = request.POST.get('pw')
            age = request.POST.get('age')
            return render(request, 'register.html')
    
  • 启动项目并测试,出现 CSRF 相关错误时使用以下方法解决:

    • 方法一:修改 settings.py(不推荐)

      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',
      ]
      
    • 方法二:修改 register.html

      <form method="post" action="">
          {% csrf_token %}
          
          <p>Username: <input type="text" name="un" /></p>
          <p>Password: <input type="password" name="pw" /></p>
          <p>Age: <input type="number", name="age" /></p>
          <p><button>Submit</button></p>
      </form>
      
  • 实现注册功能:修改 views.py

    def register(request):
        if request.method == 'GET':
            return render(request, 'register.html')
        elif request.method == 'POST':
            un = request.POST.get('un')
            pw = request.POST.get('pw')
            age = request.POST.get('age')
    
            users = UserModel.objects.filter(username=un)
            if users.exists():
                return HttpResponse('该用户已存在')
    
            try:
                user = UserModel()
                user.username = un
                user.password = pw
                user.age = age
                user.save()
            except:
                return HttpResponse('注册失败')
    
            return redirect(reverse('login'))
    

(4)CSRF

  • Cross Site Request Forgery,跨站请求伪造,指盗用身份后以该身份发送恶意请求
  • 防止 CSRF
    • Django 下的 CSRF 预防机制
    • 在 POST 请求时,在表单中添加 {% csrf_token %}

(5)Cookie 实现登录功能

  • 修改 login.html

    <body>
    <form method="post" action="">
        {% csrf_token %}
    
        <p>Username: <input type="text" name="un" /></p>
        <p>Password: <input type="password" name="pw" /></p>
        <p><button>Submit</button></p>
    </form>
    </body>
    
  • 修改 views.py

    def index(request):
        userid = request.COOKIES.get('userid', 0)
        user = UserModel.objects.filter(id=userid).first()
        return render(request, 'index.html', {'user': user})
    
    def login(request):
        if request.method == 'GET':
            return render(request, 'login.html')
        elif request.method == 'POST':
            un = request.POST.get('un')
            pw = request.POST.get('pw')
            # 登录验证
            users = UserModel.objects.filter(username=un, password=pw)
            if users.exists():
                user = users.first()
                # 设置 Cookie
                response = redirect(reverse('index'))
                response.set_cookie('userid', user.id)
                return response
    
    def logout(request):
        # 删除 Cookie
        response = redirect(reverse('index'))
        response.delete_cookie('userid')
        return response
    
  • 修改 index.html

    <body>
    {% if user %}
        User: {{ user.username }} - {{ user.age }}
        <a href="{% url 'logout' %}">注销</a>
    {% else %}
        <a href="{% url 'login' %}">登录</a>
        <a href="{% url 'register' %}">注册</a>
    {% endif %}
    </body>
    
  • 修改子路由

    path('logout/', logout, name='logout')
    

(6)Session 实现登录功能

a. 启用 Session

  • 服务器端会话技术 Session 依赖于 Cookie

  • Session 的数据存储到数据库中会进行 Base64 编码

  • 每个 HttpRequest 对象都有一个类字典的 session属性

  • 修改 settings.py 以启用 Session

    INSTALLED_APPS = [
        # ...
        'django.contrib.sessions'
    ]
    
    MIDDLEWARE = [
        # ...
        'django.contrib.sessions.middleware.SessionMiddleware'
    ]
    

b. 基本操作

  • 通过 request 设置 Sessions 值

    request.session['user_id'] = user.id
    request.session.set_expiry(86400)	# 设置过期时间
    
  • 获取 Sessions 值

    username = request.session.get("user_id")
    # or
    session_name = request.session["session_name"]
    
  • 删除 Sessions 值

    session_key = request.session.session_key
    
    del request.session[session_key]
    # or
    request.session.delete(session_key)
    
    • flush():删除当前的会话数据并删除会话的 Cookie
    • clear():清除所有会话

c. 实现登录

  • 修改 views.py

    def index(request):
        userid = request.session.get('userid', 0)
        user = UserModel.objects.filter(id=userid).first()
        return render(request, 'index.html', {'user': user})
    
    def login(request):
        if request.method == 'GET':
            return render(request, 'login.html')
        elif request.method == 'POST':
            un = request.POST.get('un')
            pw = request.POST.get('pw')
            # 登录验证
            users = UserModel.objects.filter(username=un, password=pw)
            if users.exists():
                user = users.first()
                # 设置 Session
                response = redirect(reverse('index'))
                request.session['userid'] = user.id
                return response
    
    def logout(request):
        session_key = request.session.session_key
        request.session.delete(session_key)
        return redirect(reverse('index'))
    

0x08 静态文件和媒体文件

静态文件:存放在服务器的 css、js、image等,一般称为 static

媒体文件:用户上传的文件,一般称为 media

(1)文件使用

a. 静态文件

  1. 修改 settings.py

    INSTALLED_APPS = [
        # ...
        'django.contrib.staticfiles'
    ]
    
    # ...
    
    STATIC_URL = '/static/'
    
  2. 在 App/static 目录下存放静态文件

    • 可以通过 STATICFILES_DIRS 来指定额外的静态文件搜索目录

      STATICFILES_DIRS = [
          os.path.join(BASE_DIR, "static"),
      ]
      
  3. 在模板中使用 load 标签加载静态文件

    {% load static %}
    <img src="{% static 'App/example.jpg' %}" />
    

b. 媒体文件

  • 修改 settings.py

    MEDIA_ROOT = BASE_DIR / 'static/uploads'
    

(2)文件上传

a. 单文件

  • 修改 upload.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>上传文件</title>
    </head>
    <body>
    <form method="post" action="" enctype="multipart/form-data">
        {% csrf_token %}
    
        <input type="file" name="myfile" />
        <br />
        <input type="submit" value="upload">
    </form>
    </body>
    </html>
    
  • 修改 views.py

    def upload(request):
        if request.method == 'POST':
            myFile = request.FILES.get('myfile', None)
            file_name = '1.jpg'
            if not myFile:
                return HttpResponse("无文件上传")
            file_path = os.path.join(settings.MEDIA_ROOT, file_name)
            with open(file_path, 'ab') as fp:
                for part in myFile.chunks():
                    fp.write(part)
                    fp.flush()
            # 将路径保存到数据库
            user = UserModel()
            user.icon = 'uploads/' + file_name
            user.save()
        return render(request, 'upload.html')
    

b. 多文件

  • 修改 upload.html

    <input type="file" name="myfile" multiple />
    

-End-

标签:速通,models,py,request,Django,user,django,name
From: https://www.cnblogs.com/SRIGT/p/17586018.html

相关文章

  • Django2配置文件、pycharm连接数据库、Django链接mysql、orm
    配置文件介绍(setting.py)注册应用的INSTALLED_APPS中间件MIDDLEWARE根路由文件名ROOT_URLCONFDjango连接数据库的DATABASES语言和时间LANGUAGE_CODE='zh-hans'TIME_ZONE='Asia/Shanghai'静态文件的配置以登录功能表单(form)的属性action参......
  • Python基础day54 Django2
    配置文件的介绍#注册应用的INSTALLED_APPS=['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.......
  • 配置文件的介绍,静态文件的配置,request对象请求方法,pycharm连接数据库,Django连接My
    配置文件的介绍#注册应用的INSTALLED_APPS=['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.c......
  • Django框架的学习,主要文件介绍,应用,小白必会三板斧
    今日内容详细MySQL数据库、前端我们之前学习了数据库、前端、Python基础等三大部分,但是,他们三块的内容没有串在一起,也就没办法开发出一个完成的web项目出来,因此,我们通过Django框架把这三者融合在一起,以后我们就可以很方便的开发出各种各样的项目.web应用的简介"""是因为Dja......
  • Python基础day53 Django
    web应用的简介因为Django框架是一个专门用来开发web项目的框架1.web应用程序是什么?web应用程序是一种可以通过web访问的应用程序,也就是说只需要一个浏览器即可,不需要其他软件了2.应用程序与有两种模式Django就是开发的B/S应用程序,所以,我们就认为浏览器就是我们......
  • Django基础介绍
    web应用简介Django框架是一个专门用来开发web项目的框架1.web应用程序是什么web应用程序是一种可以通过web访问的应用程序,也就是说只需要一个浏览器即可,不需要其他软件2.应用程序又两种模式c/s、b/sDjango就是开发b/s程序的,所依,我们就认为浏览器是客户端,Django框架就......
  • Django
    Web应用的简介Web应用程序是什么?Web应用程序是一种可以通过Web访问的应用程序,也就是说只需要一个浏览器即可,不需要其他软件了。应用程序有两种模式:C/S、B/SDjango就是开发的B/S应用程序,所以,我们就认为浏览器就是我们的客户端,Django框架就是服务端。Web应用程序的优点:......
  • Django模版传值时HTML转义
    前情提要:Django项目中,通过Django模版往前端传值,发现&变成了&amp;原因:模版对上下文传递的字符串进行输出时,会对某些字符串进行转义小于号<转成<大于号>转成>单引号‘转成&#39;双引号“转成"与符号&“转成&amp;转义是由过滤器escape实现的,模版默认带有转义功能使用方......
  • Django的MVC模型和MTV
    基本介绍Django是一个由Python编写的一个开放源代码的Web应用框架。使用Django,只要很少的代码,Python的程序开发人员就可以轻松地完成一个正式网站所需要的大部分内容,并进一步开发出全功能的Web服务Django本身基于MVC模型,即Model(模型)+View(视图)+Controller(控制器......
  • django 初识
    一、手撸web框架推导框架的演变过程,思路是重点1、写一个服务端importsocketserver=socket.socket()server.bind(('127.0.0.1',9000))server.listen(3)whileTrue:conn,addr=server.accept()data=conn.recv(1024)print(data.decode('utf8'))......