1.不使用自带模块<Paginator>的手写分页功能
views.py
def post_list(request):
page = request.GET.get('page', 1) # 获取页面点击的page, 默认显示第一页
page = int(page)
start = (page - 1) * 5
end = page * 5 # start + 5
posts = Post.objects.all()[start:end] # select * from post limit 5 offset 0 --> offset 偏移
num = Post.objects.count() # 文章总数
pages = ceil(num / 5) # ceil(num / 5)
return render(request, 'post_list.html', {'posts': posts, 'pages': range(1, pages + 1)})
html
{% for n in pages %}
<li><a href="/post/list/?page={{n}}">{{n}}</a></li>
{% endfor %}
2.存储密码为密文->使用django自带的
from django.contrib.auth.hashers import make_password, check_password
示例:
在保存密码时 make_password
password = make_password(request.POST.get('password'))
在需要验证密码时 check_password
check_password(password, user.password) 返回布尔值
3.需要更新数据内容时,采用的方法
先从数据库中获取到相应的数据
post = Post.objects.get(id=post_id)
更新数据
post.title = request.POST.get('title')
post.content = request.POST.get('content')
post.save()
4.图片在本地上传成头像
方法一: 线上不可用
在views.py中处理为链接的形式,然后把链接保存到数据库中
for key in request.FILES: # 处理图片
file_list = request.FILES.getlist(key)
for file in file_list:
file_path = os.path.join(settings.MEDIA_ROOT, file.name)
with open(file_path, 'wb') as f:
for data in file.chunks():
f.write(data)
file_path_list = file_path.split('\\')
icon = 'http://localhost:8888/' + file_path_list[0] + '/' + file_path_list[1]
方法二: 利用django自带的form模块
创建forms.py文件, 封装RegisterForm类,继承forms.ModelForm
from django import forms
from user.models import User
class RegisterForm(forms.ModelForm):
class Meta:
model = User
fields = ['neck_name', 'password', 'icon', 'age', 'sex']
password2 = forms.CharField(max_length=128)
def clean_password2(self):
cleaned_data = super().clean()
if cleaned_data['password'] != cleaned_data['password2']:
raise forms.ValidationError('密码不一致')
views.py
def user_register(request):
if request.method == 'POST':
form = RegisterForm(request.POST, request.FILES)
if form.is_valid(): # 判断数据
user = form.save(commit=False) # 得到user对象,不commit到数据库
user.password = make_password(user.password) # 单向加密密码
user.save() # 把检验没有问题的数据保存到数据库
# 写入session数据
request.session['uid'] = user.id
request.session['nick_name'] = user.neck_name
return redirect('/')
else:
return render(request, '', {'error': form.errors})
return render(request, 'register.html')
在urls.py中需要添加 把medias目录设置为可在浏览器查看的路由
from django.conf.urls.static import static
from django.conf import settings
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
html表单中
<form class="form-horizontal" method="POST" action="/user/register/" enctype=multipart/form-data> 必须加
启动服务过程中可能会遇到要装一个模块,属于正常,用于显示头像
5.在标签中添加过滤器
{{post.content|safe|escape|linebreaks}} -> 具体含义http://lishiguang.iteye.com/blog/1332529/
6.在html中设置只读文本框 把变量传入input标签的value属性中
<input class="form-control" value="{{foo.age}}" readonly>
7.form表单
自动处理clean_开头,后面跟字段的函数
error 返回前端是 转换成js as_js()方法
8.from hashlib import md5, sha256 单项加密
m = md5(b'12345678')
m.hexdigest()
加密后的数据
md5sum 文件名 文件加密
9.session()
未登录使用session(),缓存浏览记录
sessionid 本质就是唯一标记每个浏览器 浏览器和服务器发生的会话
10.redis
set 差集 -
交集 &
并集 |
缓存 -> 只缓存get请求
配置redis缓存,不使用django自带的cache:
安装django-redis模块,使用缓存时,还是调用 from django.core.cache import cache ,常用的get set 方法
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/1",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"PICKLE_VERSION": -1,
}
}
}
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
11.装饰器 添加缓存
装饰器传参数 -> 在装饰器外再套一层函数
多个装饰器同时使用 - > 先调用距离函数最近的装饰器,上面的装饰器装饰下面运行完的返回函数
示例:
def page_cache(content): # page_cache装饰器
def wrap1(view_func):
def wrap2(request, *args, **kwargs):
key = 'Response-{}'.format(request.get_full_path()) # 拼接唯一的key
response = cache.get(key) # 从缓存中获取数据
print('从缓存中获取数据:{}'.format(response))
if response is None:
# 获取数据库中的数据,在添加到缓存中
response = view_func(request, *args, **kwargs)
cache.set(key, response, content)
print('从数据库中获取:{}'.format(response))
return response
return wrap2
return wrap1
12.函数传参 *
调用的时候传参 foo(*L) 如果L是list,元组,会反向解析出来,再传递给foo函数
foo(**L) 如果L是字典,会反向解析出来,再传递给foo函数
定义函数时传参 foo(3, * , z, y=5) 在调用函数时,*后面的参数必须显式的传递参数.如在调用时:foo(3, z=5, y=3)
13.推导式
list [i*3 for i in range(10)]
dict {i: i*3 for i in range(10)}
set {i*3 for i in range(10)}
13.热门文章排行
定义函数:
def get_top_n(n):
'''获取 Top N'''
# zrevrange 数据格式
# [
# (b'9', 64.0),
# (b'5', 37.0),
# (b'12', 34.0),
# ...
# ]
rank_data = r.zrevrange('ReadRank', 0, n - 1, withscores=True)
# 第一次类型转换
# [
# [9, 64],
# [5, 37],
# [12, 34],
# ...
# ]
rank_data = [[int(post_id), int(num)] for post_id, num in rank_data]
post_id_list = [d[0] for d in rank_data] # 取出每一项的 post_id
posts = {post.id: post for post in Post.objects.filter(id__in=post_id_list)} # 取出每一项对应的 post 实例
# 第二次类型转换
# [
# [<Post: Post object>, 64],
# [<Post: Post object>, 37],
# [<Post: Post object>, 34],
# ...
# ]
rank_data = [[posts[post_id], num] for post_id, num in rank_data]
return rank_data
在top10 views函数中调用,在从缓存中取数据和数据库取数据时设置点击数量加1的缓存
if response:
if view_func.__name__ == 'read_post':
print('点击量加1')
r.zincrby('ReadRank', int(request.GET.get('post_id')))
14,限制用户每秒请求次数
创建middleware.py中间件
import time
from django.utils.deprecation import MiddlewareMixin
def check_request_rate(request):
request_time = request.session.get('request_time', [0, 0])
now = time.time()
if (now - request_time[0]) < 1:
time.sleep(2)
# 更新时间列表
request_time = [request_time[1], time.time()]
else:
request_time = [request_time[1], now]
request.session['request_time'] = request_time # 更新session
class BlockMiddleware(MiddlewareMixin):
"""
2018-03-23 15:29:1.02
2018-03-23 15:29:1.21
2018-03-23 15:29:2.42
2018-03-23 15:29:2.52 <- 当前时刻
记录在哪? session
以什么形式记录?数据结构? [1.82, 2.42, 2.52]
保留多少记录? count
"""
def process_request(self, request):
check_request_rate(request)
def block_middleware(get_response):
"""装饰器中间件"""
def wrap(request, *args, **kwargs):
check_request_rate(request)
response = get_response(request, *args, **kwargs) # 调用View函数
return response
return wrap
settings.py中添加
MIDDLEWARE = [
'post.middleware.block_middleware',
]
特别鸣谢 好多人。。。。