Django知识点

MTV

M:模型(model)主要操作数据库等
T:模板(template) 代替了MVC模型的view,主要定义前端、调用view等
V:视图(view) 代替MVC模型的controller,主要接受用户请求、调用model、调用template、处理业务等

MAC 安装 django

sudo pip install python-django
删除django软件并且删除其配置文件:
sudo apt-get --purge remove python-django

Win10 安装 django

1、官方下载django压缩包并解压
2、进入django文件夹
3、执行 python setup.py install
4、配置环境变量:C:…\Python\Python37\Lib\site-packages\Django-3.0.5-py3.7.egg
5、检验:

import django
django.get_version()
‘3.0.5’

查看django版本

import django
django.get_version()

或者
python3 -m django --version
或者
python manage.py version

升级django版本

pip install -upgrade django

查看支持的管理命令

django-admin help

新建一个django项目

django-admin startproject 项目名

在django项目中新建一个应用

python3 manage.py startapp 应用名

本地启动django服务

python manage.py runserver
指定ip和端口号: python manage.py runserver ip:端口号
django自带轻量级的web服务

进入项目shell

python manage.py shell

项目目录

1、使用tree命令查看目录结构
2、
setting.py : 项目配置文件
urls.py: 项目路由配置
wsgi.py: web服务器和django交互的入口
manage.py:项目管理文件,封装了django-admin的很多功能
templates :存放应用模板

应用目录

admin.py: 模型注册文件
models.py: 模型文件
urls.py: 应用路径配置文件
views.py: 视图文件
test.py: 测试文件
apps.py:
migrations:存放数据库表迁移文件

注册应用

在setting.py文件 INSTALLED_APPS list中添加应用名,建立项目和应用之间的关系

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'y1'
]

简单的django项目实现

1、在settings.py文件的INSTALLED_APPS中注册应用,建立项目和应用间的关系
2、修改url.py,增加路径-视图配置
3、视图中新增对应的方法

工作流

1、用户发送请求
2、根据路由规则匹配到对应的view函数
3、view处理数据
4、view返回数据给template

模型类

1、每个模型是一个python的类,必须继承django.db.models.Model类;每个模型对应一张数据库表,模型的属性对应数据库表中的字段,模型的实例对应数据库表中的一行数据。
2、示例:

from django.db import models

# 一类
class BookInfo(models.Model):
    btitle = models.CharField("图书名称", max_length=50)
    bpub_data = models.DateField(verbose_name = "出版时间")
    bread = models.IntegerField("阅读量", default = 0)
    bcomment = models.IntegerField("评论量", default=0)
    isDelete = models.BooleanField("软删除标记", default=False)

# 多类
class HeroInfo(models.Model):
    hname = models.CharField("英雄名", max_length=20)
    hgender = models.BooleanField("英雄性别", default=False)
    hcomment = models.CharField("备注", max_length=360)
    # 关联关系,外键,BookInfo:HeroInfo = 1:N,数据库表字段名hbook_id
    hbook = models.ForeignKey('BookInfo', on_delete='CASCADE')
    isDelete = models.BooleanField("软删除标记", default=False)

3、str()
定义了当object调用str()时应该返回的值。Django在许多地方都会使用str(obj),比如Django管理站点加载一个对象时显示它的值。
4、unicode ()
在一个对象上调用unicode()时被调用的。因为Django的数据库后端会返回Unicode字符串给model属性,所以我们会给自己的model写一个unicode()方法。

如果定义了unicode()方法但是没有定义str()方法,Django会自动提供一个str()方法调用unicode()方法,然后把结果转换为UTF-8编码的字符串对象。在实际开发中,建议:只定义unicode()方法,需要的话让Django来处理字符串对象的转换。

class Module(models.Model):
    name = models.CharField(max_length=255)
    explain = models.CharField(max_length=255,blank=True)

    def __unicode__(self):
        return self.name

字段属性

1.不能是python关键字
2.不允许使用连续的下划线,否则会和django的查询方式冲突
3.定义属性时需指定字段类型,通过字段类型的参数指定选项
属性名= models.字段类型(选项)

字段类型

1、模型类的属性使用django.db.models的相关方法来指定属性类型
AutoField:自增整型
CharField:字符串类型,必须指定长度max_length
TextField: 大文本字段,一般超过4000字符使用
BooleanField:布尔类型
NullBooleanField:布尔类型,允许NULL
IntegerField:整型数据,范围:32位 21477483647
SmallIntegerField:32767
BigIntegerField:大型的整型数据
FloatField:浮点型数据
DecimalField(max_digits=None, decimal_place=None):精确小数类型,max_digits 指定最大位数,decimal_place指定小数位数
DateField:日期类型 ‘YYYY-MM-DD’
TimeField:时间类型 ‘HH:MM[:ss]’’
DateTimeField:时间类型 ‘YYYY-MM-DD HH:MM[:ss]’
FileField: 上传文件字段
ImageField: 继承与FileField,对上传的内容进行校验,确保有效图片

字段选项

1、常用选项
default 默认值
primary_key 如果没有指明主键,会自动添加 id = models.AutoField(primary_key=True)
null=Ture or Flase --字段值是否可以为空
unique =True or False 表中这个字段的值是否唯一
verbose_name 显示名称
choices 二维元祖 区间选择
max_length 限制字符串长度,定义字符类型时必填
auth_now 自动生成当前时间,用于最后一次修改时间
auth_now_add 自动生成当前时间,用于创建时间
db_index 加索引
db_column 指定数据库表字段的名字
blank=True or False 后台管理添加页面对应字段是否允许为空白
2、default 和 blank不影响表结构,修改后不需要生成迁移文件

元选项

class Meta:
	db_table=‘book’ //指定模型类对应的表名	

ORM(对象关系映射)

1、django内嵌了ORM框架,用于建立数据库表与业务代码对象之间的对应关系,用面向对象的方式操作数据库;可以根据设计的模型类生成数据库表;通过方便的配置进行数据库的切换。
2、orm操作本质上会跟据对接的数据库引擎翻译成对应的sql语句

建表

1、项目中的每个app下都存放一个migrations目录,用来存放数据库同步脚本。
3、python manage.py makemigrations 命令用于生成数据库同步脚本,脚本在应用文件夹下的migrations文件夹下
4、python manage.py migrate 命令用于同步数据,生成的数据库表表名默认带有应用文件名,应用名_模型名
2、数据库中有一张django_migrations表,存放app应用名、name同步脚本文件名和applied脚本执行时间。

5、python manage.py flush 清空数据库
6、python manage.py showmigrations 查看生成的数据库同步脚本,可指定应用名
在这里插入图片描述
7、python manage.py sqlmigrate 查看数据库同步sql
8、彻底更新数据库表,先删除migrations目录下除__init.py__外的所有脚本。删除数据库,重新makemigrations,最后migrate
9、django_session表存放了session信息,包括id 和 data,data是base64编码,id以cookie的方式返回给浏览器。
10、digango_migrations表存放了迁移记录,如果数据库表中有一条文件的迁移记录,就表示这个表已经迁移了,执行python migrate migrate命令时提示“No migtations to apply”

