Django是一个开放源代码的Web应用框架,采用了MTV的框架模式,即模型M,视图V和模版T
在线安装
离线安装- 官网下载离线安装包
若要局域网其他主机访问此主机的Django服务,启动方式如下:
方式1:在runserver终端下
方式2:在其他终端下
from pathlib import Path
# 创建内部路径: BASE_DIR / 'subdir'.
# 绑定当前项目的绝对路径(动态),所有文件夹依赖此路径
BASE_DIR = Path(__file__).resolve().parent.parent
DEBUG = True
"""
配置Django项目的启动模式
True - 调试模式
1,检测代码改动后,立刻重启服务
2,报错页面
False - 正式启动模式 / 上线模式 / 生产模式
"""
# 公有配置 请求头Host头,过滤无效请求头,比如域名 www.tendu.com,127.0.0.1 等等
ALLOWED_HOSTS = []
"""
设置允许访问到本项目的 host 头值
- []空列表,表示只有请求头中host为127.0.0.1,localhost能访问,DEBUG=True时有效
- ['*'],表示任何请求头的host都能访问
- ['192.168.124.20','127.0.0.1']表示只有当前两个host头的值能访问
"""
# 配置Django应用 -注册应用 指定当前项目中安装的应用列表
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'user',
'index',
'note',
]
# 中间件配置,用于注册中间件
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',
'middleware.mymiddleware.MyMW',
'middleware.mymiddleware.MyMW2',
]
# 标识主路由的位置
ROOT_URLCONF = 'tedu_note.urls'
# 指定模板的配置信息
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',
],
},
},
]
WSGI_APPLICATION = 'tedu_note.wsgi.application'
# https://docs.djangoproject.com/en/4.0/ref/settings/#databases
# 数据库连接配置
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'tedu_note',
'USER': 'root',
'PASSWORD':'root',
'HOST':'127.0.0.1',
'PORT' : '3306'
}
}
# Password validation
# https://docs.djangoproject.com/en/4.0/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/4.0/topics/i18n/
# 语言设置
LANGUAGE_CODE = 'zh-Hans'
# 时区设置
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_TZ = False
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.0/howto/static-files/
STATIC_URL = 'static/'
# Default primary key field type
# https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
# 指定seesionid在cookies中的保存时长(默认是2周)
SESSION_COOKIE_AGE = 60 * 60 * 24 * 7 * 2
#设置只要浏览器关闭时,session就失效(默认为False)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False
# 数据库缓存配置
CACHES = {
'default':{
'BACKEND':'django.core.cache.backends.db.DatabaseCache',
'LOCATION':'my_cache_table',
'TIMEOUT':300, # 缓存保存时间 单位秒, 默认值为 300
'OPTIONS':{
'MAX_ENTRIES':300,# 缓存最大数据条数
'CULL_FREQUENCY':2,# 缓存条数达到最大值时 删除 1/X 的缓存数据
}
}
}
# 服务器内存的缓存配置
# CACHES = {
# 'default':{
# 'BACKEND':'django.core.cache.backends.locmem.LocMemCache',
# 'LOCATION':'unique-snowflake'
# }
# }
# 文件系统的缓存配置
# CACHES = {
# 'default':{
# 'BACKEND':'django.core.cache.backends.filebased.FileBasedCache',
# 'LOCATION':'/var/tmp/django_cache', # 缓存文件夹的路径
# 'LOCATION':'c:\test\cache', # windows下示例,缓存文件夹的路径
#
# }
# }
备注:格式化快捷键 ctr+alt+L
MVC 中 C(控制层) 相当于 MTV 中的 主路由配置(urls.py) 简化
urlpatterns = [
path('admin/', admin.site.urls),
#视图函数
path('test_request',views.test_request),
path('test_get_post',views.test_get_post),
path('test_html',views.test_html),
]
模板层配置(setting.py),并创建 templates文件夹
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates'],
# 'DIRS': [os.path.join(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',
],
},
},
]
MVC中 V(视图)功能相当于 MTV 中的 T(模板)+V(视图)
其中:T 保存 html ,V 控制逻辑,与模板层进行交互(可传变量 **{{ 变量键名 }} **)
当视图中需要生成的字典内容过多时,可以使用 locals() 自动生成含有当前所有内容的字典
def test_html(request):
# 方案1:
from django.template import loader
t=loader.get_template('test_html.html')
html=t.render()
return HttpResponse(html)
# 方案2:简化代码,使用render()直接加载并响应模板,dic传值必须是字典
from django.shortcuts import render
dic={'uname':'yuyupeng','age':22}
return render(request,'test_html.html',dic)
{{ 变量名 }} {{ 变量名.index }} {{ 变量名.key }} {{ 函数名 }} {{ 对象.方法 }}
<h3> int : {{ int }}h3>
<h3> str : {{ str }}h3>
<h3> lst : {{ lst }}h3>
<h3> lst[1] : {{ lst.1 }}h3>
<h3> dic : {{ dic }}h3>
<h3> dic['a'] : {{ dic.a }}h3>
<h3> fuc : {{ fuc }}h3>
<h3> obj : {{ obj.speak }}h3>
通过使用 过滤器来改变 变量的输出显示 ,如 lower | upper | safe | add:“n” | truncatechars":'n’
语法:{{ 变量 | 过滤器1:‘参数值1’ |过滤器2:‘参数值2’ |… }}
**safe:**变量输出时不需要转义
官方文档:https://docs.djangoproject.com/en/4.0/ref/templates/builtins/
子模板可以直接继承父模板,并覆盖相应的块
继承:{% extends ‘base.html’ %} (动态变量无法继承)
重写:{% block block_name %} {% endblock [block_name] %}
1.绝对地址
2.相对地址
(1)’**/**page/1’ (带有 / 开头的),相对地址为 127.0.0.1:8000/page/1
(2)‘page/1’(不带 / 开头的),相对地址会截取最后一位 / ,比如
127.0.0.1:8000/page**/**3 截取后相对地址为 127.0.0.1:8000/page/page/1
在视图函数中 -> 可调用django中的reverse 方法进行反向解析
from django.urls import reverse
reverse('别名',args=[],kwargs={})
ex:
print(reverse('pagen',args=[300]))
print(reverse('person',kwargs={'name':'xixi','age':18}))
1.静态文件配置(setting.py),并创建 static文件夹
STATIC_URL = 'static/'
STATICFILES_DIRS=( BASE_DIR/'static',)
方案1:绝对路径/相对路径
方案2:动态访问,更加灵活
加载static - {% load static %}
使用静态资源 - {% static ‘静态资源路径’ %}
#方案1
<img src="http://127.0.0.1:8000/static/image/django.png" width="200px" height="200px">
<img src="/static/image/django.png" width="200px" height="200px">
#方案2
{% load static %}
<img src="{% static 'image/django.png' %}" width="200px" height="200px">
添加 app 命令:python manage.py startapp music
配置(setting.py) 注册app(一定要注册应用)
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'music',
'sport',
'news',
]
ubuntu 中 安装 python3-dev 以及 default-libmysqlclient-dev
检查命令: sudo apt list --installed|grep -E ‘libmysqlclient-dev|python3-dev’
安装命令: sudo apt-get install python3-dev default-libmysqlclient-dev
Mysql - 安装命令: pip install mysqlclient
创建数据库命令 create database mysite1 default charset utf8;
配置(setting.py)
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'mysite3',
'USER': 'root',
'PASSWORD': 'root',
'HOST' : '127.0.0.1',
"PORT" : '3306'
}
}
其他数据库配置如下:
'django.db.backends.mysql'
'django.db.backends.sqllite3'
'django.db.backends.oracle'
'django.db.backends.postgresql'
模型:是数据交互的接口,表示和操作数据库的方法和方式
ORM(Object Relational Mapping) 即 对象关系映射
优点:
1.只需要面向对象编程,不需要面向数据库编写代码
2.实现了数据模型与数据库的解耦,屏蔽了不同数据库操作上的差异
新建app (python manage.py startapp bookstore)
配置 bookstore-> models.py
字段类型文档:https://docs.djangoproject.com/en/4.0/ref/models/fields/#field-types
from django.db import models
# class 模型类名(models.Model):
# 字段名 = models.字段类型(字段选项)
class Book(models.Model):
title= models.CharField('书名',max_length=50,default='')
price = models.DecimalField('价格',max_digits=7,decimal_places=2)
数据库迁移同步(只要修改过,必须要执行 makemigrations和migrate)
迁移是Django同步您对模型所作更改(添加字段、删除模型等)到数据库模式的方式
1.生成迁移文件,将应用下的models.py文件生成一个中间文件,并保存在migrations文件夹中
2.执行迁移脚本程序 ,将每个应用下的migrations目录中的中间文件同步会数据库
执行数据库交互式操作Django Shell
from bookstore.models import Book
#方式一:(推荐)
b1 = Book.objects.create(title='Python',pub='清华大学出版社',price=20,market=25)
#方式二:
b2 = Book(title='Django',pub='清华大学出版社',price=70,market=75)
b2.save()
( all / values / values_list / order_by / filter / exclude / get)
其中 get 必须 和 (try - except Exception as e) 配套使用,必须查询到唯一object,否则报错
from bookstore.models import Book
#a ll() 存放Book实例
all_book = Book.objects.all()
for book in all_book:
print('书名',book.title,'出版社:',book.pub)
#values() 存放字典
values = Book.objects.values('title','pub')
for book in values:
print('书名',book['title'],'出版社:',book['pub'])
#values_list() 存放元组
values = Book.objects.values_list('title','pub')
for book in values:
print('书名',book[0],'出版社:',book[1])
#order_by() 排序,默认为升序,降序需增加 '-',如 '-price'
order = Book.objects.all().order_by('-price')
for book in order:
print('书名',book.title,'出版社:',book.pub)
#显示Sql查询语句
print(order.query)
官方文档:https://docs.djangoproject.com/en/4.0/ref/models/querysets/#field-lookups
单个数据更新
#查 get()
try:
book = Book.objects.get(id=book_id)
except Exception as e:
print('--update book error is %s' % (e))
return HttpResponse('The book is not existed')
# 改
book.price = price
book.market = market_price
# 保存
book.save()
批量数据更新
#查
books = Book.objects.filter(id__gt=3)
#QuerySet中 update()
books.update(price=10)
单个/批量数据删除
try:
#单个
auth = Author.objects.get(id=1)
auth.delete()
#批量
auth1 = Author.objects.filter(age__gt=65)
auth1.delete()
except Exception as e:
print('删除失败%s'%(e))
伪删除
mysql表中增加 布尔型字段(is_active)字段,默认为True
注意:显示数据时,均要加 is_active = True 的过滤查询,否则删除失效
F对象
#示例1 更新Book实例中所有价格涨10元
from bookstore.models import Book
from django.db.models import F
#方案一:使用F对象
Book.objects.all().update(price=F('price')+10)
#等同于执行 mysql语句 'UPDATE book SET book.price = book.price+10'
#方案二:常规
books = Book.objects.all()
for book in books:
book.price = book.price+10
book.save()
#示例2 对数据库中两字段值进行比较,列出零售价高于定价的书籍
books = Book.objects.filter(market__gt=F('price') )
for book in books:
print(book.title,'定价:',book.price,'现价:',book.market)
Q对象
# & 与操作 |或操作 ~非操作
Q('条件1')&Q('条件2') #同时成立
Q('条件1')|Q('条件2') #满足其一
Q('条件1')&~Q('条件2') #条件1成立且条件2不成立
from bookstore.models import Book
from django.db.models import Q
Book.objects.filter(Q(price__lt=20)|Q(pub='清华大学出版社'))
聚合查询
1.整表聚合
from django.db.models import *
# Sum, Avg, Count, Max, Min
Book.objects.aggregate(result=Count('id'))
2.分组聚合
from bookstore.models import Book
from django.db.models import Count
bs = Book.objects.values('pub')
bs.annotate(res=Count('pub'))
Django支持 直接用Sql语句通信数据库
查询:MyModel.objects.raw(sql语句,拼接参数)
返回值:RawQuerySet集合对象【支持基础操作,如循环等】
books = models.book.objects.raw('select * from book')
SQL注入
#错误
s1 = Book.objects.raw('select * from book where id=%s'%('1 or 1=1'))
#正确的 sql注入防范 (sql语句,拼接参数)
s2 = Book.objects.raw('select * from book where id=%s',['1 or 1=1'])
Cursor
完全跨过模型类操作数据库 - 查询/更新/删除
from django.db import connection
#通常使用with语句进行创建cursor对象,保证异常时能释放 cursor资源
with connection.cursor() as cur:
cur.execute('执行SQL语句','拼接参数')
#将id为 10 的书的出版社调整
with connection.cursor() as cur:
cur.execute('update book set pub="光明出版社" where id=10;')
#删除id为 1的一条记录
with connection.cursor() as cur:
cur.execute('delete from book where id=10;')
配置mysite1/admin.py
from django.contrib import admin
from .models import Book
# Register your models here.
admin.site.register(Book)
配置mysite1/admin.py
from django.contrib import admin
from .models import Book,Author
# Register your models here.
class BookManager(admin.ModelAdmin):
#列表页显示哪些字段的列
list_display = ['id','title','pub','price','market']
#控制list_display 中的字段 哪些可以链接到修改页
list_display_links = ['title']
#添加过滤器
list_filter = ['pub','price']
#添加搜索框[模糊查询]
search_fields = ['title']
#添加可在列表页编辑的字段
list_editable = ['pub','price','market']
admin.site.register(Book,BookManager)
Meta类
class Book(models.model):
title = CharField(....)
class Meta:
# 1.该模型所用的数据表名称-(设置后需立马更新同步数据库)
db_table = 'book'
# 2.该模型的显示名称(单数),用于显示在/admin管理界面中
verbose_name = '图书'
# 3.该模型的显示名称(复数),用于显示在/admin管理界面中
verbose_name_plural = verbose_name
级联删除 - on_delete
1.建立应用 oto,并注册
2.建立models中数据表,并同步迁移
from django.db import models
# Create your models here.
class Author(models.Model):
name = models.CharField('姓名',max_length=11)
class Wife(models.Model):
name = models.CharField('姓名',max_length=11)
#增加一对一属性:属性 =OneToOneField(类名,on_delete=xxx)
author = models.OneToOneField(Author,on_delete=models.CASCADE)
3.创建数据
from oto.models import Author,Wife
#无外键的模型类[Author]
a1 = Author.objects.create(name='王老师')
a2 = Author.objects.create(name='吕老师')
#有外键的模型类[Wife]
wife1 = Wife.objects.create(name='王夫人',author=a1) #关联王老师的obj
wife1 = Wife.objects.create(name='吕夫人',author_id=a2.id) #关联吕老师的id
4.查询数据
#正向查询
print(wife1.author.name)
#反向查询 '实例对象.引用类名(小写)',若反向引用不存在,则出现异常
print(a2.wife.name)
1.建立应用 otm,并注册
2.建立models中数据表,并同步迁移
from django.db import models
# Create your models here.
class Publisher(models.Model):
title = models.CharField('出版社名称',max_length=11)
class Book(models.Model):
title = models.CharField('书名',max_length=11)
#增加一对多属性:属性 =ForeignKey(类名,on_delete=xxx)
publisher = models.ForeignKey(Publisher,on_delete=models.CASCADE)
3.创建数据
from otm.models import Publisher,Book
#无外键的模型类[Author]
pub1 = Publisher.objects.create(title='清华大学出版社')
#有外键的模型类[Wife]
book1 = Book.objects.create(title='C++',publisher=pub1) #关联pub的obj
book1 = Book.objects.create(title='Java',publisher_id=pub1.id) #关联pub的id
4.查询数据
#正向查询 '实例对象.引用类名(小写)'
print(book1.publisher.title)
#反向查询 通过 book_set 获取pub1 对应的多个Book数据对象
books=pub1.book_set.all()
books1=Book.objects.filter(publisher=pub1) #也可以
for book in books:
print(book.title)
1.建立应用 oto,并注册
2.建立models中数据表,并同步迁移
from django.db import models
# Create your models here.
class Author(models.Model):
name = models.CharField('姓名',max_length=11)
class Book(models.Model):
title = models.CharField('书名',max_length=11)
#增加多对多属性:属性 =ManyToManyField(类名)
authors = models.ManyToManyField(Author)
3.创建数据
from mtm.models import Author,Book
# 方案1 先创建 author 再关联 book
author1 = Author.objects.create(name='王老师')
author2 = Author.objects.create(name='吕老师')
# 王老师 和 吕老师 同时写了一本 Python
book1 = author1.book_set.create(title='Python')
author2.book_set.add(book1)
# 方案2 先创建 book 再关联 author
book1 = Book.objects.create(title='Java')
#赵老师 和 王老师 都参与了 Java 的创作
author3 = book1.authors.create(name='赵老师')
book1.authors.add(author1)
4.查询数据
#正向查询 '实例对象.引用类名(小写)'
authors = book1.authors.all()
for author in authors:
print(author.name)
#反向查询 通过 book_set 获取pub1 对应的多个Book数据对象
books=author1.book_set.all()
for book in books:
print(book.title)
# 设置cookies
def set_cookies(request):
resp=HttpResponse('set cookies is ok')
resp.set_cookie('uname','yyp',500)
return resp
# 获取cookies
def get_cookies(request):
value = request.COOKIES.get('uname','空值')
return HttpResponse('value is %s'%(value))
# 删除cookies
def delete_cookies(request):
resp = HttpResponse('已删除 uname')
resp.delete_cookie('uname')
return resp
session是在服务器上开辟一段空间,用于保留浏览器和服务器交互时的重要数据。
相关配置项 setting.py
# 启用 session 应用
INSTALLED_APPS = [
'django.contrib.messages',
]
# 启用 session 中间件
MIDDLEWARE = [
'django.contrib.sessions.middleware.SessionMiddleware',
]
# 指定seesionid在cookies中的保存时长(默认是2周)
SESSION_COOKIE_AGE = 60 * 60 * 24 * 7 * 2
#设置只要浏览器关闭时,session就失效(默认为False)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False
session用法
# 保存 session 的值到服务器
def set_session(request):
value = request.session['uname'] = 'wwc'
return HttpResponse('set session is ok')
# 获取 session 的值
def get_session(request):
value = request.session.get('uname')
return HttpResponse('session value is %s'%(value))
# 删除 session
def delete_session(request):
del request.session['uname']
return HttpResponse('delete session is ok')
# 修改session存储时间为 1 天
request.session.set_expiry(60*60*24)
# 你可以传递四种不同的值给它:
# *如果value是个整数,session会在些秒数后失效(适用于整个Django框架,即这个数值时效时整个页面都会session失效)。
# *如果value是个datatime或timedelta,session就会在这个时间后失效。
# *如果value是0, 用户关闭浏览器session就会失效。
# *如果value是None, session会依赖全局session失效策略。
session的问题
用户可在该系统中 记录 自己的 日常学习/旅游 笔记,用户的数据将被安全的存储在 云笔记平台;用户与用户之间数据为隔离存储(用户只有在登陆后才能使用相关笔记功能,且之恩能够查阅自己的笔记内容)
部分页面展示如下:
哈希算法 : 给定明文,计算出一段定长的 ,不可逆的值; md5, sha-256
应用场景:1. 密码处理 2. 文件完整性校验(如电影下载)
特点
import hashlib
# 哈希算法 - 给定明文,计算出一段定长的 ,不可逆的值; md5, sha-256
h = hashlib.md5()
# 字符串需解码 -> 2进制
h.update(password1.encode())
passwordm = h.hexdigest()
需使用 try - except 异常处理
# 有可能报错 - 重复插入 [唯一索引注意并发写入问题]
try:
user = User.objects.create(username=username,password=passwordm)
except Exception as e:
print('--create user error %s'%(e))
error = '用户名重复,请重新填写!'
return render(request, 'user/register.html', locals())
使用装饰器,降低代码重复率,解耦
# 在每个视图前引用装饰器即可
@check_login
def check_login(fn):
def wrap(request,*args, **kwargs):
# 检查 Session
if 'username' not in request.session or 'uid' not in request.session:
# 检查Cookies
c_username = request.COOKIES.get('username')
c_uid = request.COOKIES.get('uid')
if not c_username or not c_uid:
return HttpResponseRedirect('/user/login')
else:
# 回写session
request.session['username'] = c_username
request.session['uid'] = c_uid
return fn(request, *args, **kwargs)
return wrap
session记录登陆用户,并设置过期时间
# 用户登录视图
def login_view(request):
if request.method == 'GET':
# 获取登录页面
# 检查登录状态 ,如果登录了,显示 ’已登录'
if request.session.get('username') and request.session.get('uid'):
return HttpResponse('已登录')
# 检查Cookies
c_username = request.COOKIES.get('username')
c_uid = request.COOKIES.get('uid')
if c_uid and c_username:
# 回写session
request.session['username'] = c_username
request.session['uid'] = c_uid
return HttpResponse('已登录')
return render(request,'user/login.html')
elif request.method == 'POST':
error = ''
username = request.POST.get('username')
password = request.POST.get('password')
remember = request.POST.get('remember')
try:
user = User.objects.get(username=username,is_active=True)
except Exception as e:
print('--login user error %s'%(e))
return render(request, 'user/login.html', locals())
# 记录会话状态- 默认存session 为1天
request.session['username'] = username
request.session['uid'] = user.id
# 设置过期时间 为一天,默认 settings.py 中为 14天
request.session.set_expiry(60 * 60 * 24)
resp = HttpResponse('登录成功')
# 判断用户是否 点选了 ‘记住用户名‘
if remember:
resp.set_cookie('username',username,60 * 60 * 24 * 3)
resp.set_cookie('uid',user.id,60 * 60 * 24 * 3)
# 点选了 -> Cookies 存储 username,uid 时间3天
return resp
given a URL, try finding that page in the cache
if the page is in the cache:
return the cached page
else:
generate the page
save the generated page in the cache (for next tiem)
return the generated page
1.将缓存的数据存储在数据库中(mysql等)
需要手动执行 创建表 的命令,即 执行 python3 manage.py createcachetable
# 数据库缓存配置 (settings.py中添加)
CACHES = {
'default':{
'BACKEND':'django.core.cache.backends.db.DatabaseCache',
'LOCATION':'my_cache_table',
'TIMEOUT':300, # 缓存保存时间 单位秒, 默认值为 300
'OPTIONS':{
'MAX_ENTRIES':300,# 缓存最大数据条数
'CULL_FREQUENCY':2,# 缓存条数达到最大值时 删除 1/X 的缓存数据
}
}
}
2.将数据缓存到服务器内存中(测试使用)
# 服务器内存的缓存配置 (settings.py中添加)
CACHES = {
'default':{
'BACKEND':'django.core.cache.backends.locmem.LocMemCache',
'LOCATION':'unique-snowflake'
}
}
3.将缓存的数据存储到本地文件中
# 文件系统的缓存配置
CACHES = {
'default':{
'BACKEND':'django.core.cache.backends.filebased.FileBasedCache',
'LOCATION':'/var/tmp/django_cache', # 缓存文件夹的路径
# 'LOCATION':'c:\test\cache', # windows下示例,缓存文件夹的路径
}
}
# 1.视图函数使用缓存(即装饰器使用)
from django.views.decorators.cache import cache_page
@cache_page(30) # 单位(s)
def my_view(request):
pass
# 2.路由中使用缓存(urls.py)
from django.views.decorators.cache import cache_page
from note import views
urlpatterns = [
path('note/all',cache_page(30)(views.my_view))
]
# 方式1:引入cache对象,使用 caches['CACHE配置 KEY'] 导入具体对象
from django.core.cache import caches
cache = caches['default']
cache1 = caches['myalias']
cache2 = caches['myalias_2']
# 方式2:相当于直接引入 CACHES配置项中的 'default'项
from django.core.cache import cache
#
# 1.存储缓存
cache.set(key,value,timeout)
# key:缓存的key,字符串类型
# value:Python对象
# timeout:缓存存储时间(s),默认为CACHES的TIMEOUT值
# 返回值:None
# 2.获取缓存
cache.get(key)
# key:缓存的key,字符串类型
# 返回值:key的具体指,若无,则为None
# 3.储存缓存,只在 key 不存在时生效
cache.add(key,value)
# 返回值:True[存储成功] or False[存储失败]
# 4.若为获取到数据,则执行 set操作
cache.get_or_set(key,value,timeout)
# 返回值:value
# 5.批量存储缓存
cache.set_many(dict,timeout)
# 返回值:插入不成功的key的数组
# 6.批量获取缓存数据
cache.get_many(key_list)
# 返回值:取到的key和value的字典
# 7.删除key的缓存数据
cache.delete(key)
cache.delete_many(key_list)
# 返回值:None
不会向服务器发送请求,直接从缓存中读取资源
响应头 - Expires
响应头 - Casche-Control
强缓存中数据过期后,浏览器会和服务器协商,当前缓存是否可用,可用则无需返回,否则返回最新数据
1.Last-Modeified响应头 和 If-Modified-Since 请求头
2.ETag 响应头 和 If-None-Match请求头
Etag是服务器返回当前资源文件的一个唯一标识(如哈希值),资源变化,Etag重新生成
缓存到期后,浏览器将ETag值 作为 If-None-Match请求头的值 进行协商,服务器比对文件标识,一致则返回 304 响应码,不一致则返回 200 响应码【响应体为最新资源】
# 中间件配置
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',
'middleware.mymiddleware.MyMW',
]
中间件中大多数方法在返回None时表示忽略当前操作进入下一项事件,返回HttpResponse对象时表示此请求结束,直接返回给客户端。
class MyMW(MiddlewareMixin):
# 执行路由前被调用,在每个请求上调用,返回None 或 HttpResponse对象
def process_request(self,request):
print('MyMW process_request do ---')
# 调用视图前被调用,返回None 或 HttpResponse对象
def process_view(self,request,callback,callback_args,callback_kwargs):
print('MyMW process_views do --')
# 所有响应返回浏览器 被调用,返回HttpResponse对象
def process_response(self,request,response):
print('MyMW process_response do ---')
return response
# 当处理过程中抛出异常时调用,返回一个HttpResponse对象
def process_exception(self,request,exception):
print('MyMW process_exception do ----')
# 在视图函数执行完毕 且 试图返回的对象中包含 render 方法时被调用,
# 该方法需要返回实现了 render 方法的相应对象
def process_template_response(self,request,response):
print('MyMW process_template_response')
return response
class VisitLimit(MiddlewareMixin):
visit_times = {}
def process_request(self,request):
ip = request.META['REMOTE_ADDR']
path_url = request.path_info
if not re.match('^/note',path_url):
return
times = self.visit_times.get(ip,0)
print('ip', ip,'已经访问',times)
self.visit_times[ip] =times+1
if times < 6:
return
return HttpResponse('您已经访问过'+str(times)+'次,访问被禁止')
# 中间件配置
MIDDLEWARE = [
'django.middleware.csrf.CsrfViewMiddleware',
]
若某个视图不需要django进行csrf保护,可以用装饰器 (csrf_exempt) 关闭对此视图的检查
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def my_view(request):
return HttpResponse('Hello world')
paginator负责分页数据整体的管理
Paginator属性
from django.core.paginator import Paginator
# /test_page/3
def test_page(request,page_num):
object_list= ['1','2','3','4','5'] # 需要分页数据的对象列表
per_page = 3 # 每页数据个数
# 初始化paginator
paginator = Paginator(object_list,per_page)
# 初始化 具体页码的page对象
c_page = paginator(int(page_num))
return render(request,'test_page.html', locals())
负责具体某一页的数据的管理 ( page = paginator.page(number) )
若提供页码不存在,则抛出InvalidPage异常
InvalidPage 总的异常基类
Page对象属性
CSV文件下载注意:
def csvload_note(request,page_num):
# 获取当前页的数据
uid = request.session.get('uid')
notes = Note.objects.filter(user_id=uid, is_active=True)
# 初始化 分页对象 paginator
paginator = Paginator(notes, 5)
# 初始化 具体页码的page对象
c_page = paginator.page(page_num)
# 修改响应头符合浏览器 csv 保存模式
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment;filename="note-%s.csv"' % (page_num)
# 调用 csv 的写方法,并写入数据
writer = csv.writer(response)
writer.writerow(['id','titel','content','created_time','updated_time','user_id'])
for note in c_page.object_list:
writer.writerow([note.id,note.title,note.content,note.created_time,note.updated_time,note.user_id])
return response
<html lang="en">
<head>
<meta charset="UTF-8">
<title>上传文件title>
head>
<body>
<form action="/note/test_upload" method="post" enctype="multipart/form-data">
{% csrf_token %}
<input type="text" name="title">
<input type="file" name="myfile">
<input type="submit" value="上传">
form>
body>
html>
视图函数中,用 file=request.FILES[‘xxxx’] 取 文件框的内容
# file:settings.py
MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR/'media'
# 在主路由中 添加路由,
# 等价于 做了MEDIA_URL开头的路由,Django接到该特征请求后去MEDIA_ROOT路径查找资源
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
]
urlpatterns += static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT)
# 方案一:传统的open方式 (不推荐),会出现文件重名判断并修改问题
@csrf_exempt
def upload_view(request):
if request.method == 'GET':
return render(request,'test_upload.html')
elif request.method == 'POST':
a_file = request.FILES['myfile']
print('上传文件名:',a_file.name)
filename = settings.MEDIA_ROOT/a_file.name
with open(filename,'wb') as f:
data = a_file.file.read()
f.write(data)
return HttpResponse("接收文件:"+a_file.name+"成功")
# 方案二:借助ORM
# 新增模型类,(如Content),包含字段: FileField(upload='子目录名')
class Content(models.Model):
desc = models.CharField('描述',max_length=11)
myfile = models.FileField(upload_to='myfile')
# 视图操作
def test_load(request):
if request.method == 'GET':
return render(request,'note/test_upload.html')
elif request.method == 'POST':
title = request.POST.get('title')
a_file = request.FILES['myfile']
Content.objects.create(desc=title,myfile=a_file)
return HttpResponse('---上传文件成功---')
SMTP
IMAP
from django.contrib.auth.models import User
settings.py配置
# 未登录情况下的跳转地址
LOGIN_URL='/login'
以下含7种内置操作:
# 1.创建普通用户 create_user
from django.contrib.auth.models import User
user = User.objects.create_user(username='用户名',password='密码',...)
# 注意,此时密码由该方法 哈希加密过(不用自己重新加密)
# 2.创建超级用户 create_superuser
user = User.objects.create_superuser(username='用户名',password='密码',...)
# 3.校验密码 authenticate
from django.contrib.auth import authenticate
user = authenticate(username=username,password=password)
# 如果用户名密码检验成功,则返回对应的 User对象,否则返回 None
# 4.修改密码 set_password
try:
user = User.objects.get(username='test')
user.set_password('123456')
user.save()
return HttpResponse("修改密码成功!")
except:
return HttpResponse("修改密码失败!")
# 5.登录状态保持 login
from django.contrib.auth import login
def login_view(request):
user = authenticate(username=username,password=password)
login(request,user)
# 6.登陆状态校验(login_required 装饰器 等同于 自建的check_login)
from django.contrib.auth decorators import login_required
@login_required
def index_view(request):
# 该视图必须为用户登陆状态下才可访问,未登录跳转至 settings.LOGIN_URL
# 当前登录用户可通过request.user 获取
login_user = request.user ....
# 7.登录状态取消 logout
from django.contrib.auth import logout
def logout_view(request):
logout(request)
# 1.添加user应用 python manage.py startapp user
# 2.user/models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
class UserInfo(AbstractUser):
# 新增手机号,其余字段继承了 User表
phone = models.CharField(max_length=11,default='')
# 3.settings.py添加配置
AUTH_USER_MODEL = 'user.UserInfo'
# 4.用户系统操作 和内建表 使用相同,如添加用户
from user.models import UserInfo
UserInfo.objects.create_user(username='test1',password='123456',phone='13211112131')
在软件开发完毕后,将开发机器上运行的软件实际安装到服务器上进行长期运行
WSGI (Web Server Gateway Interface) Web服务器网关接口
[uwsgi]
# 注意 socket 和 http 二选一
# socket = 127.0.0.1:8000 # 套接字方式的IP地址:端口号【此模式需要有nginx】
http = 127.0.0.1:8000 # Http通信方式的IP地址:端口号
chdir = C:\Users\Administrator\tedu_note # 项目当前工作目录(绝对路径)
wsgi-file = tedu_note/wsgi.py # 项目中wsgi.py文件目录,当前工作目录(相对路径)
process = 4 # 进程个数, CPU核心数量最小值
theads = 2 # 每个进程的线程个数
pidfile = uwsgi.pid # 服务的pid记录文件
daemonize = uwsgi.log # 服务的日志文件位置
master = True # 开启主进程管理模式
1.无论是启动还是关闭,都需执行 ps aux|grep ‘uwsgi’ 确认是否符合预期
2.启动成功后,进程在后台执行,所以日志输出在配置文件所在目录 uwsgi.log中
3.Django中代码有任何修改,需要重新启动uwsgi
1.启动失败:端口被占用(被其他进程占用uWSGI启动端口)
解决:可执行 sudo lsof -i:端口号 查询出具体进程;kill 进程后 sudo kill -9 PID,重启即可
2.停止失败:stop无法关闭uWSGI(重复启动uWSGI,导致pid文件中进程号失准)
解决:ps出WSGI进程,手动kill即可 sudo kill -9 PID
Nginx是轻量级的高性能Web服务器,提供了诸如HTTP代理和反向代理、负载均衡等
C语言编写,执行效率高
nginx作用 :
-负载均衡、多台服务器轮流处理请求
-反向代理
原理:
-客户端请求nginx,再由nginx将请求转发uWSGI进行的django
sudo apt install nginx 如果下载慢,考虑更换为国内源
-vim /etc /apt/sources.list
-sudo apt-get update
安装后,ubuntu终端输入 nginx -v 查看nginx version 是否成功即可
修改nginx的配置文件
-sudo vim /etc/nginx/sites-enabled/default
-关闭 vim,输入 :wq
-检查配置文件语法 sudo nginx -t
# 在server节点下添加新的location项,指向uwsgi的ip与端口
server{
location / {
# try_files $uri/ =404 #需要将其禁用,对转发而言无用
uwsgi_pass 127.0.0.1:8000; # 重定向到127.0.0.1的8000端口
include /etc/nginx/uwsgi_params; # 将所有的参数转到uwsgi下
}
}
# 方式1 :
sudo /etc/init.d/nginx start|stop|restart|status
# 方式2:
sudo service nginx start|stop|restart|status
# 注意:nginx配置只要修改,就需要进行重启,否则配置不生效
说明nginx负责接收请求,并把请求转发给后面的uWSGI
此模式下,uWSGI需要以 socket 模式启动
[uwsgi]
# 套接字方式的IP地址:端口号【此模式需要有nginx】
socket = 127.0.0.1:8000
# 去掉http
# http = 127.0.0.1:8000
STATIC_ROOT = '/home/pp/项目名_static/static'
#注意: 此配置路径为 存放正式环境中需要的静态文件
# 进入file:sudo vim /etc/nginx/sites-enabled/default
# 新添加 location /static 路由配置,重定向到 指定文件路径
server{
location /static {
# root 第一步创建文件夹的绝对路径,如:
root /home/pp/项目名_static;
}
}
1.访问127.0.0.1:80地址,502响应
502响应 代表nginx反向代理配置成功,但是对应的uWSGI未启动
2.访问127.0.0.1:80/url 404响应
1)路由的确不在django配置中
2)nginx配置错误,未禁止掉 try_files