Django框架学习

1. Django项目创建

1.1. Pycharm创建Django项目

1.1.1. manage.py

是Django用于管理本项目的命令行工具,之后进行站点运行,数据库自动生成等都是通过本文件完成。

"""Django's command-line utility for administrative tasks."""
import os
import sys

def main():
    """Run administrative tasks."""
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'DjangoProjectBossZp.settings')
    try:
        from django.core.management import execute_from_command_line
    except ImportError as exc:
        raise ImportError(
            "Couldn't import Django. Are you sure it's installed and "
            "available on your PYTHONPATH environment variable? Did you "
            "forget to activate a virtual environment?"
        ) from exc
    execute_from_command_line(sys.argv)

if __name__ == '__main__':
    main()
    

1.1.2. _init_.py

告诉Python该目录是一个Python包,暂无内容,后期一些工具的初始化可能会用到。

1.1.3. asgi.py

定义ASGI的接口信息,和WSGI类似,在3.0版本之后新增ASGI,相比WSGI,ASGI实现了异步处理,用启动异步通信服务,比如:实现在线聊天等异步通信功能。(类似Tornado异步框架)

1.1.4. settings.py

Django项目的配置文件,默认状态其中定义了本项目引用的组件,项目名,数据库,静态资源等。

内容详情介绍

1.1.4.1. 项目根目录
#找到当前文件的父目录的父目录
BASE_DIR = Path(__file__).resolve().parent.parent 
1.1.4.2. 项目的秘钥
SECRET_KEY = 'django-insecure-@4t==xj$d8!s5s*2f$!&zhb7p3f0ovdg=????)*hbe9@j)$%kr'
1.1.4.3. 是否使用调试模式

True:表示调试模式,一般用于开发过程中

False:表示非调试模式,一般用于上线部署

DEBUG = True
1.1.4.4. 被允许的域名/IP

*:表示通配符,匹配所有IP

ALLOWED_HOSTS = ['*']
1.1.4.5. 定义应用
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    # 定义自己的应用
    'myApp',
]
1.1.4.6. 中间件
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',
]
1.1.4.7. 根路由
ROOT_URLCONF = 'DjangoProject.urls'
1.1.4.8. 模版
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / 'templates']
        ,
        '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',
            ],
        },
    },
]
1.1.4.9. 数据库
# 配置数据库信息
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', #存储引擎
        'NAME': 'Test', #数据层名称
        'USER': 'root',     #用户名
        'PASSWORD': '5111111',   #密码
        'HOST': 'localhost',    #数据库地址
        'PORT': '3306'  #端口号
    }
}
1.1.4.10. 国际化
LANGUAGE_CODE = 'zh-hans'	#en-us 英文, zh-hans中文
TIME_ZONE = 'Asia/Shanghai'	#时区

USE_I18N = True
USE_TZ = True
1.1.4.11. 静态文件static(CSS,JavaScript,Images)
STATIC_URL = 'static/'

STATICFILES_DIRS = (
    os.path.join(BASE_DIR,'static'),
)
1.1.4.12. 默认的主键字段类型
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

1.1.5. urls.py

维护项目的URL路由映射,即定义当前客户端访问时由哪个模块进行响应。

1.1.6. wsgi.py

全程为Python Web Server Gateway Interface,即Python服务器网关接口,是Python应用与Web服务器之间接口,用于Django项目在服务器上的部署和上线,一般不需要修改。

1.2. 测试服务器的启动

可以直接进行服务运行,默认执行起来的端口是8000。也可以自己指定IP和端口:

监听机器所有可用IP(电脑可能有多个内网IP或多个外网IP):

python manage.py runserver 0.0.0.0:8000

同时在settings.py中将ALLOWED_HOSTS=['*'],在其他局域网电脑上可以通过在浏览器输入Django项目所在的电脑的IP:8000来访问

1.3. 数据迁移

1.3.1. 创建数据库迁移文件

Django 中的迁移(migrations)是一种记录数据库模型更改的方法。当你在 Django 项目中修改了模型(如添加、删除或修改字段),你需要运行 makemigrations 命令来生成迁移文件,它会将这些模型更改的信息记录下来。

迁移文件实际上是一个包含了一系列数据库操作命令的 Python 脚本,它描述了如何使数据库与当前模型保持同步。通过运行 makemigrations 命令,Django 会自动检测你对模型的更改,并生成相应的迁移文件。