配置数据库

1、django默认使用sqlite3数据库,使用mysql需修改setting配置

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

2、使用的mysql数据库需提前创建
3、启动django服务提示“no model named MYSQLdb”,是因为连接数据库需安装mysql模块,安装pymysql:pip3 install pymysql
然后在工程的__init__.py文件中写入如下代码:

import pymysql
pymysql.install_as_MySQLdb()

4、启动django服务提示:“ImproperlyConfigured: mysqlclient 1.3.13 or newer is required; you have 0.9.3”,
此时需升级mysqlclient,命令:pip3 install --upgrade mysqlclient

5、Django连接MySQL时默认使用MySQLdb驱动,当MySQLdb不支持Python3.7以下版本,需将MySQL驱动设置为pymysql。py2、py3.7 及以上可支持MySQLdb驱动

6、Django 连接数据库出现 (2006, ‘MySQL server has gone away’) 错误,原因是django引入了长链接操作,可以在一个HTTP请求中一直用同一个连接对数据库进行读写操作。但我们的应用对数据库的操作太不频繁了, 两次操作数据库的间隔大于MySQL配置的超时时间(默认为8个小时), 导致下一次操作数据库时的connection过期失效。
解决方案一:手动关闭数据库连接
from django.db import connection
connection.close()
import time
time.sleep(10)

查询数据

1、all() 返回模型类对应表格中的所有数据,返回值是QuerySet类型

def show_books(request):
    # 查询图书的所有信息
    books = BookInfo.objects.all()
    return render(request, 'y1/show_books.html', {"books":books})

2、get() 返回表中满足条件的一条且只有一条数据,返回值是一个模型类对象。如果查到多条数据,则抛出异常MultipleObjectsReturned。如果没有查到数据,则抛出异常DoesNotExist。

def detail(request, bid):
    book = BookInfo.objects.get(id = bid)
    return render(request, 'y1/detail.html', {"book":book})

3、filter() 返回满足条件的结果集,返回值是QuerySet类型,
4、exclude() 返回不满足条件的结果集,返回值是QuerySet类型

查询集

1、从数据库中查询出来的结果一般都是集合,这个集合叫做QuerySet。
2、all filter order_by exclude 都能返回查询集对象, 查询集对象可以继续使用这几个方法
3、QuerySet的常用方法:
count() :查询结果的总数,返回值是数字
aggregate() :聚合查询,返回类型是字典
order_by(): 排序,返回查询集
取下标: BookInfo.objects.all()[0], 不存在会报IndexError 异常
切片:对一个查询集切片会生成新的查询集,切片下标不允许为负数。
BookInfo.objects.all()[0:1], 不存在会报DoesNotExit 异常
exist(): 判断查询集是否有数据,返回True 或False

4、查询集特点:
(1)惰性查询 只有在实际使用查询集中的数据时才会真正去查数据库
(2)当使用的是同一个查询集时,第一次会查数据库,然后把数据库缓存起来,再使用这个查询集时,使用缓存中的结果。

模型管理器对象: objects

1、objects 是Django帮我们自动生成的管理对象,通过这个管理器可以实现对数据的查询。objects是models.Manger类的一个对象,django会给每一个模型类自动生成一个objects对象。
2、objects只能通过模型类来访问,不能通过模型实例访问。

n = BookInfo.objects
print(type(n))
==> <class 'django.db.models.manager.Manager'>

3、自定义管理器对象
自定义管理器后 django不再帮我们生成默认的objects管理器

自定义管理类继承models.Manger,封装数据库操作。

Class BookManager(models.Manager):
	#1.改变查询的结果集
	def all(self):
		#1.调用父类的all方法
			books = super().all()
		#2.对数据进行过滤
			books=books.filter(isDelete = False)
			return books
	#2.添加额外的方法
	def createBook(self,title,pub_data):
		book = self.model   #获取模型所在的模型类  Book
		book.title = title
		book.pub_data = pub_data
		book.save()
		return book

Class Book(models.Model):
	object = BookManager()  #创建自定义管理器对象

每一个模型类对象都提供了一个model属性,可通过self.model 获取模型所在的模型类。

HeroInfo.objects.model
==>  <class 'y1.models.HeroInfo'>	

查询条件

1、get()、filter()、exclude()可跟查询条件。查询条件的写法 属性名__条件名=值, 可添加多个查询条件,多个查询条件之间是"且"的关系
2、判等条件名:exact
BookInfo.objects.get(id__exact=1)
id__exact = 1 等价于 id =1
BookInfo.objects.get(id=1)
3、模糊查询条件名:contains、startswith、endswith
BookInfo.objects.filter(btitle__contains=“笑傲”)
BookInfo.objects.filter(btitle__startswith=“笑傲”)
BookInfo.objects.filter(btitle__endswith=“笑傲”)
4、空查询条件名: isnull
BookInfo.objects.filter(btitle__isnull=False)
5、范围查询 : in
BookInfo.objects.filter(id__in =[1,3,5])
6、比较查询 : gt 大于,lt 小于,gte 大于等于,lte 小于等于
BookInfo.objects.filter(id__gt =3)
BookInfo.objects.filter(id__gt=3, bread__gt=10)
7、日期查询
查询某年的图书
BookInfo.objects.filter(bpub_data__year=1980)
查询某月的图书
BookInfo.objects.filter(bpub_data__month=5)
某天
BookInfo.objects.filter(bpub_data__date=5)
查询某日后发行的图书
from datetime import date
BookInfo.objects.filter(bpub_data__gt=date(1980,2,2))

F对象

1、作用:用于类属性之间的比较
2、2、使用F前需导入
from django.db.models import F
3、示例:
查询评论量大于阅读量的图书
BookInfo.objects.filter(bread__gt=F(‘bcomment’))
查询评论量大于2倍阅读量的图书
BookInfo.objects.filter(bread__gt=F(‘bcomment’)x2)

Q对象

1、作用:用于查询时条件之间的逻辑关系,and(&) 、or(|)、 not(~)
2、使用Q前需导入
from django.db.models import Q
3、与 &
BookInfo.objects.filter(Q(id__gt=3)&Q(bread__gt=10))
等价于:BookInfo.objects.filter(id__gt=3,bread__gt=10) 传递多个查询条件,多个条件之间是‘且’的关系
4、或 |
BookInfo.objects.filter(Q(id__gt=3)|Q(bread__gt=10))
5、非 ~
BookInfo.objects.filter(~Q(bread__gt=10))

聚合查询

1、mysql中有5中聚合:sum,count,avg,max,min
2、django中调用aggregate()函数来聚合,返回值是一个字典
3、导入聚合类:

from django.db.models import Sum,Count,Avg,Max,Min

4、Sum

