Django笔记
一、开始
1.安装
pip install Django==3.2.7
pip install pymysql==1.0.2
pip install channels==2.1.7
pip install channels_redis==2.3.3
pip install pillow==3.0.4
pip uninstall django
2.创建
- 创建工程和app
django-admin startproject projectName
django-admin startapp app
- 注册app
#
INSTALLED_APPS = [
...
'django.contrib.staticfiles',
'loginApp',
]
二、路由系统
1.路由与分发
- 一对一
url(r'index/',view.index)
url(r'home/',view.Home.as_view())
- 一对多路由
# 方法1
url(r'detail-(\d+).html',view.detail)
def detail(request,mid):
detail_info = MDICT['mid']
return TemplateResponse(request,'myapp2/madd.html',detail_info)
#方法2
url(r'detail-(?P<nid>\d+)-(?P<uid>\d+).html',view.detail)
def detail(request,**kwargs):
kwargs = {'nid':1,'uid':2}
def detail(request,*args):
args = (2,9)
<li><a href="/detail-{{ mid }}.html">{{ row.name }}</a></li>
- 路由器分发
#一级路由
from django.contrib import admin
from django.urls import path,include
from appAuthentication import urls as auth_urls
from appDataDisplay import urls as display_urls
urlpatterns = [
path('admin/', admin.site.urls),
path('auth/',include((auth_urls,'auth_np'),namespace='auth_np')),
path('display/',include((display_urls,'display_np'),namespace='display_np')),
]
#二级路由
from django.urls import path
from appAuthentication import views
# app_name = 'loginApp'
urlpatterns = [
path('index.html',views.index,name='index'),
]
2.路由地址生成(模板生成)
-
单条路由生成
- 方法1
url(r'asdgasgasgd/',view.index,name='indexx')<form action="{% url 'indexx' %}" method="POST"> ... </form>- 方法2
def index(request,nid): print(request.path_info) #当前路由地址,可用于获取动态的地址 ... -
命名空间路由生成
# 工程.urls.py
from django.conf.urls import url,include
urlpatterns = [
url(r'^a/', include('app01.urls', namespace='author-polls')),
url(r'^b/', include('app01.urls', namespace='publisher-polls')),
]
# app.urls.py
from django.conf.urls import url
from app01 import views
app_name = 'app01'
urlpatterns = [
url(r'^(?P<pk>\d+)/$', views.detail, name='detail')
]
# app.views.py
def detail(request, pk):
print(request.resolver_match)
return HttpResponse(pk)
# name的使用方法需调整
from django.urls import reverse
v = reverse('app01:detail', kwargs={'pk':11})
{% url 'app01:detail' pk=12 pp=99 %}
三、视图
1.用户请求
if request.method == "GET": # 获取请求类型
request.GET.get('name') # 获取get数据
...
elif request.method == "POST":
request.POST.get('name') # 获取post数据
request.POST.getlist('name') # 获取post数据,checkbox或多选内容!
request.FILES.get('name') # 获取文件数据,具体操作在后面
request.environ.items() # 封装了用户所有信息
request.environ['HTTP_USER_AGENT'] # 请求头,判断是手机端还是客户端
...
2.COOKIE和SESSION
- cookie
# cookie中不设置超时时间,则表示关闭浏览器自动清除
# 设置 cookie:
rep = HttpResponse || render || redirect
rep['name'] = 'sjl' # 添加响应头
rep.set_cookie(key,value,...)
rep.set_signed_cookie(key,value,salt='加密盐',...) # cookie加密
# 获取 cookie:
request.COOKIES.get(key)
# 删除 cookie:
rep.delete_cookie(key)
- session
#session 设置:
request.session["key"] = value
request.session.setdefault('key',123) #存在则不设置
# session 获取:
request..get('key')
# session删除
del request.session["is_login"] # 删除session_data里的一组键值对
request.session.flush() # 删除一条记录包括(session_key session_data expire_date)三个字段
request.session.delete('session_key')# 删除当前用户的所有Session数据
request.session.clear() # 注销,然后删除当前用户全部session数据
#用户session的随机字符串
request.session.session_key
#将单个用户session失效日期小于当前日期的数据删除
request.session.clear_expired()
# 检查用户session的随机字符串 在数据库中是否存在
request.session.exists('session_key')
# 如果value是个整数,session会在这些秒数后失效
# 如果value是个datetime或者timedelta,session就会在这个时间后失效
# 如果value是0,用户关闭浏览器时失效
# 如果value是None,session会依赖全局session失效策略
request.session.set_expiry(value)
SESSION_SAVE_EVERY_REQUEST = True
- 全局session设置
#setting.py中设置session的默认选项(通用配置)
SESSION_SAVE_EVERY_REQUEST = False # 每次请求是否都会重置时效时间
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期
SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)
SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输
SESSION_COOKIE_SECURE = False # 是否Http传输cookie
SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名
SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径
SESSION_COOKIE_PATH = "sessionid" # Session的cookie保存到浏览器的键值对键名
# Session数据默认放到数据库中
SESSION_ENGINE = 'django.contrib.sessions.backends.db'
# 缓存
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
SESSION_CACHE_ALIAS = 'default'
# 文件
SESSION_ENGINE = 'django.contrib.sessions.backends.file'
SESSION_FILE_PATH = os.path.join(BASE_DIR,'session_cache') #创建一个session_cache文件,将session放入其中
# 缓存+数据库
SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'
# 加密cookie session
SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'
3.基本方法
-
FBV(function base view)、CBV(class base view)
url(r'home/',view.Home.as_view()) #CBV from django.views import View class Home(View): def dispatch(selft,request,*args,**kwargs): print('before') result = super(Home,self).dispatch(request,*args,**kwargs) print('after') return result def get(self,request): pass def post(self,request): pass #FBV def home_index(request): pass -
给浏览器返回数据
from django.http import HttpResponse,HttpResponseRedirect,JsonResponse
from django.shortcuts import render,redirect
from django.views.decorators.csrf import csrf_exempt
from django.template.response import TemplateResponse
#老
render(request,"模板文件的路径",字典)
redirect("url") #跳转到另外一个页面
#新
HttpResponse("字符串")
HttpResponseRedirect('url')#跳转到另外一个页面
TemplateResponse(request,"模板文件的路径",字典)
SimpleTemplateResponse('foo.html', 'path/to/bar.html')
- 用户认证
def auth_is_login(func):
def warpper(request, *args, **kwargs):
if not request.session.get('username'):
return redirect('/auth/login.html')
return warpper
# FBV
@auth_is_login
def index(request):
pass
# CBV
from django views
from django.utils.decorators import method_decorator
@method_decorator(auth_is_login,name='dispatch')
class Order(View.view):
def get(self,request):
pass
def post(self,request):
pass
四、数据库
1.配置数据库
- 在数据库中创建一个数据库
create database mydb default charset=utf8;
- 配置项目settings.py文件
DATABASES = {
'default':
{
'ENGINE': 'django.db.backends.mysql', # 数据库引擎
'NAME': 'mydb', # 数据库名称
'HOST': '127.0.0.1', # 数据库地址,本机 ip 地址 127.0.0.1
'PORT': 3306, # 端口
'USER': 'root', # 数据库用户名
'PASSWORD': 'root', # 数据库密码
}
}
INSTALLED_APPS = [
...
'loginApp',
]
- 在与settings.py同目录下的_init_.py进行配置
# Django默认是用的MySQLdb模块连接MYSQL,主动改为pymysql
import pymysql
pymysql.install_as_MySQLdb()
2.创建模型
- 创建app
django-admin.py startapp myModelapp
- 创建表
class Person(models.Model):
SEX_CHOICES = (
( 0 , '男'),
( 1 , '女')
)
# id列,自增,主键
name = models.CharField(max_length=32)
age = models.IntegerField()
sex = models.BooleanField(choices=SEX_CHOICES)
id_card = models.CharField(max_length=18)
addr = models.CharField(max_length=255,null=True) #可以为空
temp = models.FloatField()
class Meta:
#db_table = 'M_Major' #指明数据库表名
verbose_name = '专业表' #指明admin显示名称
#外键的关键字段,将对象转换成字符时调用
def __str__(self):
return self.major_name
# DateField,日期类型date
# DateTimeField,日期类型datetime
# TimeField 时间 HH:MM[:ss[.uuuuu]]
# AutoField(primary_key=True)主键
"""
字段:
字符串类型
数字
时间
二进制
字段参数
null=True 是否可以为空
default=143 默认值
primary_key=True 主键
db_column=’cn‘ 表的当前列列名
db_index=True 索引
unique=True 唯一索引
unique_for_date 只对日做索引
unique_for_month 只对月做索引
unique_for_year 只对年做索引
auto_now 创建时,自动生成时间
auto_now_add 更新时,自动更新为当前时间
choices django admin下拉选择
blank django admin是否为空
verbose_name django admin显示字段为中文
editable django admin是否可以被编辑
error_messages django admin错误提示信息
help_text django admin提示
validators django form/admin自定义错误信息
"""
- 外键创建
class Major(models.Model):
name = models.CharField(max_length=30,verbose_name = '专业名称')
college_id = models.ForeignKey(to="College",on_delete=models.CASCADE,verbose_name = '学院id号')
class College(models.Model):
name = models.CharField(max_length=30,verbose_name = '学院名称')
#(uid = models.AutoField(primary_key=True) --> to_field='uid')
- 多对多
#自定义关系表
class Host(models.Model):
hostname = models.CharField(max_length=32,db_index=True)
ip = models.GenericIPAddressField(protocol="ipv4",db_index=True)
port = models.IntegerField()
class Application(models.Model):
name = models.CharField(max_length=32)
class HostToApp(models.Model):
hobj = modeels.ForeignKey(to='Host',to_field='id')
aobj = modeels.ForeignKey(to='Application',to_field='id')
#自动创建关系表(无法直接操作第三张表,通过Application来操作)
class Host(models.Model):
hostname = models.CharField(max_length=32,db_index=True)
ip = models.GenericIPAddressField(protocol="ipv4",db_index=True)
port = models.IntegerField()
class Application(models.Model):
name = models.CharField(max_length=32)
r = models.ManyToManyField('Host')
obj = models.Application.objects.create(name=app_name)
#增删改
obj.r.add(2)
obj.r.add(2,3)
obj.r.add(*host_list) #host_list是一个列表
obj.r.remove(..)
obj.r.clear()
obj.r.set([1,2,3,55]) #交集,有就保存,没有就删除
#查
obj.r.all() #全部,多个组
obj.r.filter(name='CTO') #筛选
- 创建数据库
# 让 Django 知道我们在我们的模型有一些变更,生成迁移文件
python manage.py makemigrations loginApp
# 创建表结构,执行迁移文件
python manage.py migrate loginApp
#大型改动需要删除数据库表和app目录下migrations目录下的文件c
3.数据库操作
- 添加数据
#111111
test1 = models.Person(name='李四',
age=19,
sex=1,
id_card='438726200008142097',
addr='长沙',
temp=36.6)
test1.save()
#222222
models.Person.objects.create(title="如来神掌",
price=200,
publish="功夫出版社",
pub_date="2010-10-10")
#3333333
dic = {'title':"如来神掌",'price':200,'publish':"功夫出版社"}
models.Person.objects.create(dic)
#外键插入1,需要两次数据库查询
pub_obj = models.Publish.objects.filter(pk=1).first()
book = models.Book.objects.create(title="菜鸟教程", price=200, pub_date="2010-10-10", publish=pub_obj)
#外键插入2(外键字段_id=id值)
book = models.Book.objects.create(title="菜鸟教程", price=200, pub_date="2010-10-10", publish_id=12)
- 查找数据
# 通过objects这个模型管理器的all()获得所有数据行,相当于SQL中的SELECT * FROM
result = Person.objects.all()
#result,QuerySet => Django => [obj(title,price),obj...]
# 获取单个对象
response3 = Person.objects.get(id=1)
# filter相当于SQL中的WHERE,可设置条件过滤结果
response2 = Person.objects.filter(id=1)
# 查询价格大于200的数据
books = models.Book.objects.filter(price__gt=200)
# 查询价格小于300的数据
books=models.Book.objects.filter(price__lt=300)
# 查询价格在200到300之间的数据
books=models.Book.objects.filter(price__range=[200,300])
# 查询包含"菜"的数据
books=models.Book.objects.filter(title__contains="菜")
# 查询包含"python"的数据(不区分大小写)
books=models.Book.objects.filter(title__icontains="python")
# 查询以指定字符开头的数据
books=models.Book.objects.filter(title__startswith="菜")
# 查询以指定字符结尾的数据
books=models.Book.objects.filter(title__endswith="教程")
# 查询DateField 数据类型的年份
books=models.Book.objects.filter(pub_date__year=2008)
# 查询DateField 数据类型的月份
books=models.Book.objects.filter(pub_date__month=10)
# 查询DateField 数据类型的日
books=models.Book.objects.filter(pub_date__day=01)
# 数据排序
Person.objects.order_by("id")
# 限制返回的数据 相当于 SQL 中的 OFFSET 0 LIMIT 2;
Person.objects.order_by('name')[0:2]
# 上面的方法可以连锁使用
Person.objects.filter(name="runoob").order_by("id")
# 查询所有数据的数量
models.Book.objects.count()
# 返回所有数据的第一条数据
books = models.Book.objects.first()
# 返回所有数据的最后一条数据
books = models.Book.objects.last()
# 判断的数据QuerySet中是否有数据
books = models.Book.objects.exists()
# 查询所有的id字段和price字段的数据
books = models.Book.objects.values("pk","price")
books = models.Book.objects.values_list("price","publish")
# 对数据进行去重
books = models.Book.objects.values_list("publish").distinct()
#Book: title="菜鸟教程", price=200, pub_date="2010-10-10", publish=pub_obj
# 跨表查询1(对象)
book = Book.objects.all()
book.first().publish_id.title
# 跨表查询2(字典),模板里面也可以用双下划线!!!
book = Book.objects.filter(id__gt=0).values('id','price','publish_id','publish__title')
# 跨表查询3(元组)
book = Book.objects.filter(id__gt=0).values_list('id','price','publish_id','publish__title')
- 删除数据
books = models.Book.objects.filter(pk=8).first().delete()
books = models.Book.objects.filter(pk__in=[1,2]).delete()
- 修改数据
books = models.Book.objects.filter(pk=7).first()
books.price = 400
books.save()
books = models.Book.objects.filter(pk__in=[7,8]).update(price=888)
- 外键的关键字段
def __str__(self):
return self.major_name
4.admin后台管理页面
# 创建管理员账户和密码
python manage.py createsuperuser
# 在app下admin.py文件中添加注册
from .models import Student,College,Major
# Register your models here.
admin.site.register(Student)
admin.site.register(College)
admin.site.register(Major)
五、模板
- view中传递方法
def func(request):
content['name'] = "我是名字"
content['dict'] = {"name":"6666"}
content['list'] = ["我是数据1","我是数据2","我是数据3"]
return TemplateResponse(request,"runoob.html", content)
- 常用方法
<h1>{{ hello }}</h1>
<h1>{{ dict.name }}</h1>
{% if condition1 %}
... display 1
{% elif condition2 %}
... display 2
{% else %}
... display 3
{% endif %}
{% for i in views_list %}
{{ forloop.parentloop }} {# 查看循环信息 #}
{{ forloop.counter }} {# 循环信息之一——计数 #}
{{ i }}
{% endfor %}
{% if x > 0 %}
<h2>{{ x }}是大于0的</h2>
{% elif x == 0%}
<h3>{{ x }}是等于0的</h3>
{%elif x < 0 %}
<h4>{{ x }}是小于0的</h4>
{% endif %}
{{ str|safe }} {# 这个字符串是安全的,不需要转义,可以直接执行 #}
{{ item.event_start|date:"Y-m-d H:i:s" }} {# 时间 #}
{{ str|truncatewords:"30" }} {# 取前30个字符 #}
{{ name|lower }} {# 字符串转小写 #}
- 自定义方法(simple_tag,filter)
# templatetags/xxoo.py
# 目录的名字必须是templatetags,在app目录下,不能改!!!
from django import template
from django.utils.safestring import mark_safe
register = template.Library()
#可以随意传参数
@register.simple_tag
def myfun(a1,a2):
return a1 + a2
#只能传2个参数
@register.filter
def myfun2(a1,a2):
return a1 + a2
{# a.html templates文件 #}
{% load xxoo %}
{% myfun 2 5 %}
{{ "666"|myfun2:"999"}}
{% if "666"|myfun2:"999" %}
...
{% endif %}
- 模板继承
{% extends "母板路径"%}
{% block 名称 %}
预留给子模板的区域,可以设置设置默认内容
{% endblock 名称 %}
- 模板包含
{% include "tag.html" %}
- 模板加载路径设置
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR,'templates')], #自定义模板路径app/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',
],
},
},
]
- 静态文件
# 在工程的更目录下建立static文件夹,然后把建立js,css等等文件夹,把文件放入
# 在setting.py文件中加入以下代码
import os
STATIC_URL = '/static/'
STATICFILES_DIRS=(
os.path.join(BASE_DIR,'static').replace('\\','/'),
)
#在html使用静态文件
{% load static %}
<script src="{% static 'js/jquery.js' %}"></script>
- 分页
# view.py
def index(request):
notices = models.Notice.objects.all().order_by('-pub_time')
paginator = Paginator(notices,10) #创建分页器,10条为一页
num_p = request.GET.get('page',1) # 以page为键得到默认的页面1
page = paginator.page(int(num_p)) #找到第一个页面
return TemplateResponse(request,'a.html',locals())
<!--a.html-->
{% for p in page %}
<div class="item">
<h2>{{ p.title }}</h2>
<p>{{ p.content }}</p>
</div>
<hr/>
{% endfor %}
<!--判断是否有上一页,然后拼接关于page的查询字符串-->
{% if page.has_previous %}
{# 得到上一页的页码编号 #}
<a href="/loginApp/thrindex.html?page={{ page.previous_page_number }}">上一页</a>
{% else %}
上一页
{% endif %}
{# 在页面范围内循环选择一个页面号码 #}
{% for p in paginator.page_range %}
{# 如果页面编号等于当前页码序号 #}
{% if p == page.number %}
{{ p }}
{% else %}
{# 否则跳转到页码相对应的页面 #}
<a href="/loginApp/thrindex.html?page={{ p }}">{{ p }}</a>
{% endif %}
{% endfor %}
{% if page.has_next %}
<a href="/loginApp/thrindex.html?page={{ page.next_page_number }}">下一页</a>
{% else %}
下一页
{% endif %}
六、高级操作
1.csrf
- 开启
#setting.py
'django.middleware.csrf.CsrfViewMiddleware', #开启中间件csrf
- 表单引用组件
<form>
{# 表单提交生成一个隐藏带值的控件 #}
{% csrf_token %}
</form>
- ajax引用组件
<script>
$.ajaxSetup({
//在所有ajax请求之前执行的代码
beforeSend:function(xhr,settings){
//xhr:XMLHttpRequest
//setting:当前点的ajax的所有配置
xhr.setRequestHeader('X-CSRFtoken',$.cookie('csrftoken')) //把csrftoken的cookie加入头
}
})
$('.cal').click(function(){
$.ajax({
url:'/login/',
type:'POST',
data:{
'a1':$('.a1').val(),
'a2':$('.a2').val()
},
success:function(data){
$('.a3').val(data);
#location.reload();
}
})
});
</script>
- view中操作
# 有csrf过滤
def add(request):
if request.method == 'POST':
a = request.POST.get('a1')
b = request.POST.get('a2')
c = int(a) + int(b)
return HttpResponse(c)
elif request.method == 'GET':
# return HttpResponse('我是get请求')
return TemplateResponse(request,'myapp2/madd.html')
# 取消当前函数防止跨站请求伪造功能
@csrf_exempt
def add(request):
pass
# 为当前函数强制设置跨站请求伪造功能
@csrf_exempt
def add(request):
pass
- csrf配置
CSRF_COOKIE_AGE #cookie的有效期
CSRF_COOKIE_DOMAIN #允许访问的域名
CSRF_COOKIE_HTTPONLY #是否允许JS读取cookie
CSRF_COOKIE_NAME #cookie的键
CSRF_COOKIE_PATH #cookie的位置
CSRF_COOKIE_SAMESITE
CSRF_COOKIE_SECURE #将此设置为 True,避免不小心使用 HTTP 传输 CSRF cookie。
CSRF_FAILURE_VIEW #csrf拒绝后跳转的视图
CSRF_HEADER_NAME #csrf在header中的键
CSRF_TRUSTED_ORIGINS #信任源
CSRF_USE_SESSIONS #是否使用基于session的csrf令牌
- ajax字典传输写法
def test_ajax(request):
import json
ret = {'status',True,'error':None,'data',None}
try:
h = request.POST.get('hostname')
j = request.POST.get('port')
if len(h) >5:
pass #插入到数据库
else:
ret['status'] = False
ret['error'] = "太短了"
except Exception as e:
ret['status'] = False
ret['error'] = "请求错误..."
return HttpResponse(json.dumps(ret))
success:function(data){
var obj = JSON.parse(data);
if(obj.status){
...
}else{
...
}
}
3.中间件
- 创建中间件
# Middle/m1.py 在根目录下创建
from django.utils.deprecation import MiddlewareMixin
"""
流程:过滤所有用户的请求,一下是整个运行流程
请求 -> row1:process_request -> row2:process_request -> row3:process_request \
\ row3:process_view <- row2:process_view <- row1:process_view <- 路由映射匹配
自己写的view函数 -> row3:process_response -> row2:process_response -> row1:process_response
"""
#view_func是View函数指针,view_func_args和view_func_kwargs是view函数的参数
class Row1(MiddlewareMixin):
def process_request(self,request):
print("111111")
def process_view(self,request,view_func,view_func_args,view_func_kwargs):
print("zzz111")
def process_response(self,request,response):
print("666666")
return response
class Row2(MiddlewareMixin):
def process_request(self,request):
print("222222")
return HttpResponse("走") #阻止请求。。。
def process_view(self,request,view_func,view_func_args,view_func_kwargs):
print("zzz222")
def process_response(self,request,response):
print("555555")
return response
class Row3(MiddlewareMixin):
def process_request(self,request):
print("333333")
def process_view(self,request,view_func,view_func_args,view_func_kwargs):
print("zzz333")
def process_response(self,request,response):
print("444444")
return response
def process_exception(self,request,exception)
printf("view函数报错了就执行")
if isinstance(exception,ValueError):
return HttpResponse('出现异常了...')
def process_template_exception(self,request,response):
# 如果Views中的函数返回的对象中,具有render方法就执行
print("-------------")
return response
- 注册中间件
# setting.py
MIDDLEWARE = [
...,
'Middle.m1.Row1',
'Middle.m1.Row2',
'Middle.m1.Row3',
]
4.缓存
由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存,缓存将一个某个views的返回值保存至内存或者memcache中,5分钟内再有人来访问时,则不再去执行view中的操作,而是直接从内存或者Redis中之前缓存的内容拿到,并返回。
-
设置缓存
- 开发调试
# 此为开始调试用,实际内部不做任何操作 配置: CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.dummy.DummyCache', # 引擎 'TIMEOUT': 300, # 缓存超时时间(默认300,None表示永不过期,0表示立即过期) 'OPTIONS':{ 'MAX_ENTRIES': 300, # 最大缓存个数(默认300) 'CULL_FREQUENCY': 3, # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认1/3) }, 'KEY_PREFIX': '', # 缓存key的前缀(默认空) 'VERSION': 1, # 缓存key的版本(默认1) 'KEY_FUNCTION': 函数名 # 生成key的函数(默认函数会生成为:【前缀:版本:key】) } } # 自定义key def default_key_func(key, key_prefix, version): """ Default function to generate keys. Constructs the key used by all other methods. By default it prepends the `key_prefix'. KEY_FUNCTION can be used to specify an alternate function with custom key making behavior. """ return '%s:%s:%s' % (key_prefix, version, key) def get_key_func(key_func): """ Function to decide which key function to use. Defaults to ``default_key_func``. """ if key_func is not None: if callable(key_func): return key_func else: return import_string(key_func) return default_key_func- 内存
CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', 'LOCATION': 'unique-snowflake', # 全局其实就是一个字典,这是变量名 } } # 注:其他配置同开发调试版本- 文件
CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', 'LOCATION': os.path.join(BASE_DIR,'django_cache'), #路径 } } # 注:其他配置同开发调试版本- 数据库
# 数据库 CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.db.DatabaseCache', 'LOCATION': 'my_cache_table', # 数据库表 } } # 注:执行创建表命令 python manage.py createcachetable # 就会生成一个表my_cache_table- Memcache缓存(python-memcached模块)
# 此缓存使用python-memcached模块连接memcache CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 'LOCATION': '127.0.0.1:11211', } } CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 'LOCATION': 'unix:/tmp/memcached.sock', } } CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 'LOCATION': [ '172.19.26.240:11211', '172.19.26.242:11211', ] } }- Memcache缓存(pylibmc模块)
CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache', 'LOCATION': '127.0.0.1:11211', } } CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache', 'LOCATION': '/tmp/memcached.sock', } } CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache', 'LOCATION': [ '172.19.26.240:11211', '172.19.26.242:11211', ] } }- Redis缓存(依赖:pip3 install django-redis)
CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://127.0.0.1:6379", "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", "CONNECTION_POOL_KWARGS": {"max_connections": 100} # "PASSWORD": "密码", } } } -
使用缓存
# 视图中链接并操作
from django_redis import get_redis_connection
conn = get_redis_connection("default")
#整个页面做缓存
from django.views.decorators.cache import cache_page
@cache_page(10) #10秒之内都会去缓存取数据
def cache(request):
import time
ctime = time.time()
return render(request,'cache.html',{'ctime':ctime})
{# 局部缓存 #}
{% load cache %}
{% cache 5000 缓存key %} {# 超时时间:单位s key #}
缓存内容
{% endcache %}
#全站缓存
"""
使用中间件,经过一系列的认证等操作,如果内容在缓存中存在,则使用FetchFromCacheMiddleware获取内容并返回给用户,当返回给用户之前,判断缓存中是否已经存在,如果不存在则UpdateCacheMiddleware会将缓存保存至缓存,从而实现全站缓存
"""
import django.middleware.cache import UpdateCacheMiddleware
import django.middleware.cache import FetchFromCacheMiddleware
MIDDLEWARE = [
'django.middleware.cache.UpdateCacheMiddleware',
# 其他中间件...
'django.middleware.cache.FetchFromCacheMiddleware',
]
CACHE_MIDDLEWARE_ALIAS = ""
CACHE_MIDDLEWARE_SECONDS = ""
CACHE_MIDDLEWARE_KEY_PREFIX = ""
5.信号
- 信号(触发器)
#使用方法
# __init__.py中调用下面代码(建议封装成模块)
from django.core.signals import request_finished
from django.core.signals import request_started
from django.core.signals import got_request_exception
from django.db.models.signals import class_prepared
from django.db.models.signals import pre_init, post_init
from django.db.models.signals import pre_save, post_save
from django.db.models.signals import pre_delete, post_delete
from django.db.models.signals import m2m_changed
from django.db.models.signals import pre_migrate, post_migrate
from django.test.signals import setting_changed
from django.test.signals import template_rendered
from django.db.backends.signals import connection_created
def fun(sender,**kwargs):
print('按照信号规则触发此函数')
pre_init.connect(fun) #注册一个信号,django的modal执行其构造方法前,自动执行fun函数
Model signals
pre_init # django的modal执行其构造方法前,自动触发
post_init # django的modal执行其构造方法后,自动触发
pre_save # django的modal对象保存前,自动触发
post_save # django的modal对象保存后,自动触发
pre_delete # django的modal对象删除前,自动触发
post_delete # django的modal对象删除后,自动触发
m2m_changed # django的modal中使用m2m字段操作第三张表(add,remove,clear)前后,自动触发
class_prepared # 程序启动时,检测已注册的app中modal类,对于每一个类,自动触发
Management signals
pre_migrate # 执行migrate命令前,自动触发
post_migrate # 执行migrate命令后,自动触发
Request/response signals
request_started # 请求到来前,自动触发
request_finished # 请求结束后,自动触发
got_request_exception # 请求异常后,自动触发
Test signals
setting_changed # 使用test测试修改配置文件时,自动触发
template_rendered # 使用test测试渲染模板时,自动触发
Database Wrappers
connection_created # 创建数据库连接时,自动触发
- 自定义信号
# 定义信号
import django.dispatch
pizza_done = django.dispatch(providing_args=["toppings","size"])
#注册信号
def fun(sender,**kwargs):
print('按照信号规则触发此函数')
pizza_done.connect(fun) #注册一个信号,django的modal执行其构造方法前,自动执行fun函数
#触发信号
pizza_done.send(sender='seven',toppings=123,size=456)
6.表单验证
- form组件
# 生成HTML标签
# 验证用户数据(显示错误信息)
# HTML Form提交保留上次提交数据
# 初始化页面显示内容
from django.forms import widgets
from django.forms import fields
class stuForm(forms.Form):
stu_id = fields.CharField(
label='学号',
min_length=11,
max_length=11,
widget=widgets.TextInput(attrs={'id': 'stu_id', 'class': 'stu_id'}) #这个地方可以设置控件的属性
)
passwd = fields.CharField(
label='密码',
widget=widgets.PasswordInput(attrs={'class': 'passwd'}, render_value=True) #不会丢
)
sex = fields.ChoiceField(
label='性别',
choices=((0, '男'), (1, '女'),),
initial=1,
widget=widgets.RadioSelect
)
age = fields.IntegerField(
label='年龄',
min_value=0,
max_value=130,
)
stu_name = fields.CharField(
label='真实姓名',
min_length=2,
max_length=5,
widget=widgets.TextInput(attrs={'id': 'stu_name', 'class': 'stu_name'})
)
major_name = form_model.ModelChoiceField(
label='专业班级',
queryset=models.Major.objects.all(),
widget=widgets.Select(),
initial=0
)
phone_number = fields.CharField(
label='手机号码',
min_length=11,
max_length=11,
widget=widgets.TextInput(attrs={'id': 'phone_number', 'class': 'phone_number'})
)
def register(request):
view_content = {}
view_content['college'] = models.College.objects.all()
view_content['major'] = models.Major.objects.all()
dic = {
'user':'rrr',
'passwd':'pppwww' ,
}
if request.method == 'GET':
view_content['form'] = stuForm(initial=dic) #生成时初始化数
return TemplateResponse(request,'loginApp/register.html',view_content)
elif request.method == 'POST':
obj = stuForm(request.POST)
view_content['form'] = obj
if obj.is_valid(): #用户的表单正确
#values = obj.clean()
models.UserInfo.objects.create(**obj.cleaned_data) #直接存入数据库
print(values)
else:
print(obj.errors.as_json())
#return render(request, 'index.html', {'form': obj})
return TemplateResponse(request,'loginApp/register.html',view_content)
<form action="register.html" method="POST" enctype="multipart/form-data">
<p>{{ form.stu_id.label }} : {{ form.stu_id }} {{ form.stu_id.errors }}</p>
<p>{{ form.sex.label }} : {{ form.sex }} {{ form.sex.errors }}</p>
<p>{{ form.passwd.label }} : {{ form.passwd }} {{ form.passwd.errors }}</p>
<p>{{ form.age.label }} : {{ form.age }} {{ form.age.errors }}</p>
<p>{{ form.stu_name.label }} : {{ form.stu_name }} {{ form.stu_name.errors }}</p>
<p>{{ form.major_name.label }} : {{ form.major_name }} {{ form.major_name.errors }}</p>
<p>{{ form.phone_number.label }} : {{ form.phone_number }} {{ form.phone_number.errors }}</p>
{{ form.as_p }}
{{ form.as_ul }}
<table>{{ form.as_table }}</table>
<input type="submit"/>
</form>
- modelsForm
from django.forms import fields as Ffields
from django.forms import widgets as Fwidget
class UserInfoModelForm(forms.Form):
is_rmb = Ffields.CharField(widget=Fwidgets.CheckboxInput()) #获取到值,检查是否失效
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for field in self.fields.values():
field.widget.attrs['class'] = 'form-control'
field.widget.attrs['placeholder'] = '请输入{}'.format(field.label)
# 验证用户名
def clean_username(self):
# 校验数据前,都需要获取到被校验的数据
username = self.cleaned_data['username']
# 开始校验:判断数据库中是否已存在用户名
xists = models.User.objects.filter(username=username).exists()
if exists:
raise ValidationError('用户名已存在')
return username
class Meta:
model = models.UserInfo #对应哪个字段
fields = '__all__' #取所有字段
fields = ['username'] #展示哪个字段
exclude = ['username'] #排除哪个字段
labels = { 'username':'用户名'} #提示信息
help_texts = {'username':'...'} #帮助信息
widgets = {'username':Fwidget.Textare(attrs={'class':'c1'})} #控件
error_messages = {
'email':{'required':'邮箱不能为空'} #字段对应字典,字典里一个个code设置字段信息
}
field_classes = {'email':Ffield.URLField} #修改验证格式
localized_fields = ('publish_date') # 时区本地化
"""
setting.py
TIME_ZONE = 'Asia/Shanghai'
USE_TZ = True
数据库中 2016-12-27 04:10:57 -> 2016-12-27 12:10:57
"""`
def index(request):
if request.method == 'GET':
obj = UserInfoModelForm()
return render(request,'index.html',{'obj':obj})
if request.method == 'POST':
obj = UserInfoModelForm(request.POST)
if obj.is_valid():
obj.save() #直接保存到数据库了
return render(request,'index.html',{'obj':obj})
obj = UserInfoModelForm(request.POST)
instance = obj.save(False) #返回数据库实例
instance.save() # 保存
instance.save_m2m() # 保存多对多表
def user_edit(request,nid):
if request.method == "GET":
user_obj = models.UserInfo.objects.filter(id=nid).first()
mf UserInfoModelForm(instance=user_obj)
return render(request,'user_edit.html',{'mf',mf,'nid':nid})
if request.method == "POST":
user_obj = models.UserInfo.objects.filter(id=nid).first()
mf = UserInfoModelForm(request.POST,instance=user_obj) #表示修改数据
if mf.is_valid():
mf.save()
else:
print(mf.errors.as_json())
return render(request,'user_edit.html',{'mf',mf,'nid':nid})
- 伪ajax请求
//iframe可以直接用来上传文件!!!view部分用标准文件获取写法
function iframeSubmit(){
$('iframe').load(function(){
var txt = $('#ifml').contents().find('body').text(); //取iframe中的数据
var obj = JSON.parse(txt);
})
}
<form action='/upload_file/' method='POST' enctype='multipart/form-data' target='ifm1'>
<!--form中的taget在指定的iframe中打开-->
<iframe id='ifm1' name='ifm1'></iframe>
<input type='file' name='fafafa'/>
<input type='submit' onclick='iframeSubmit();' value='提交'/>
</form>
- ajax上传文件
<div class="form2">
<input type="file" name="file" id="file_upload">
<input type="button" value="上传" class="file_upload_submit">
</div>
{% load static %}
<script src="{% static 'js/jquery.js' %}"></script>
<script>
$('.file_upload_submit').click(function(){
var form_data = new FormData();
var file_info = $('#file_upload')[0].files[0];
var csrf = $('input[name=csrfmiddlewaretoken]').val();
form_data.append('file',file_info);
form_data.append('csrfmiddlewaretoken', csrf);
//console.log($('#file_upload')[0].files)
if(file_info==undefined){//暂且不许要判断是否有附件
alert('你没有选择任何文件');
return false
}
$.ajax({
url:'/myapp2/fileUpload',
type:'POST',
data: form_data,
processData: false, // tell jquery not to process the data
contentType: false, // tell jquery not to set contentType
success: function(callback) {
console.log('ok')
},
// header:{
// 'X-CSRFToken': $.cookie('csrftoken'),
// }
});
});
</script>
@csrf_exempt
def uploadFile(request):
if request.method == 'POST':
file_obj = request.FILES.get('file')
name = file_obj.name
size = file_obj.size
if file_obj:
import os
f = open(os.path.join(settings.BASE_DIR, 'static', 'upload', file_obj.name), 'wb')
for chunk in file_obj.chunks():
f.write(chunk)
f.close()
print('11111')
return TemplateResponse(request,'myapp2/madd.html')
with open(os.path.join(settings.BASE_DIR, 'static', 'upload', file_obj.name), 'wb) as f:
for chunk in file_obj.chunks()
f.write(chunk)
xss攻击
{{ str|safe }} {# 这个字符串是安全的,不需要转义,可以直接执行 #}
from django.utils.safestring import mark_safe
page_str = "<h1>666</h1>"
page_str = make_safe(page_str)
8.验证码
"""
1.访问页面/login/
- 创建一个图片给用户
- session储存验证码
2.POST页面
- 检查表单和session是否匹配
pip3 install Pillow
1.创建一张图片
2.在图片中写入随机字符串
3.将图片写入到定制文件
"""
<img src='/check_code.html' onclick="changeCheckCode(this);">
function changeCheckCode(this){
this.src = this.src + '?'; //重新发请求
}
VSCODE
- html没有提示
- 打开设置,在设置中搜索Files: Associations,可以看到这么一个选项,
- 在键中输入**/*.html,在值中输入html,点击勾完成,具体如下图所示

浙公网安备 33010602011771号