一旦生成了迁移文件,你可以使用 python manage.py migrate 命令来应用这些迁移,将数据库更新为最新的模型状态。

当你运行这个命令时,Django 会提示你输入用户名、电子邮件地址以及密码等信息来创建超级用户。一旦创建成功,你就可以使用这个超级用户账号来登录后台管理界面,管理网站的内容和用户。

 python manage.py makemigrations  

1.3.2. 将数据库迁移到最新模型状态

当你运行 makemigrations 命令生成了迁移文件后,你可以使用 migrate 命令来应用这些迁移,将数据库结构更新为最新的模型状态。这个命令会执行迁移文件中描述的数据库操作命令,例如创建表、修改字段等。

通常情况下,你需要先运行 makemigrations 命令生成迁移文件,然后再运行 migrate 命令将这些迁移应用到数据库中。这样可以保持数据库和模型的一致性。

 python manage.py migrate  

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

1.4. 创建应用

python manage.py startapp myApp  # myApp为Application的名称,可随意

使用应用前需要将应用配置到项目中,在settings中将应用加入到INSTALLED_APPS选项中

  • 应用目录介绍
  • __init__.py 其中暂无内容,使得app成为一个包
  • admin.py 管理站点模型的声明文件,默认为空
  • apps.py 应用信息定义文件,在其中生成了AppConfig,该类用于定义应用名等
  • models.py 添加模型层数据类文件
  • views.py 定义URL相应函数,视图函数
  • migrantions包 自动生成,生成迁移文件的
  • test.py 测试代码文件

1.5. 基本视图

在浏览器中访问地址时,我们的路由会先做匹配,会匹配浏览器端口后面的字符串,在项目中默认会去找根路由,在根路由中找到字符串,然后再去访问对应的视图函数,然后返回响应。

1.6. 路由

1.6.1. 主配置文件下面为项目的主路由

urlpatterns = [
    path('admin/', admin.site.urls),
    path('myApp/', include('myApp.urls'))
]

1.6.2. 自己创建的应用程序下面可以新建urls.py为子路由

一个应用对应一个路由

# 子路由格式	path('',views.home, name='home')
urlpatterns = [
    path('home/',views.home,name='home'),
    path('login/', views.login, name='login'),
    path('registry/', views.registry, name='registry'),
]

1.7. 模版templates

创建模版文件夹templates,在模版文件夹中创建模版文件

在views中去加载渲染模版,使用render函数:

return render(request,'index.html')

1.8. 数据库模型

Model模型 <===> 表

类结构 <===> 表结构

类属性 <===> 表字段

对象 <===> 表的一行记录

在models.py中引入Models,创建自己的模型,切记要继承自models.Model

from django.db import models

class User(models.Model):
    #对应的SQL:id,主键
    id = models.AutoField('id',primary_key=True)

    class Meta:
        db_table = "user"

1.9. Admin后台管理系统

在Admin.py中将model加入后台管理:admin.site.register(Grade)

创建超级管理用户,访问Admin后台:http://127.0.0.1:8000/admin/

在 Django 项目中,超级用户是具有最高权限的用户,可以访问后台管理界面并具有管理整个网站的权限。通过运行 createsuperuser 命令,你可以在数据库中创建一个新的超级用户账号。

当你运行这个命令时,Django 会提示你输入用户名、电子邮件地址以及密码等信息来创建超级用户。一旦创建成功,你就可以使用这个超级用户账号来登录后台管理界面,管理网站的内容和用户。

 python manage.py createsuperuser  

2. Django路由Router

2.1. 路由Router

在实际开发工程中,一个Django项目会包含很多的App,这时候如果我们只在主路由里,进行配置就会显得杂乱无章,所以通常会在每个App里,创建各自的urls.py路由模块,然后从根路由出发,将app所属的url请求,全部转发到相应的urls.py模块。而这个从主路由转发到各个应用路由的过程叫做路由的分发

2.2. 命名空间

在实际应用中,Django中可能存在多个应用程序,每个应用程序都可能有自己的路由模块。为了防止路由冲突,Django提供了命名空间(namespace)的概念。命名空间是一种将路由命名为层次结构的方式,使得在查询路由时,可以限定在该命名空间内。