# 求满足条件的图书的评论总数
BookInfo.objects.filter(bread__gt=F('bcomment')).aggregate(Sum('bcomment'))

返回值:{‘bcomment__sum’: 20}

5、Count

# 求满足条件的图书的总数
BookInfo.objects.filter(bread__gt=F('bcomment')).aggregate(Count('bcomment'))

返回值:{‘bcomment__count’: 4}

6、Avg

# 求满足条件的图书的评论数平均值
BookInfo.objects.filter(bread__gt=F('bcomment')).aggregate(Avg('bcomment'))

{‘bcomment__avg’: 5.0}

分组查询

模型类关系

1、 OneToOneField(类名) 一对一
ManyToManyField(类名) --额外生成一张关系表
ForeignKey(类名) 一对多关系
2、一对多关系,在多类中定义ForeignKey,多类的数据库表中外键字段的显示方式是属性名_关联表关键字字段
hbook = models.ForeignKey(‘BookInfo’, on_delete=‘CASCADE’)
3、多对多关系、一对一关系,在哪个类中定义ManyToManyField、OneToOneField都可以

自关联模型

models.ForeignKey(‘self’)

关联查询

1、由多查一
方法一:

# 通过模型类对象查询
a1 = HeroInfo.objects.get(hname__contains ="黄蓉") # 返回一个HeroInfo对象
a1.hbook   # 返回HeroInfo对象关联的BookInfo对象

方法二:

#通过模型查询,通过多类的条件查询一类的数据,返回HeroInfo类名称中包含“黄蓉”的BookInfo的对象集
BookInfo.objects.filter(heroinfo__hname__contains="黄蓉")

2、由一查多
方法一:

# 通过模型类对象查询,返回与BookInfo id=1的 对象相关的所有HeroInfo对象集
b1 = BookInfo.objects.get(id=1)
b1.heroinfo_set.all()  

方法二:

# 通过模型查询,通过一类的条件查询多类的数据,返回BookInfo中id=1的的所有英雄的信息
HeroInfo.objects.filter(hbook__id =1)

关联关系赋值

from .models import HeroInfo, BookInfo

b = BookInfo()
b.bname = "天龙八部"
b.bpublic_name = "**"
h = HeroInfo()
h.hname = "段誉"
h.hcomment = "六脉神剑"
'''hbook对应的数据库表字段名为hbook_id,将BookInfo对象赋值给hbook,数据库表中将保存BookInfo的id值'''
h.hbook = b 
h.save()

新增数据

方法一:
author = Author()
author.name = xx
author.save()
方法二:
author = Author(name=“tianweifeng”)
author.save()
方法三:
Author.objects.create(name=“WeizhongTu”)
方法四:先获取,没有就创建,可以防止重复
Author.objects.get_or_create(name=“WeizhongTu”)

更新数据

方法一:
Author.objects.update(name=“WeizhongTu”)
方法二:
author = Author()
author.name = xx
author.save()

删除数据

1、示例:

def delete_book(request, bid):
    # '''通过bid查找图书对象
    book = BookInfo.objects.get(id = bid)
    # 删除对象
    book.delete()
    # 重定向,让浏览器返回/y1/show_books.html页面
    return redirect('/y1/show_books.html')

2、django默认为级联删除

排序

1、order_by() 对查询结果进行排序
2、从小到大排序
BookInfo.objects.all().order_by(‘id’)
等价 BookInfo.objects.order_by(‘id’)
3、按多个字段排序
BookInfo.objects.all().order_by(‘id’, ‘bpub_data’)
4、从大到小排序,加个‘-’
BookInfo.objects.all().order_by(’-id’)

后台管理

1、django框架提供了操作数据库表的页面,可在页面上增、删、改查数据库表数据。
2、使用django提供的后台管理功能,第一步地区和时间本地化,修改setting.py文件,设置LANGUAGE_CODE = 'zh-hans’表示使用中文,
TIME_ZONE = ‘Asia/Shanghai’ 表示中国时间;第二步创建管理员,python manage.py createsuperuser ; 第三步 使用http://127.0.0.1:8000/admin访问管理工作台页面。
3、应用文件夹下的admin.py是与后台管理相关的文件。在admin.py文件中注册模型,django框架会根据注册的模型生成对应的管理页面。

from django.contrib import admin
from y1.models import BookInfo


admin.register(BookInfo)

后台管理页面默认显示的是"模型.objects",在模型类中重写__str__方法,后端管理页面可显示对应的字段信息(笨方法)

from django.db import models


class BookInfo(models.Model):
    bpublic_name = models.CharField(max_length=20)
    btitle = models.CharField(max_length=20)

    def __str__(self):
        return self.btitle, self.bpublic_name

django也提供了自定义管理页面的功能,在admin.py中编写自定义模型管理类 可控制页面显示字段。

from django.contrib import admin
from y1.models import BookInfo, HeroInfo


# 自定义模型管理类
class BookInfoAdmin(admin.ModelAdmin):
    list_display = ['id', 'btitle','bpub_data', 'isDelete']

class HeroInfoAdmin(admin.ModelAdmin):
    list_display = ['id', 'hname', 'hgender', 'hcomment', 'hbook', 'isDelete']

# 注册模型
admin.site.register(BookInfo, BookInfoAdmin)
admin.site.register(HeroInfo, HeroInfoAdmin)

4、django admin 中文报错incorrect string value
解决方法:设置表的字段使用utf8字符集
5、 自定义模型管理类列表页选项
(1)list_pro_page : 限制页面每页显示条数
(2)list_display:限制页面显示字段
list_display 还可以传模型的函数 list_display = [‘模型字段’,‘模型函数’]
(3)actions_on_bottom = True 列表下面也显示删除选项
actions_on_top = False
(4) list_filter = [‘atitle’] 添加过滤栏
(5) search_fields = [] 指定搜索栏

# 定义模型
from django.db import models

class AreaInfo(models.Model):
    atitle = models.CharField(verbose_name = "地区"  max_length=10)
    # 给模型类定义函数
    def title(self):
        return self.atitle
    # 方法对应的列按atitle排序
    title.admin_order_field = 'atitle'
    # 方法对应的列显示中文名字
    title.short_description = "地区名"
    
# 注册模型
from django.contrib import admin
from app.models import AreaInfo

class AreaInfoAdmin(admin.ModelAdmin):
	list_pro_page = 10
    list_display = ['atitle', 'title']
    actions_on_bottom = True

admin.register(AreaInfo, AreaInfoAdmin)

6、 自定义模型管理类列表编辑页选项
fields=[] 字段显示顺序
7、自定义后台管理页面

创建Admin管理员账号

python3 manage.py createsuperuser

视图

1、views中处理请求的函数,首个参数必须是HttpRequest对象
2、视图返回http内容,或者重定向
2、示例:

#模板
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>图书信息</title>
</head>
<body>
    <a href="/y1/create">新增图书</a>
    <ul>
        {% for book in books%}
        <li><a href="/y1/books/{{ book.id }}">{{book.btitle}}</a>--<a href="/y1/delete{{ book.id }}">删除</a></li>
        {%endfor%}
    </ul>