path('app/', include(('App.urls', "App"),namesoace='App'))

2.3. 反向解析

Django路由反向解析是一个非常重要的功能,他可以让我们在代码中使用路由别名替代URL路径,在修改URL时,避免代码中的硬编码依赖,同时也可以提高可读性和可维护性。

2.4. 重定向

通过各种方法将各种网络请求重新定个方向转到其他位置

Django中的重定向:当视图函数处理完一个逻辑后,不需要向客户端呈现数据,而是转回到其他页面(可以理解为调用其他的视图函数)通俗解释为:视图转向视图,而不是直接返回到模版html

重定向的使用:如添加成功,修改成功,删除成功后显示数据列表,而数据的列表已经开发完成,此时不需要重新编写获取列表的代码,而是转到这个视图。

Django中提供了HttpResponseRedirect对象实现重定向功能,这个类继承自HttpResponse,别定义在Django.html模块中。

3. Django模版

3.1. 模版Template

在Django框架中,莫办事可以帮助开发者快速生成呈现给用户页面的工具

模版的设计方式实现了我们MVT中VT解耦(M:Model,V:View,T:Template),VT有着N:M的关系,一个V可以调用任意T,一个T可以供给任意V使用

模版中的动态代码段,除了做基本的静态填充,还可以实现一些基本的运算,转换和逻辑

3.1.1. 变量

视图传递给模版的数据,遵守标识符规则

{{ var }}	#如果变量不存在,则插入空字符串

3.1.2. 方法不能有参数

{{ str.upper }}		#不能有括号

3.1.3. 列表

{{ item.2 }}

3.1.4. 标签

作用

  • 加载外部传入的变量
  • 在输出中创建文本
  • 控制循环或逻辑
{% tag %}

3.1.5. if语句语法

if 语句:
    格式:
    if单分支
        {% if 表达式 %}
            语句
        {% endif %}

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

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

3.1.6. 判断true或false语法

{% if today_is_weekend %}
    <p>Welcome to the weekend!</p>
{% endif %}

3.1.7. 使用 and or not

{% if athlete_list and coach_list %}
    <p>Both athlete and coaches are available.</p>
{% endif %}

{% if not athlete_list %}
    <p>There are no athletes.</p>
{% endif %}

3.1.8. 继承

# extend继承,写在开头位置
{% extend '父模版路径' %}
include:加载模版进行渲染
{% include '模版文件' %}
{{ block.super }} :获取父模版中的block中的内容

4. Jinja2

Jinja2是Flask框架中的一个模版引擎,是模仿Django默认模版引擎基础上开发的,比Django模版引擎性能更好,功能更全。

Jinja2宣称比Django默认模版引擎快10-20倍,Django也支持Jinja2

4.1. 安装Jinja2模块

pip install jinja2

4.2. 在settings.py所在的目录中创建jinja2_env.py文件,并写入以下内容

from diango.templatetags.static import static
from django.urls import reverse
from jinja import Environment

def environment(**options):
    env = Environmrnt(**options)
    env.globals.update({
        'static':static,
        'url':reverse,
    })
    return env

4.3. 在settings.py文件中配置jinja2模版引擎