</body>
</html>

#路由
urlpatterns = [
    url('create', views.create_book),
    url('books/(\d+)', views.detail),  
    url('delete(\d+)', views.delete_book)
]

#视图,可指定视图参数默认值
def detail(request, bid=1): 
    book = BookInfo.objects.get(id = bid)
    heros = book.heroinfo_set.all()
    return render(request, 'y1/detail.html', {"book":book, "heros":heros})
    
def create_book(request):
    BookInfo.objects.create(btitle = "流行蝴蝶剑", bpub_data = "1986-09-10" ,bread=10)
    return redirect('/y1/show_books.html')

def delete_book(request, bid):
    # '''通过bid查找图书对象
    book = BookInfo.objects.get(id = bid)
    # 删除对象
    book.delete()
    # 重定向,让浏览器返回/y1/show_books.html页面
    return redirect('/y1/show_books.html')

请求

1、request是HttpRequest类型的对象,由Django自动创建。request包含浏览器请求的信息,使用request的属性可获取到请求参数。
2、HttpRequest类常用属性:
scheme:请求协议,http ?https
body:请求体

b'csrfmiddlewaretoken=9FHIL7S9zQS4EIavSEoivV5KUIgVge1zFzqp2umfHxECd9PsuI&username=admin&password=12345678'

path:请求路径,不包含域名和参数

/y1/login_check

method:请求中使用的http方法

encoding:如果返回None,表示使用浏览器默认的编码方式,一般为utf-8
GET:类似于字典的QueryDict对象,包含了get请求的所有参数

<QueryDict: {'csrfmiddlewaretoken': ['lq8wiEV0aG2V8oaAIhoDoY'], 'username': ['admin'], 'password': ['12345678']}>

POST:类似于字典的QueryDict对象,包含了post请求的所有参数

<QueryDict: {'csrfmiddlewaretoken': ['DsDooaE9xudwi'], 'username': ['admin'], 'password': ['12345678']}>

FILES:类似字典的对象,包含了所有上传的文件
COOKIES:字典,包含所有的cookie

{'csrftoken': '4lo5OifHLjPTwq8BC856P', 'sessionid': 'vxckxqg49ng9rphpzut7eiz6l'}

session:类似字典的对象,表示当前会话

<django.contrib.sessions.backends.db.SessionStore object at 0x1110cebe0>

META 请求的META属性

{'TMPDIR': '/var/folders/9d/myqm5ql529jcldjr250m_c3w0000gn/T/', 'XPC_FLAGS': '0x0', 'Apple_PubSub_Socket_Render': '/private/tmp/com.apple.launchd.FgJz3tuqtY/Render', 'TERM_PROGRAM_VERSION': '404', 'LANG': 'zh_CN.UTF-8', 'TERM_PROGRAM': 'Apple_Terminal', 'XPC_SERVICE_NAME': '0', 'TERM_SESSION_ID': 'AD4961D8-4215-4E56-A387-4579A6', 'SSH_AUTH_SOCK': '/private/tmp/com.apple.launchd.ABRodYSJ8C/Listeners', 'TERM': 'xterm-256color', 'SHELL': '/bin/zsh', 'HOME': '/Users/macbookpro', 'LOGNAME': 'macbook', 'USER': 'macbook', 'PATH': '/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Frameworks/Mono.framework/Versions/Current/Commands', 'SHLVL': '1', 'PWD': '/Users/macbookpro/PycharmProjects/yxx', 'OLDPWD': '/Users/macbookpro/PycharmProjects', 'ZSH': '/Users/macbookpro/.oh-my-zsh', 'PAGER': 'less', 'LESS': '-R', 'LC_CTYPE': 'zh_CN.UTF-8', 'LSCOLORS': 'Gxfxcxdxbxeged', '_': '/usr/local/bin/python3', '__CF_USER_TEXT_ENCODING': '0x1F5:0x19', '__PYVENV_LAUNCHER__': '/usr/local/Cellar/python/3.7.3/bin/python3.7', 'DJANGO_SETTINGS_MODULE': 'yxx.settings', 'TZ': 'Asia/Shanghai', 'RUN_MAIN': 'true', 'SERVER_NAME': '1.0.0.127.in-addr.arpa', 'GATEWAY_INTERFACE': 'CGI/1.1', 'SERVER_PORT': '8000', 'REMOTE_HOST': '', 'CONTENT_LENGTH': '', 'SCRIPT_NAME': '', 'SERVER_PROTOCOL': 'HTTP/1.1', 'SERVER_SOFTWARE': 'WSGIServer/0.2', 'REQUEST_METHOD': 'GET', 'PATH_INFO': '/y1/login_check', 'QUERY_STRING': 'csrfmiddlewaretoken=rUcxi8F9944cGx0KCL&username=admin&password=12345678', 'REMOTE_ADDR': '127.0.0.1', 'CONTENT_TYPE': 'text/plain', 'HTTP_HOST': '127.0.0.1:8000', 'HTTP_CONNECTION': 'keep-alive', 'HTTP_UPGRADE_INSECURE_REQUESTS': '1', 'HTTP_USER_AGENT': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36', 'HTTP_SEC_FETCH_USER': '?1', 'HTTP_ACCEPT': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9', 'HTTP_SEC_FETCH_SITE': 'same-origin', 'HTTP_SEC_FETCH_MODE': 'navigate', 'HTTP_REFERER': 'http://127.0.0.1:8000/y1/login', 'HTTP_ACCEPT_ENCODING': 'gzip, deflate, br', 'HTTP_ACCEPT_LANGUAGE': 'zh-CN,zh;q=0.9', 'HTTP_COOKIE': 'csrftoken=4lo5OifHLjPTwq8BC856PViUNR; sessionid=vxckxqg49ng9rphpzu', 'wsgi.input': <django.core.handlers.wsgi.LimitedStream object at 0x10ceafc18>, 'wsgi.errors': <_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>, 'wsgi.version': (1, 0), 'wsgi.run_once': False, 'wsgi.url_scheme': 'http', 'wsgi.multithread': True, 'wsgi.multiprocess': False, 'wsgi.file_wrapper': <class 'wsgiref.util.FileWrapper'>, 'CSRF_COOKIE': '4lo5OifHLjPTwq8BC856PViEJwo'}

3、HttpRequest类常用方法
is_ajax():如果是通过XMLHttpRequest发起的,返回 True
get_host() 当前服务器的IP和端口
get_port() 当前服务器的端口
get_full_path() 完整的访问路径
is_secure() 是否为安全的请求

QueryDict

1、request对象中的GET,POST都属于QueryDict对象
2、类似于字典,但是不同之处在于QueryDict的key可以有多个值。
4、values()
5、items()

q = QueryDict(a=1&a=5&b=2&c=3)  # 设置值
q['a']  # 取值,不存在的key会报错,如果Key对应多个值,只返回最后一个。
q.get('a', 'default') # 如果Key对应多个值,只返回最后一个。不存在的key返回null
q.getlist('a') # 返回[1, 5]

AJAX请求

1、向服务器发送异步请求,无须刷新整个页面,性能高。AJAX是在浏览器中使用Javascript技术完成的
2、jquery实现ajax请求,用JsonResponse返回响应内容

# 模板
<!DOCTYPE html>
<html lang="en">
{% load static %}
<head>
    <meta charset="UTF-8">
    <title>登录</title>
    <script src="{% static 'js/jquery-3.4.1.min.js' %}"></script>
    <script src="{% static 'js/jquery.cookie.js' %}"></script>
</head>
<body>
    <div>
        用户名:<input id='name' type = "text" name="username">
        密码:<input id='pwd' type="password" name="password">
        <input class="send_Ajax" type="button" value="登录">
    </div>
</body>
<script>
    $(function(){
        $(".send_Ajax").click(function(){
            user = $('#name').val()
            passwd = $('#pwd').val()
            $.ajax({
                url:"/y1/login_check",
                type:"POST",
                data:{'username':user,'password':passwd},
                headers:{ "X-CSRFtoken":$.cookie("csrftoken")},
                dataType:'json',
                success:function(data){
                   if(data.res ==1){
                    location.href = '/y1/index'
                   }else{
                    alert("请求失败")
                   }
               }
            })
        })
    })
</script>
</html>

# 视图
from django.shortcuts import redirect
from django.http import JsonResponse
def login(request):
    return render(request, 'y1/login.html')

def login_check(request):
    name = request.POST.get('username')
    pwd = request.POST.get('password')
    if name =='admin' and pwd=='12345678':
        data = {"res":1}
    else:
        data = {"res": 0}
    return JsonResponse(data)

3、发送ajax请求时设置async=false,可发送同步的ajax请求
4、使用AJAX请求不能重定向或者返回一个页面。

Cookie

1、cookie由服务器产生,并存储在浏览器中,用户信息都保存在某个位置的文件中。
2、通过浏览器访问网站时,会将浏览器存储的跟网站相关的所有cookie信息发送给该网站的服务器。浏览器发给服务器的cookie保存在requests.COOKIES里。
3、cookie基于域名安全性。
4、cookie有过期时间,如果不指定,关闭浏览器时cookie就会过期。
5、设置cookie信息,并通过max_age或者expires设置cookie过期时间。

hr = HttpResponse()
hr.set_cookie('num', 1,max_age=14*24*60*60)
hr.set_cookie('num', 1,expires=datetimes.now()+timedelta(14))
return hr

6、示例:

def login_check(request):
    name = request.POST.get('username')
    pwd = request.POST.get('password')
    rem = request.POST.get('rem')
    if name =='admin' and pwd=='12345678':
        data = {"res":1}
        jr = JsonResponse(data)
        if rem == 'on':
            jr.set_cookie('name',name,max_age=1*24*60*60)
        return jr
    else:
        data = {"res": 0}
        return JsonResponse(data)

Session

浏览器中只保存session id,用户的信息保存在数据库表或者其他地方。
session依赖于cookie
1、http是无状态协议;cookie存储在浏览器中,安全性不够;session是存储在服务器端的。使用session的目的就是把数据暂时存储起来,方便访问服务端的其他页面。
2、session运行机制:浏览器访问服务,服务器设置session信息并将session信息保存在服务端,同时把session id以cookie的形式发给客户端。客户端再去访问服务时会带着session id。将客户端的session id与服务端存储的session做对比,一致则可以继续请求。
3、django中使用session
(1)在setting.py 文件的MIDDLEWARE 中添加django.contrib.sessions.middleware.SessionMiddleware中间件
INSTALLED_APPS中添加 django.contrib.sessions应用
(2)在视图函数中使用session
创建或修改session:request.session[key] = value
获取session:request.session.get(key, default = None)
删除session: del request.session[key]
request.session.flush() 删除整条数据
request.session.clear() 只删除用户信息,session id 还在表中
设置有效时长:request.session.set_expiry(value) 默认有效时间是两周。
如果value是个整数,session会在些秒数后失效
如果value是个datatime或timedelta,session就会在这个时间后失效
如果value是0,用户关闭浏览器session就会失效
如果value是None,session会依赖全局session失效策略
4、cookies和session的区别
(1)cookies不管保存什么返回的都是字符串,session设置的是数值返回的就是数值。
(2)cookie支持跨域名访问。session不支持跨域名访问。
(3)假如客户端禁用了cookie,或者不支持cookie。cookie是需要客户端浏览器支持的,则会话跟踪会失效。关于WAP上的应用,常规的cookie就派不上用场了。运用session需要使用URL地址重写的方式。一切用到session程序的URL都要进行URL地址重写,否则session会话跟踪还会失效。
(4)cookie保管在客户端,不占用服务器资源。对于并发用户十分多的网站,cookie是很好的选择。session是保管在服务器端的,每个用户都会产生一个session。假如并发访问的用户十分多,会产生十分多的session,耗费大量的内存。
(5)单个cookie保存的数据<=4KB,一个站点最多保存20个Cookie。对于session来说并没有上限,但出于对服务器端的性能考虑,session内不要存放过多的东西,并且设置session删除机制。
(6)cookie的数据信息存放在客户端浏览器上。session的数据信息存放在服务器上。

redis存储session

1、pip3 install django-redis-sessions=0.5.6

2、setting文件中加配置
SESSION_ENGINE = ‘redis_sessions.session’
SESSION_REDIS = {
‘host’: ‘localhost’,
‘port’: 6379,
‘db’: 0,
‘password’: ‘’,
‘prefix’: ‘session’,
‘socket_timeout’: 1
}

3、views.py中使用session
request.session[‘user_name’]=‘user_name’ # 设置session
request.session.get(‘user_name’) # 取出session
del request.session[‘user_name’] # 删除session

URL地址重写

响应

1、django视图 一定返回HttpResponse响应对象
2、响应类在django.http.response中,包含BadHeaderError, FileResponse, Http404, HttpResponse,HttpResponseBadRequest,
HttpResponseForbidden, HttpResponseGone,
HttpResponseNotAllowed, HttpResponseNotFound, HttpResponseNotModified,
HttpResponsePermanentRedirect, HttpResponseRedirect,
HttpResponseServerError, JsonResponse, StreamingHttpResponse,

渲染

1、使用模板文件,首先需要加载模板文件,去模板目录下获取html文件的内容,得到一个模板对象;然后定义模板上下文,向模板文件传送数据;最后渲染模板,得到一个标准的HTML内容。

from django.http import HttpResponse
from django.template import loader, RequestContext

def index(request):
    # 加载模板文件, 返回一个模板对象
    temp = loader.get_template("y1/index.html")
    # 定义模板上下文,向模板传送数据,传递数据为字典格式
    context = RequestContext(request, {})
    #  渲染模板
    res_html = temp.render(context)
    #  返回模板内容
    return HttpResponse(res_html)