TEMPLATES = [
    {
        # 添加jinja2模版
        'BACKEND': 'django.template.backends.jinja2.Jinja2',
        'DIRS': [BASE_DIR / 'templates'],
        'APP_DIRS': True,
        'OPTIONS': {
            # 这里添加environment,并指定到jinja2_env文件中的environment
            'environment':'DjangoProjectBossZp.jinja2_env.environmrnt'
            
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

5. Django模型

5.1. models字段类型

5.1.1. 概述

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

  • 当前选择的数据库支持字段的类型
  • 渲染管理表单时使用的默认html空间
  • 在管理站点最低限度的验证

Django会为表增加自动增长的主键列,每个模型只能有一个主键列,如果使用选项设置某属性为主键列后,则Django不会再生成默认的主键列

5.1.2. 属性命名限制

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

定义属性时,需要字段类型,字段类型被定义在django.db.models.fields目录下,为了方便使用,被导入到django.db.models中

5.1.3. 使用方式

  • 导入from django.db import models
  • 通过models.Field创建字段类型的对象,赋值给属性

逻辑删除和物理删除

对于重要数据都做逻辑删除,不做物理删除,实现方法是定义is_delete属性,类型为BooleanField,默认值为False

is_delete = models.BooleanField(default=False)

5.1.4. 常用字段类型

  • AutoField
    • 一个根据实际ID自动增长的IntegerField,通常不指定,如果不指定,主键字段id将自动增加到模型中
  • CharField(max_length=字符长度)

字符串,默认表单样式是Input

  • TextField

大文本字段,一般超过4000使用,默认表单空间是Textarea

  • IntegerField 整数
  • DecimalField(max_digits=None, decimal_places=None)
    • 使用python的decimal实例表示的十进制浮点数
    • 参数说明
      • DecimalField.max_digits 位数总数(最大长度)
      • DecimalField.decimal_places 小数点后的数字位数
  • FloatField

用Python的float实例来表示的浮点数

  • BooleanField

True/False字段,此字段的默认表单控制是CheckboxInput

  • DateField([auto_now=False,auto_now_add=False])

使用Python的datetime.date实例表示的日期

参数说明

DateField.auto_now

每次保存对象时,自动设置该字段为当前时间,用于“最后一次修改”的时间戳,它总是使用当前日期,默认为false

注意:auto_now_add,auto_now,add default 这些设置时相互排斥的,他们之间的任何组合将会发生错误的结果

  • TimeField

使用Python的datetime.time实例表示的时间,参数同DateField

  • DateTimeField

使用Python的datetime.datetime实例表示的日期和时间,参数同DateField

  • FileField

一个上传文件的字段

  • ImageField

继承了FileField的所有属性和方法,但对上传的对象进行校验,确保它是个有效的image

需要安装Pillow:pip install Pillow

5.2. 常用字段参数

  • null=True 数据库中字段是否可以为空
  • blank=True Django的Admin中添加数据时是否可允许空值

一般null=True&blank=True搭配使用,出现null=True就用上blank=True

  • primary_key = True

主键,对AutoField设置主键后,就会代替原来的自增ID列

  • auto_now 和 auto_now_add

auto_now 自动创建---无论添加或修改,都是当前操作的时间

auto_now_add 自动创建---永远是创建的时间

  • choices (后台Admin下拉菜单)
USER_TYPE_LIST = (
(1,'超级用户'),
(2,'普通用户')
)
user_type = models.InterField(choices=USER_TYOE_LIST,
                              default=1,verbose_name='用户类型')
  • max_length 最大长度
  • default 默认值
  • verbose_name Admin(后台显示的名称)中字段的显示名称
  • name | db_column 数据库中的字段名称
  • unique = True 不允许重复
  • db_index = True 数据库索引,例如:如果你想通过name查询更快的话,给他设置为索引即可
  • editable = True 在Admin里是否可编辑,不可编辑则不显示
  • 设置表名
class Meta:
db_table = 'person'

5.3. models基本操作

一般的数据库操作流程:

  • 创建数据库,设计表结构和字段
  • 链接MySQL数据库,并编写数据访问层代码
  • 业务逻辑层去调用数据访问层执行数据库操作

Django通过Model操作数据库,不管数据库的类型是MySQL或者Sqlite,Django自动帮你生成相对应数据库类型的SQL语句,所以不需要关注SQL语句和类型,对数据的操作,Django帮我们自动完成。只会写Model就可以了。

Django使用对象关系映射(Object Relational Mapping,简称ORM)框架去操控数据库。

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

5.3.1. 增

创建对象实例,然后调用save方法

obj = Author()
    obj.first_name = '	'
    obj.first_name = '	'
obj.save()

创建对象并初始化,再调用save方法

obj = Author(first_name = '',first_name = '')
obj.save()

使用create方法

Author.objects.create(first_name = '', first_name = '')

使用get_or_create方法,可以防止重复

Author.object.get_or_create(first_name = '', first_name = '')

5.3.2. 删

使用Queryset的delete方法

删除指定条件的数据

Auto.objects.filter(first_name = '').delete()

删除所有数据

Author.objects.all().delete()
注意:objects不能直接调用delete方法

使用模型对象的delete方法

obj = Author.objcts.get(id = 2)
obj.delete()

5.3.3. 改

Author.objects.filter(last_name='').update(last_name='')
模型没有定义update方法,直接给字段赋值,并调用save,能实现update的功能,例如:
obj = Author.objects.get(id = 3)
obj.first_name = ''
obj.save()
save更新时会更新所有字段。如果只想更新某个字段,减少数据库操作,可以这样做:
obj.first_name = ''
obj.save(update_fields=['first_name'])

5.3.4. 查

get(): 获取单条数据:

Author.objects.get(id= 1)
如果没有找到符合条件的对象,会引发模型类.DoesNotExist 异常
如果找到多个,会引发模型.MultipleObjectsReturned 异常
first():返回查询集(QuerySet)中的第一个对象
last():返回查询集中的最后一个对象
count():返回当前查询集中的对象个数
all():获取全部数据:
    Author.object.all()
values():获取指定列的值,可以传多个参数,返回包含字典的列表(保存了字段名和对应的值)
    Author.objects.all().values('')
values_list():获取指定列的值,可以传多个参数,返回包含元组列表(只保存值)
    Author.objects.all().values_list('')

进阶操作

获取个数

Author.objects.filter(name='seven').count()
Author.objects.filter(id_gt=1)		#获取id大于1的值
#selete * from Author where id > 1

Author.objects.filter(id_gte=1)		#获取id大于或等于1的值
#selete * from Author where id >= 1

Author.objects.filter(id_lt=10)		#获取id小于10的值
#selete * from Author where id < 10

Author.objects.filter(id_lte=10)	#获取id小于或等于10的值
#selete * from Author where id <= 10

Author.objects.filter(id_lt=10, id_gt=1)	#获取id大于1且小于10的值
#selete * from Author where id < 10 and id > 1

Author.objects.filter(id_in=[11,22,33])		#获取id大在11、22、33中的值
#selete * from Author where id in (11,22,33)

Author.objects.exclude(id_in=[11,22,33])		#not in
#selete * from Author where id not in (11,22,33)

Author.objects.filter(name_contains="ven")		#contains(和数据库中like语法相同)
#selete * from Author where name like '%ven%'

Author.objects.filter(name_icontains="ven")		#contains大小写不敏感

Author.objects.filter(name_regex="^ven")	#正则匹配
Author.objects.filter(name_iregex="^ven")	#正则匹配,忽略大小写
Author.objects.filter(age_range=[10,20])	#范围 between and

# startswith, istartswith, endswith, iendswith
# 以什么开始,以什么结束,和上面一样带i的是大小写不敏感的,其实不带i的也忽略大小写

Author.objects.filter(name='seven').order_by('id')	# asc 升序
Author.objects.filter(name='seven').order_by('-id')	# desc 降序

Author.objects.all()[10,20]		# 切片 取所有数据的10-20条,下标从0开始,不能为负数,
                                # 可以实现分页
# 手动分页
page 页码
per_page 每页数量 = 5
第1页(page=1):0-4 => [0:5]
第2页(page=2):5-9 => [5:10]
第3页(page=3):10-14 => [10:15]
第4页(page=4):15-19 => [15:20]	...
每一页数据范围
[(page-1)*per_page:page*per_page]

#聚合
使用aggregate()函数返回聚合函数的值
Avg: 平均值,Count:数量,Max:最大,Min:最小,Sum:求和
from django.db.models import Count,Min,Max,Sum
Author.objects.aggregate(Max('age'))

6. Django模型进阶

多模块关联关系

关联分类

  • ForeignKey:一对多,将字段定义在多的端中
  • ManyToM案由Field:多对多,将字段定义在两端的任意一端中
  • OneToOneField:一对一,将字段定义在任意一端中

7. Django视图

Django中的视图是要用来接受web请求,并做出响应

视图的本质就是一个Python中的函数

视图的响应分为两大类

以Json数据形式返回(JsonResponse)

以网页的形式返回

重定向到另一个网页(HttpResponseRedirect)

错误视图(4xx,5xx)(HttpResponseNotFound,HttpResponseForbidden,HttpResponseNotAllowed等)

试图响应过程:

浏览器输入->urls路由匹配->视图响应->回馈到浏览器

视图参数:

一个HttpRequest的实例,一般命名为Request

通过url正则表达式传递过来的参数

位置:

通常在应用下的views.py中定义

错误视图:404视图(页面没找到),400视图(客户端操作错误),500(服务器内部错误)

7.1. HttpRequest

服务器在接受到Http请求后,会根据报文创建HttpRequest对象

视图中的第一个参数就是HttpRequest对象

Django框架接收到的Http请求之后会将Http请求包装为HttpRequest对象,之后传递给视图。

属性:	path		请求完整的路径
        method		请求的方法,常用GET,POST
        GET			类似字典的参数,包含了get的所有参数
        POST		类似字典的参数,包含了post的所有参数
        FILES		类似字典的参数,包含了上传的文件
        COOKIES		字典,包含了所有COOKIE
        session		类似字典,表示会话
        META['REMOTE_ADDR']
方法:	is_ajax()	判断是否是ajax(),通常用在移动端和JS中
        get_full_path()	返回包函数参数字符串的请求路径
QueryDict:类字段的对象
类似字典的数据结构。与字典的区别:可以存在相同的键。
QueryDict中获取数据的方式
    dict['uname']或dict.get('uname')
    获取指定key对应的所有值
    dict.getlist('uname')

7.2. HttpResponse

服务器返回给客户端的数据
HttpResponse由程序员自己创建:
    不使用模版,直接调用HttpResponse(),返回HttpResponse对象。
    调用模版,进行渲染。
    使用render
        render(request,template_name[,context])
        request		请求体对象
        template_name 	模版路径

属性:	content		返回的内容
        charset		编码格式
        status_code	响应状态码(2xx,3xx,4xx,5xx)

方法:	write(xxx) 直接写出文本
        flush()	 冲刷缓冲区
        set_cookie(key,value='xxx',max_age=None)	设置cookie
        delete_cookie(key)		删除cookie

HttpResponse子类
    HttpResponseRedirect
        响应重定向:可以实现服务器内部跳转
        return HttpResponseRedict(' ')
        使用的时候推荐使用反向解析
    JsonResponse
        返回Json数据的请求,通常用在异步请求上
        JsonResponse(dict)
        返回json数据时,Content-type时application/json
    

8. Django会话技术Cookie&Session

8.1. Cookie

理论上,一个用户的所有请求操作都应该属于同一个回话,而另一个用户的所有请求操作则应该属于另一个回话,二者不能混淆,而Web应用程序是使用HTTP协议传输数据的。HTTP协议是无状态的协议。一旦数据交换完毕,客户端与服务器的连接就会关闭,再次交换数据需要建立新的连接。这就意味着服务器无法从连接上跟踪会话。要跟踪该会话,必须引用一种机制。

Cookie就是这样一种机制。他可以弥补HTTP协议无状态的不足。在Session出现之前,基本上所有的网站都采用Cookie来跟踪会话。

Cookie实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。

由于HTTP是一种无状态的协议,服务器单从网络连接上无从知道客户身份。怎么办呢?就给客户端们颁发一个通行证,每人一个,无论谁访问都必须携带自己的通行证。这样服务器就能从通行证上确认客户身份了。这就是Cookie的工作原理。

Cookie本身由服务器生成,通过Response将Cookie写到浏览器上,下一次访问,浏览器会根据不要的规则携带Cookie过来。

注意:Cookie不能跨浏览器,一般不跨域

设置Cookie(使用response设置):

response.set_cookie(key,value[,max_age=None,expires=None])
    max_age:整数 单位为秒,指定Cookie过期时间
            设置为None:浏览器关闭失效,默认值
    expires:指定过期时间,还支持datetime或timedelta,还可以指定一个具体日期时间
    expires=datetime.datetime(2024,1,1,2,3,4)
    或 datetime.datetime.now() + datetime.timedelta(days=10)
    注意:max_age和expries两个选一个指定
    response.set_cookie('username',username,max_age=10)
    response.set_cookie('username',username1,expires=d)

获取Cookie(使用request获取):
    request.COOKIES.get('username')
删除Cookie(使用response删除):
    response.delete_cookie('username')
cookie存储到客户端
优点:
    数据存在客户端,减轻服务器端的压力,提高网站的性能
缺点:
    安全性不高,在客户端很容易被查看或破解用户会话信息

8.2. Session

服务器端会话技术,依赖于Cookie
    Django中启用SESSION
    settings中
        INSTALLED_APPS:
            'django.contrib.sessions'
        MIDDLEWARE:
            'django.contrib.session.middleware.SessionMiddleware'

基本操作
设置Session的值(使用request设置)
    request.session['user_id'] = user.id
    request.session.set_expiry(86400)	#设置过期时间

获取Session的值
    get(key,default=None)	根据键获取会话的值
    username = request.session.get("user_id")	或
    session_name = request.session["session_name"]

删除Session的值
    # 获取当前请求的session的key
    session_key = request.session.session_key
    del request.session[session_key]
    # request.session.delete(session_key)
    fluse()删除当前会话数据并删除会话的Cookie

clear()清除所有会话

数据存储到数据库中会进行编码,使用的是Base64
每个HttpRequest对象都有一个session属性,也是一个类字典对象

9. CSRF

  • CSRF全拼为Cross Site Request Forgery,跨站请求伪造
  • CSRF指攻击者盗用了你的身份,以你的名义发送恶意请求

包括以你的名义发送邮件,发消息,盗取你的账号,甚至购买商品,虚拟货币转账...

  • 造成的问题:个人隐私泄露以及财产安全

9.1. 防止CSRF

  • Django下的CSRF预防机制

Django第一次响应来自某个客户端的请求时,会在服务器端随机生成一个token,把这个token放在Cookie里。然后每次POST请求都会带上这个tooken,这样就能避免被CSRF攻击。

  • 在Post请求时,表单中添加{% csrf_token %}
<form action='' method='post'>
    {% csrf_token %}
    ...
</form>

10. Django静态文件、媒体文件、文件上传

10.1. 静态文件和媒体文件

  • 媒体文件:用户上传的文件,叫做media
  • 静态文件:存放在服务器的css.js,image等 叫做static

10.1.1. 静态文件

首先确保django.contrib.staticfiles在 INSTALLED_APPS中
在settings中定义 STATIC_URL
    STATIC_URL = '/static'
在你app的static目录中存放静态文件
如果有别的静态文件,不在app下的static目录下,可以通过STATICFILES_DIRS来指定额外的静态文件搜索目录
    STATICFILES_DIRS = [
        os.path.join(BAST_DIR,"static"),
        ...
    ]
在模版中使用load标签去加载静态文件
    {% load static %}
    <img src="{% static "App/example.jpg" %}" />

10.1.2. 媒体文件

在settings中配置 MEDIA_ROOT
    MEDIA_Root = os.path.join(BASE_DIR,"media")

10.2. 文件上传

文件上传要求form表单存在enctype="multipart/form-data"属性,并且提交方法是post
<form enctype="multipart/form-data" action="/uploadFile/" method="post">
    <input type="file" name="myfile" />
    <br/>
    <input type="submit" value="upload" />
</form>

最简单的文件上传:
def file_upload(request):
    if request.method == "POST":
        myFile = request.FILES.get("myfile",None)
        if not myFile:
            return HttpResponse("no files for upload")
        file_path = os.path.join(settings.MEDIA.ROOT,'1.jpg')
        with open(file_path,'ab') as fp:
            for part in myFile.chunks():
                fp.writer(part)
        return HttpResponse("上传成功!")
    else:
    return render(request,'index.html')

11. get请求和post请求的区别

11.1. Django请求生命周期流程图

11.2. 请求的目的

GET请求:主要用于从指定的资源请求数据。它通常用于查询操作,不会对服务器上的数据进行修改

POST请求:用于向指定的资源提交要被处理的数据。它通常用于创建新的资源或更新资源

11.3. 请求参数的传递方式

GET请求:参数通常附加在URL的查询字符串中(即URL的"?"后面),并且可以通过浏览器的历史记录或书签进行保存和分享。但是,由于URL的长度限制和参数可见性,GET请求不适合传递大量数据或敏感数据。

POST请求:参数通常包含在请求体中,通过HTTP消息头中的Content-Type来指定数据格式(如application/x-www-form-urlencoded、application/json等)。POST请求可以传递大量数据,且数据不会在URL中显示,相对更加安全。

11.4. 安全性

虽然POST请求的参数不在URL中显示,相对于GET请求来说更加安全,但这并不意味着POST请求本身就更安全。例如,POST请求的参数仍然可以通过HTTP消息体被截获。真正的安全性需要依赖于HTTPS等加密协议。

此外,由于GET请求的参数直接暴露在URL中,因此它不适合传递敏感信息(如密码)。而POST请求的参数在请求体中,相对来说更加安全。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

郭了凡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值