2、django提供了便捷渲染方法render方法,结合一个给定的模板和一个给定的上下文字典,并返回一个渲染后的 HttpResponse 对象。

from django.shortcuts import render

def index(request):
    return render(request, 'y1/index.html', {})

3、使用字典格式给模板传递参数

# 模板
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>英雄信息</title>
</head>
<body>
<h1>{{book.btitle}}--{{book.bpub_name}}</h1>
<ul>
    {%for hero in heros%}
    <li>{{hero.hname}}</li>
    {%endfor%}
</ul>
</body>
</html>

# 视图
def detail(request, bid):
    book = BookInfo.objects.get(id = bid)
    heros = book.heroinfo_set.all()
    return render(request, 'y1/detail.html', {"book":book, "heros":heros})

locals()

1、生成参数字典
2、locals()函数可直接将views中的某个函数的全部变量组合成参数字典传递给模板

重定向

1、redirect() 服务器不返回页面,而是告诉浏览器再去请求其他地址
2、示例:

# 路由
from django.conf.urls import url
from . import views

urlpatterns = [
    url('show_books', views.show_books),
    url('create', views.create_book)
]

# 视图
from django.shortcuts import render, redirect
from y1.models import BookInfo

def show_books(request):
    # 查询图书的所有信息
    books = BookInfo.objects.all()
    return render(request, 'y1/show_books.html', {"books":books})


def create_book(request):
    BookInfo.objects.create(btitle = "流行蝴蝶剑", bpub_data = "1986-09-10" ,bread=10)
    return redirect('/y1/show_books.html')

3、重定向 访问地址设置为绝对路径。
4、redirect() 是django.http.response.HttpResponseRedirect() 的简写。
5、redirect() 传参如果是一个模型,将调用模型的get_absolute_url() 函数
object = MyModel.objects.get()
return redirect(object)
6、redirect() 传参如果是一个视图,可以带有参数:将使用 url.reverse 来反向解析名称
redirect(‘some-view-name’, foo=‘bar’)
7、redirect() 默认返回一个临时的重定向;传递permanent=True 可以返回一个永久的重定向。

错误视图

1、404:页面找不到, debug = True, 调试模式。请求不存在的页面,页面会显示代码错误信息。设置debug = False 关闭调试模式,请求不存在的页面,页面会显示标准的错误信息,如果不想使用django自带的404页面,则在template目录下新建一个404.html页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>404页面</title>
</head>
<body>
    页面不存在--{{request_path}}
</body>
</html>

request_path 会返回请求的地址
2、500:服务器端错误
同样可定义500.html页面

1、get_object_or_404(klass, *args, **kwargs)
在一个给定的模型管理器上调用get(),但是引发Http404 而不是模型的DoesNotExist 异常。
2、接收Model类
my_object = get_object_or_404(MyModel, pk=1)
3、接收QuerySet实例
queryset = Book.objects.filter(title__startswith=‘M’)
get_object_or_404(queryset, pk=1)

4.get_list_or_404(klass, *args, **kwargs)
返回一个给定模型管理器上filter() 的结果,并将结果映射为一个列表,如果结果为空则返回Http404。

捕获URL参数

1、位置参数

# 定义一个正则表达式组(\b+)
url('books/(\d+)', views.detail)
# 视图函数中必须加对应的参数
def detail(request, did)

2、关键字参数

# 定义一个正则表达式组,并命名(?P<did>\b+)
url('books/(\d+)', views.detail)
# 视图函数中必须加对应的参数,参数名必须和正则表达值中的命名相同
def detail(request, did)

路由

1、作用:配置url及视图间的映射关系
2、执行django-admin.py startproject时会自动生成 项目的urls.py及项目的settings.py文件,在setting.py文件中变量ROOT_URLCONF的值为项目urls模块
ROOT_URLCONF = ‘项目名.urls’
3、urls.py文件中存放一个urlpatterns列表,列表中每个元素包含路径、视图函数、字典参数、别名等
4、当接收到用户请求时,会遍历urlpatterns列表,发现匹配项后调取对应的视图函数,如果没有找到则返回404错误
5、url配置方法
(1)导入视图

from django.conf.urls import url
from . import views

urlpatterns = [
    url('index', views.index),
    url('show_books', views.show_books),
    url('books/(\d+)', views.detail),
]

(2)视图处理方法

urlpatterns = [
				url(r'^nowamagic/',  'blog.views.index')       
]

(3)视图写在前缀里

urlpatterns = patterns(
				'blog.views', url(r'^nowamagic/',  'index')       
)

(4)带参数且指定参数类型

urlpatterns = [
	path('articles/<int:year>/', views.year_archive)
	]

(5)正则表达式组

urlpatterns = [
re_path(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive)
]

re_path(r’^comments/(?:page-(?P<page_number>\d+)/)?$’, comments)
5、可以在每个应用app中单独创建urls.py文件,需在项目的urls.py中使用include()填加应用的urls

from django.contrib import admin
from django.urls import path, include

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

URL反向解析

1、模板中使用反向解析
{% url ‘index’%}


<body>
    <a href="{% url 'index'%}">url 反转</a>
</body>
urlpatterns = [
    url('index/', views.index, name = 'index'),
]

或者:{% url ‘app:index’%}

<body>
    <a href="{% url 'app:index'%}">url 反转</a>
</body>
#urls.py
urlpatterns = [
    url('app/', include('app.urls', namespace='app'))
]
# app urls.py
app_name='[app]'
urlpatterns = [
    url('index/', views.index, name = 'index')
]

带位置参数:{% url ‘app:index’ 1 2 %}

url('index/(\d+)/(\d+)/', views.index, name = 'index'),
<body>
    <a href="{% url 'app:index' 1 2 %}">url 反转</a>
</body>

带关键字参数:{% url ‘app:index’ c=1 d=2 %}

<a href="{% url 'app:index' c=1 d=2 %}">url 反转</a>
app_name='[app]'
urlpatterns = [
    url('index/(?P<c>\d+)/(?P<d>\d+)/', views.index, name = 'index'),
]

2、视图中使用反向解析
不带参数:

def url_reverse(request):
    return redirect(reverse('app:index'))

位置参数:

def url_reverse(request):
    return redirect(reverse('app:index', args=(1, 2)))

关键字参数:

from django.urls import reverse
def url_reverse(request):
    return redirect(reverse('app:index', kwargs={"c":1, "d":2}))

应用配置

1、常见配置
1)DEBUG=True,打开调试模式,项目发布后需改为False,否则当地址输入错误时会将错误信息显示在前端。
2)ALLOWED_HOSTS=[] ,允许哪些IP地址访问网站。 当DEBUG改为False,一定要设置ALLOWED_HOSTS,允许所有就写[’*’]
3)INSTALLED_APPS,注册应用,建立项目和应用之间的关系
4)MIDDLEWARE中间件
5)ROOT_URLCONF 指定根路由,默认为项目的urls.py文件路径
6)TEMPLATES 模板
DIRS : 默认访问每个APP下的templates
7)WSGI_APPLICATION
9)STATIC_URL = ‘/static/’ 访问静态文件的路径以static开头
10)STATICFILES_DIRS = (
os.path.join(BASE_DIR, ‘static’),
) 默认访问每个app下的static文件
11)MEDIA_URL=“” 开启文件服务器的配置
2、在manage.py 文件中 设置默认的配置文件
import os
os.environ.setdefault(“DJANGO_SETTINGS_MODULE”, “djblog.settings”)

CORS

模板文件

1、在django中使用模板,首先现在项目文件夹下创建模板文件夹,用来存放模板;然后在setting.py文件中配置模板目录TEMPLATES;最后定义模板并使用。

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BISE_DIR, 'templates')],  #设置模板目录
    
    },
]

2、为了区分不同应用的模板,在templates文件夹下建立与应用同名的文件夹存放对应应用的模板。
3、在模板中定义链接时,建议使用绝对路径

<a href="/y1/create">新增图书</a>

4、加载模板时,先在TEMPLATES指定的模板路径下查找文件,然后在INSTALLED_APPS的模板文件夹下查找文件。
5、模板文件包含两部分内容,一种动态内容,一种静态内容。动态内容通过模板语言来产生,静态内容css,js,html
6、

<form method="post" enctype="multipart/form-data" action="/app/shangchuan/">
    {% csrf_token%}
    <input type="file" name="pic"><br>
    <input type="submit" value="上传"><br>
</form>

提交表单报错:RuntimeError: You called this URL via POST, but the URL doesn’t end in a slash and you have A,提示form的action地址最后不是/结尾的,而且APPEND_SLASH的值是Ture
将from的action地址改为/结尾的就可以了或者修改settings:APPEND_SLASH=False

模板语言

模板语言简称DTL

模板变量

1、模板变量由数字、下划线、点、字母组成,不能以下划线开头,使用模板变量 {{book.btitle}}
2、模板变量的解析顺序:
例如: {{book.btitle}}
(1)先把book当成字典,btitle当成key取值book[btitle]
(2) 然后把book当成对象,btitle当成属性取值book.btitle
(3) book当成对象,btitle当成对象的方法取值book.btitle
{{book.0}}
(1)先把book当成字典,0当成key取值book[‘0’]
(2)把book当成列表,0当成下标取值book[0]
如果解析失败用空字符串填充模板变量
3、示例
在模板中使用{{变量名}}定义变量,渲染时使用字典格式传递变量值

# 模板
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>模板使用</title>
</head>
<body>
    {{context}}
</body>
</html>

# 视图函数
from django.shortcuts import render

def index(request):
    # 加载模板文件, 返回一个模板对象
    return render(request, 'y1/index.html', {"context":"你好,老铁!"})

模板标签

1、{% for i in list%}
{% empty %}
{{ forloop.counter }} 显示循环了多少次
{% endfor %}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>模板使用</title>
</head>
<body>
<ul>
    {% for i in temp_list%}
        <li>{{i}}---{{  forloop.counter }}</li>>
    {%endfor%}
</ul>
</body>
</html>

2、条件判断
{% if s%}
{% elif b %}
{% else %}
{% endif %}
条件中可用比较运算符> < >= <= == !=,进行比较操作时,操作符两边必须有空格 。可用逻辑运算符 and not or
3、多行注释
{% comment %}
{% endcomment %}
4、{% extends ‘app/base.html’%} 继承模板
5、{% block title %} {% endblock title%} 父模板预留块,子模板重写块的内容
6、{% autoescape off %}
{% endautoescape %} 关闭模板转义

{% csrf_token %}
{% url %}
{% static %}
{% load static %}

模板变量过滤器

过滤器用于对模板变量进行操作。使用格式 {{ 模板变量 | 过滤器:参数 }}
date :"Y年"可用改变日期的显示格式
length 求字符串、列表等的长度
default:“默认值” 设置模板变量的默认值
safe: 关闭模板转义

自定义过滤器

1、步骤:
(1)在应用文件夹下创建templatetags文件夹,文件名必须是templatetags
(2)新建filter.py文件,定义过滤函数

# 自定义过滤器,过滤器本质就是一个函数
from django.template import Library

#创建一个对象
register = Library()

@register.filter
def mod(num):
    # 判断是否为偶数
    return num%2 == 0

(3)在模板中使用{% load filter%}
(4)使用 {{ if book.id | mod }}
2、自定义过滤器至少有一个参数,最多有两个

模板注释

1、单行注释
{# #}
2、多行注释
{% comment %}
{% endcomment %}
网页源码看不到模板注释的内容,但能看到html注释的内容

模板继承

1、子模板继承父模板{% extends ‘app/base.html’%}
2、{% block title %} {% endblock title%} 父模板预留块,子模板重写 块的内容
3、{{ block.super }} 可获取父模板中的内容

模板转义

1、render(request , {"content":"<h1>sdsd</h1>"}) 在前端会直接显示<h1>sdsd</h1>,是因为模板自动进行了转义。
2、关闭模板转义可以使用{{ 模板变量| safe }}
也可以使用
{% autoescape on|off %}
{% endautoescape %}

静态文件

1、在项目目录下创建static文件夹,并在setting.py文件中设置静态访问文件路径,及访问

STATIC_URL = '/static/'  设置访问静态文件对应的url地址,以static开头的请求被认为是静态文件

STATICFILES_DIRS = [os.path.join(BASE_DIR, ‘static’)] 设置静态文件的物理目录

显示图片

{% load static %}
<img src='/static/image/a.jps/'>
或者
<img src='{% static image/a.jps %}'>

在模板header中引入js

{% load static %}
<script src="{% static 'js/jquery-3.4.1.min.js' %}"></script>

2、.js .css image等都存放在静态文件目录下
3、django加载静态文件是通过中间件加载的,中间件可通过from django.conf import settings 查看

登录装饰器

def login_required(view_func):
    def wrapper(request, *view_args, **view_kwargs):
        if request.session.has_key('islogin'):
            return view_func(request, *view_args, **view_kwargs)
        else:
            return redirect('/login')
    return wrapper

CSRF

1、跨站请求伪造(CSRF)攻击原理:
用户访问网址A,浏览器保存了网站A的cookies。用户在该浏览器上打开网站B,但是网站B隐藏了访问网站A的链接,网站B可使用浏览器保存的网站A的cookies更改或查看网站A的信息
2、CSRF防范措施:
网站A指定表单或者请求头的里面添加随机值参数,在接口响应的cookies中也添加随机值参数,服务器收到请求后,对比两个参数的值,如果两边的随机值相等,则可继续请求。而网站B并不知道随机值是多少,所以请求会失败
3、启动防跨站请求伪造功能的方法
全局设置:在setting.py文件中MIDDLEWARE添加中间件django.middleware.csrf.CsrfViewMiddleware
局部设置:
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt,csrf_protect
(1)如果是函数视图@csrf_protect;如果是类视图@method_decorator(csrf_exempt)
为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。
如果是函数视图@csrf_exempt;如果是类视图@method_decorator(csrf_exempt)
取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。
(2)在URLconf里使用as_view()方式。
from django.views.decorators.csrf import csrf_exempt,csrf_protect
urlpatterns = [
path(‘login/’, csrf_exempt(LoginView.as_view()),name=“login”),
]

4、提交csrftoken的方法:
第一种(form表单提交):在form表单里添加{%csrf_token%},这样在查看页面源码的时候会看到form中有一个input是隐藏的。当用户提交这个表单前会自动生成一个csrf随机字符串,并将这个随机字符串存放到cookie中,当用户再次提交提交表单时会带着这个随机字符串,如果没有这个随机字符串则无法提交。
在这里插入图片描述
第二种:通过在ajax请求的请求头里设置csrf
使用cookie,得先讲jquery.cookie.js放到静态文件夹下,然后在模板中引入

# 模板
<script src="{% static 'js/jquery-3.4.1.min.js' %}"></script>
<script src="{% static 'js/jquery.cookie.js' %}"></script>

<input class="send_Ajax" type="submit" value="登录">

<script>
    $(function(){
        $(".send_Ajax").click(function(){
            $.ajax({
                url:"/y1/login_check",
                type:"POST",
                data:{username:"admin",password:"12345678"},
                headers:{ "X-CSRFtoken":$.cookie("csrftoken")},
                dataType:'json',
                success:function(data){
                   alert(data.name)
               }
            })
        })
    })
</script>

5、csrf在前端的key为:X-CSRFtoken,到后端的时候django会自动添加HTTP_,并且最后为HTTP_X_CSRFtoken

验证码

在注册、登录页面为了防止暴力请求,添加验证码功能。如果验证码错误,则不处理业务。可以减轻业务服务器、数据库服务器压力。

WSGI

1、Django不是完整的web后端框架,它只负责WSGI应用开发。在生产环境中Django应该与一个WSGI服务器配套,由WSGI服务器负责网络通信部分。WSGI是为Python 语言定义的Web服务器和应用程序间的一种简单的网络通信接口。
在这里插入图片描述
2、WSGI允许开发者选择将web服务器和web框架分开,可以混合匹配web服务器和web框架。

2、django创建WSGI应用对象很简单,这通过调用get_wsgi_application()函数来完成。 这个对象用来与WSGI服务器对接:

from django.core.wsgi import get_wsgi_application
wsgi_app = get_wsgi_application()

3、由于django框架严重依赖于一个全局配置对象settings来定制 其行为,因此,我们需要在创建WSGI应用对象之前,首先使用默认值初始化这个全局 配置对象:

from django.conf import settings
settings.configure()

中间件

1、django中间件是django给我们预留的函数接口,让我们可以干预请求或者应答。
2、获取浏览器IP地址 request.META[‘REMOTE_ADDR’]
3、使用中间件文件,在应用目录下新建middleware.py文件,并在文件中定义process_view函数。process_view是django预留的函数,会在调用视图前调用这个函数。最后需要在配置文件中注册这个函数。

from django.http import HttpResponse

class BlockedIPMiddleware(object):
	EXCLUDE_IPS = ['172.16.179.152']
    # 函数名是固定的,不可修改
    def process_view(request, view_func, *view_args, **view_kwargs):
        '''视图函数调用之前调用'''
        user_ip = request.META['REMOTE_ADDR']
        if user_ip in EXCLUDE_IPS:
            return HttpResponse("不可访问")
        else:
            return view_func(request, *view_args, **view_kwargs)
# 注册函数
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',	
    'app.middleware.BlockedIPMiddleware'
]

4、django预留的中间件函数
process_request:在产生request,调用url配置之前调用
process_view :在调用url配置,使用视图函数之前调用
process_response :视图函数调用之后,返回浏览器数据之前调用
process_exception:产生异常时调用
5、中间件调用顺序
在这里插入图片描述

上传图片

1、上传图片 , 首先在static文件夹下新建上传文件目录media;然后在配置文件中配置ERDIA_ROOT = os.path.join(BASE_DIR, ‘static/media’)
2、上传图片方法有两种,一种是在后台管理页面上传,另一种是用户自定义页面上传图片
3、后台管理页面上传图片
(1)设置模型类

Class PictTest(models.Model):
	# upload_to保存上传图片的文件目录,这个目录是相对于media的
	# ImageField可对上传图片做校验
	gpic = models.ImageField(upload_to=‘app’) 

(2)生成迁移数据库表
(3)注册模块

admin.register(PictTest)

(4)登录/admin上传图片

4、自定义页面上传图片
request 对象有一个FILES的属性,类似于字典,通过request.FILES可以获取上传文件的处理对象。
django返回两种上传文件处理器, 这个和上传图片的大小有关。如果图片小于2.5m,文件放在内存中,否则存放在临时文件中。

FILE_UPLOAD_HANDLERS ={
‘django.core.files.uploadedfile.InMemoryUploadedFile’,
‘django.core.files.uploadedfile.TemporaryFileUploadedFile’
}

# 模板
<form method="post" enctype="multipart/form-data" action="/app/shangchuan/">
    {% csrf_token%}
    <input type="file" name="pic"><br>
    <input type="submit" value="上传"><br>
</form>

# 上传图片
def uplode_file(request):
    # 1.获取上传图片,返回的是一个文件对象
    pic = request.FILES['pic']

    # 2.创建一个文件
    #pic.name可以获得上传图片的名字,WechatIMG162.jpeg
    save_path = 'app/%s/%s' %(settings.ERDIA_ROOT(),pic.name)
    with open(save_path, 'wb') as f:
    
        # 3.获取上传文件的内容并写到创建的文件中
        # pic.chunks() 的返回值是生成器,可遍历读取文件的内容
        for context in pic.chunks():
            f.write(context)

    # 4. 在数据库中保存上传记录
    PicTest.objects.create(goods_pic= save_path)

    # 5. 返回响应
    return HttpResponse('ok')

文件服务器

django自带一个文件服务器
serve() 视图可以用来作为任意目录的服务器。
static.serve(request, path, document_root, show_indexes=False)

分页

Django部署

nginx + uwsgi socket 的方式来部署 Django
Nginx (engine x) 高性能的http服务器及反向代理服务器
uWSGI是一个Web服务器,它实现了WSGI协议、uwsgi、http等协议。Nginx中HttpUwsgiModule的作用是与uWSGI服务器进行交换。
WSGI是一种通信协议。
uwsgi是一种线路协议而不是通信协议,在此常用于在uWSGI服务器与其他网络服务器的数据通信。
而uWSGI是实现了uwsgi和WSGI两种协议的Web服务器。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值