一、文件上传
form表单中需要添加 enctype="multipart/form-data"
1.media: 文件上传的文件
在settings.py 文件中配置:
MEDIA_URL = '/static/media/' #媒体路径
MEDIA_ROOT = os.path.join(BASE_DIR, 'static/media') #必须是绝对路径
static
|-- media
|-- uploads
|---2019
|---05
|---文件名
#模板中如果想引用上传的文件并展示,
在模板中可以使用{{ MEDIA_URL }}
->TEMPLATES
-> 'context_processors': [
...
django.template.context_processors.media
...
]
在主路由中添加:
re_path(r'^media/(?P<path>.*)$', serve, {'document_root': MEDIA_ROOT})
模板中使用
<img src="{{ MEDIA_URL }}{{ user.icon }}" alt="" id="icon">
2.模型: FileField(任何文件)
ImageField(只能是图片)---->继承自FileField
FileField(upload_to='表示文件上传的路径 uploads/%Y/%m')
--->此路径是基于media_root指明的路径
ImageField(upload_to='相对路径')
使用ImageField文件上传
icon = models.ImageField(upload_to='uploads/%Y/%m/%d',default="uploads/mine1.png")
icon = request.FILES.get('icon') -----> 内存 的存储对象
user.username = username
user.email = email
user.mobile = mobile
user.icon = icon # ImageField(upload_to='')
user.save()
user.icon ----> 不是存储字符串,ImageField
user.icon.name ----> 字符串值
二、系统默认用户的继承使用:
1.必须继承AbstractUser ----》auth_user ----> 系统用户
class UserProfile(AbstractUser):
mobile = models.CharField(max_length=11, verbose_name='手机号码', unique=True)
icon = models.ImageField(upload_to='uploads/%Y/%m/%d')
class Meta:
db_table = 'userprofile'
verbose_name = '用户表'
verbose_name_plural = verbose_name
2.必须修改settings.py
# 如果用户继承了AbstractUser,修改auth_user的模型
AUTH_USER_MODEL = 'user.UserProfile'
3.然后执行迁移和同步
authenticate() (认证)---》user =====》 login(request,user)----> session保存和request.user赋值
logout()----》清空session和cookie,将request.user设置成匿名的User()
is_authenticated() ----> 判断用户是否被认证 request.user.is_authenticated()
三、forms 表单:
问题:使用ModelForm好像按照注册搞,不能输入数据库已存在的用户名??
Django会处理涉及表单的三个不同部分:
准备并重组数据,以便下一步的渲染
为数据创建HTML 表单
接收并处理客户端提交的表单及数据
1.Form 和 ModelForm
Form比较灵活需要自己定义各个要验证的字段
Form使用:
class UserRegisterForm(Form):
username = forms.CharField(max_length=50, min_length=6, error_messages={'min_length': '用户名长度至少6位', }, label='用户名')
email = forms.EmailField(required=True, error_messages={'required': '必须填写邮箱信息'}, label='邮箱')
mobile = forms.CharField(required=True, error_messages={'required': '必须填写手机号码'}, label='手机')
password = forms.CharField(required=True, error_messages={'required': '必须填写密码'}, label='密码',widget=forms.widgets.PasswordInput)
#widget插件,密码隐藏
ModelForm是跟Model有关的,model的字段可以直接引用过来。
ModelForm使用:
class RegisterForm(ModelForm):
repassword = forms.CharField(required=True, error_messages={'required': '必须填写确认密码'}, label='确认密码', widget=forms.widgets.PasswordInput)
class Meta:
model = UserProfile
fields = ['username', 'email', 'mobile', 'password'] ---->可以自己添加需要验证的字段
# fields = '__all__' ----》 如果是model中的所有字段都需要验证可以使用__all__
# exclude = ['first_name','date_joined','last_name'] -----> 使用exclude排除不需要验证的部分
2.定义一些指定字段的专门验证:
def clean_username(self):
username = self.cleaned_data.get('username')
result = re.match(r'[a-zA-Z]\w{5,}', username)
if not result:
raise ValidationError('用户名必须字母开头')
return username
或者
def clean_username(self):
username = self.cleaned_data.get('username')
if not UserProfile.objects.filter(username=username).exists():
raise ValidationError('用户名不存在')
return username
或者验证密码与确认密码是否一致
def clean_password(self):
repassword = self.cleaned_data.get('repassword')
password = self.cleaned_data.get('psssword')
if password != repassword:
raise ValidationError('密码不一致')
return password
在views中接收用rform.is_valid()
3.密码加密和检查密码:
check_password(原文密码,加密密码) -----》返回结果是boolean
make_password(原文密码) -----》加密密码返回结果是加密后的密码
cookies实现登录退出
https://www.cnblogs.com/banshaohuan/p/9493021.html
https://blog.csdn.net/weixin_33918357/article/details/85629371?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromBaidu-1.control&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromBaidu-1.control
4.session的使用:
request.session request里面的一个属性,而且是字典类型
设置session的值:
request.session['key']=value
取值:
value = request.session.get(key)
清除session:
request.session.clear() # 删除字典
request.session.flush() # 删除django_session + cookie +字典
del request.session[key] # 删除指定的key
5.继承abstractuser的用户
from django.contrib.auth import logout,login,authenticate
authenticate+login 先使用authenticate 进行用户的数据库查询判断,如果有则返回用户对象
login(request,user) ---->类似session 只不过: request.user=user
#将用户对象保存在底层的request中
request.user.is_authenticated 是否是认证过的用户返回值是True,False
两种方式登录
username = lform.cleaned_data.get('username')
password = lform.cleaned_data.get('password')
# 方式一
# user = UserProfile.objects.filter(username=username).first()
# print(password, user.password, make_password(password))
# flag = check_password(password, user.password)
# if flag:
# request.session['username'] = username
# 方式二
user=authenticate(username=username,password=password)【必须是明文密码,从数据库中取出来加密的不可以】
if user:
login(request,user)
return redirect(reverse('index'))
return render(request, 'user/login.html', context={'msg': "用户名或密码有误"})
两种方式注销:
# 方式一:
# request.session.flush()
# 方式二:
logout(request)
两种方式验证是否登录:
{# 方式一#}
{# {% if request.session.username %}#}
{# 欢迎!<a href="">{{ request.session.username }}</a> #}
{# <a href="{% url 'user:logout' %}">注销</a>#}
{# 方式二#}
{% if request.user.is_authenticated %}
欢迎!<a href="">{{ request.user.username }}</a>
<a href="{% url 'user:logout' %}">注销</a>
{% else %}
<a href="{% url 'user:login' %}">登录</a>
<a href="{% url 'user:register' %}">注册</a>
{% endif %}
四、发送手机验证码:第三方
写账号密码登陆和验证码登陆的切换页
使用网易云信:
https://dev.yunxin.163.com/docs/product/%E7%9F%AD%E4%BF%A1/%E7%9F%AD%E4%BF%A1%E6%8E%A5%E5%8F%A3%E6%8C%87%E5%8D%97
模拟浏览器发送请求:
pip install requests
1.流程
发送验证码:
---》 send_code ----> ajax ----》sendcode + mobile
-----》后台:mobile -----》使用requests(浏览器)
2.定义工具类
#作用就是向网易云信发送请求,帮助后台发送短信息给客户
def util_sendmsg(mobile):
url ='https://api.netease.im/sms/' ---->访问网易云信的url地址
data={'mobile':你的手机号码} ----
AppKey =‘’ #开发者平台发布的
Nonce=‘’ #随机数
CurTime=str(time) #时间戳
AppSecret=''
content=AppSecrect+Nonce+CurTime
CheckSum=hashlib.sha1(appsecret+Nonce+CurTime)
headers={} -----》4 部分
response = requests.post(url,data,headers)
str = response.Text
json = json.loads(str)
json.code
json.obj ----> 发送的验证码
保存到session
五、生成图形验证码(使用插件)
文档地址:
https://django-simple-captcha.readthedocs.io/en/latest/usage.html
1.插件安装步骤
1.pip install django-simple-captcha
2.Add captcha to the INSTALLED_APPS in your settings.py
3.Run python manage.py migrate------》数据库自动添加表(captcha-captchastore)
4。Add an entry to your urls.py:
re_path(r'^captcha/',include('captcha.urls'))
2.使用验证码插件步骤
Form使用
1.# 验证码captcha的Form
class CaptchaTestForm(forms.Form):
email = EmailField(required=True, error_messages={'required': '必须填写邮箱'},label='邮箱')
captcha = CaptchaField()
产生的图形就是一张图片。img+hidden
2.使用CaptchaTestForm渲染页面:
if request.method == 'GET':
form = CaptchaTestForm()
return render(request, 'user/forget_pwd.html', context={'form': form})
3.页面中使用captcha:
<div class="w3layouts-main">
<p>{{ msg }} {{ errors }}</p>
<form action="{% url 'user:forget_pwd' %}" method="post"> {% csrf_token %}
{{ form.email }}
{{ form.captcha }}
<input type="submit" value="找回密码">
</form>
</div>
3.刷新验证
$('.captcha').click(function(){
var img= $(this);
$.getJSON('/captcha/refresh',function(data){
console.log(data)
img.attr('src',data['image_url']); #attr是一个属性
$('#id_captcha_0').val(data['key'])
})
});
4.验证验证码是否正确
$('#id_captcha_1').blur(function(){
var $this = $(this);
var key = $('#id_captcha_0').val();
var code = $(this).val();
$.getJSON('{% url 'user:valide_code' %}',{key:key,code:code},function(data){
console.log(data)
if(data.status==1){
$this.after('<span>验证码正确</span>')
}else{
$this.after('<span>验证码错误</span>')
}
})
})
路由:valide_code
# 定义一个路由验证验证码
def valide_code(request):
if request.is_ajax():
key = request.GET.get('key')
code = request.GET.get('code')
# CaptchaStore 模型对象
captche = CaptchaStore.objects.filter(hashkey=key).first()
if captche.response == code.lower():
# 正确
data = {'status': 1}
else:
# 错误的
data = {'status': 0}
return JsonResponse(data)
六、发送邮件
1.邮件的配置
在settings.py中配置:
EMAIL_HOST = 'smtp.126.com'
EMAIL_HOST_USER = 'student1902@126.com'
EMAIL_HOST_PASSWORD = 'student1902' #邮箱的授权码
EMAIL_PORT = 25
EMAIL_USE_TLS = True
EMAIL_USE_SSL = False # 126,QQ: 465 163:454
2.调用方法
send_mail(subject,message,from,to_list)
发送成功就是1 否则0
message与html_message的区别
ran_code = uuid.uuid4()
ran_code = str(ran_code)
ran_code =ran_code.replace('-','')
request.session[ran_code] = user.id
3.进行激活
密码和确认密码+ 隐藏表单域(code)
code = request.POST.get('code')
uid = request.session.get(code)
user = UserProfile.objects.get(pk=uid)
# 获取密码
pwd = request.POST.get('password')
repwd = request.POST.get('repassword')
if pwd == repwd and user:
pwd = make_password(pwd)
user.password = pwd
user.save()
return render(request, 'user/update_pwd.html', context={'msg':'用户密码更新成功!'})
else:
return render(request, 'user/update_pwd.html', context={'msg': '更新失败!'})
七、中间件(类似flask 钩子函数)
https://www.cnblogs.com/sui776265233/p/9664642.html
1.中间件应用场景
由于中间件工作在 视图函数执行前、执行后适合所有的请求/一部分请求做批量处理。
1、做IP限制
放在中间件类的列表中,阻止某些IP访问了;
2.URL访问过滤
如果用户访问的是login视图(放过)
如果访问其他视图(需要检测是不是有session已经有了放行,没有返回login),这样就省得在 多个视图函数上写装饰器了!
3、缓存(CDN)
客户端请求来了,中间件去缓存看看有没有数据,有直接返回给用户,没有再去逻辑层 执行视图函数
2.进行用户的登录验证
步骤:
1. middreware文件夹----》 xxxmiddleware.py ---->定义类继承MiddlewareMixin
2. 重写:
如果仅仅是对请求做处理则重写的方法名:process_request(self,request)
3. 参数request:参数request是请求对象
request.path
request.method
request.is_ajax()
request.META.get('REMOTE_ADDR')
if path in login_list:
print(request.user) # AnonymousUser 未登录
print(type(request.user))
print(request.user.username) # 认为就是用户登录的对象
if not request.user.is_authenticated:
return redirect(reverse('user:login'))
@login_required 前提(要验证的用户必须是继承自AbstractUser)
login(request,user)
request.user.is_authenticated
@login_required
def user_center(request):
return HttpResponse('用户中心')
改变页面跳转需要在settings.py文件中设置:
LOGIN_URL = '/user/login'
# 添加一个登陆路由 结合 @login_required
3.中间件的默认可以自定义的函数
-
Request预处理函数: process_request(self, request)
这个方法的调用时机在Django接收到request之后,但仍未解析URL以确定应当运行的视图函数。Django向它传入相应的Request对象,以便在方法中修改。 如果返回None,Django将继续处理这个request,执行后续的中间件, 然后调用相应的 view。 如果返回HttpResponse对象,Django将不再执行任何除了process_response以外其它的中间件以及相应的view,Django将立即返回该HttpResponse。
-
View预处理函数: process_view(self, request, callback)
callback_args,callback_kwargs) 这个方法的调用时机在 Django 执行完 request 预处理函数并确定待执行的 view (即callback参数)之后,但在 view 函数实际执行之前。 request:HttpRequest 对象。 callback:Django将调用的处理request的python函数. 这是实际的函数对象本身, 而不是字符串表述的函数名。 args:将传入view的位置参数列表,但不包括request参数(它通常是传入view的第一个参数)。 kwargs:将传入view的关键字参数字典。 process_view() 应当返回None或 HttpResponse 对象。如果返回 None, Django将继续处理这个request ,执行后续的中间件, 然后调用相应的view。 如果返回 HttpResponse 对象,Django 将不再执行任何其它的中间件(不论种类)以及相应的view,Django将立即返回。
-
Template模版渲染函数:process_template_response()
默认不执行,只有在视图函数的返回结果对象中有render方法才会执行,并把对象的render方法的返回值返回给用户 (注意不返回视图函数的return的结果了,而是返回视图函数 return值(对象)中rende方法的结果)
-
Exception后处理函数:process_exception(self, request, exception)
这个方法只有在 request 处理过程中出了问题并且view 函数抛出了一个未捕获的异常时才会被调用。这个钩子可以用来发送错误通知,将现场相关信息输出到日志文件,或者甚至尝试从错误中自动恢复。 这个函数的参数除了一贯的request对象之外,还包括view函数抛出的实际的异常对象exception 。 process_exception() 应当返回None或HttpResponse对象。 如果返回None,Django将用框架内置的异常处理机制继续处理相应request。 如果返回HttpResponse对象,Django将使用该response对象,而短路框架内置的异常处理机制。
-
Response后处理函数:process_response(self, request, response)
这个方法的调用时机在 Django 执行 view 函数并生成 response 之后。 该处理器能修改response 的内容;一个常见的用途是内容压缩,如gzip所请求的HTML页面。 这个方法的参数相当直观:request是request对象,而response则是从view中返回的response对象。 process_response() 必须返回 HttpResponse 对象. 这个 response 对象可以是传入函数的那一个原始对象(通常已被修改),也可以是全新生成的
九、云存储(七牛云)
1.注册用户
2.创建存储空间,测试域名(30天)
3.文档中心:https://developer.qiniu.com/kodo/sdk/1242/python
4.在项目中使用:
#上传图片到七牛云
def upload_image(storeobj):
# 只要注册用户就会有默认的access_key,secret_key
access_key = '1fXvG9wkbN7AgRUG6usHDcRP5Bb85apcovRAIITP'
secret_key = 'Aqf1lPAmUG72EdZJ7PxKtWHfWDYNdUycZP1TaAIN'
# 构建鉴权对象
q = Auth(access_key, secret_key)
# 要上传的空间
bucket_name = 'myblog'
# 上传后保存的文件名
key = storeobj.name
# 生成上传 Token,可以指定过期时间等
token = q.upload_token(bucket_name, key, 3600)
# 要上传文件的本地路径
# localfile = os.path.join(MEDIA_ROOT, imagepath) # 本地图片路径
ret, info = put_data(token, key, storeobj.read()) # 第三个参数是二进制流
ret,info = put_file(token,key,localfile) # 第三个参数是文件的路径
print(ret, info)
filename = ret.get('key')
save_path = 'http://pr67kkhq9.bkt.clouddn.com/'+filename
return save_path
接口:
模板:给用户看的
model 模型
view 视图 + url路由 ----》 类视图
url:------》 json ----》前端
app(vue) + 后端 --------》 前后端分离
十、xadmin与admin
https://xadmin.readthedocs.io/en/docs-chinese/quickstart.html#id1
git里下载zip并解压
cmd进入requirements.txt文件夹
workon 切换到虚拟环境
pip install -r requirements.txt
将解压后文件夹中的xadmin文件夹复制到项目下
使用:
https://blog.csdn.net/xinyan233/article/details/80399534
xadmin就是admin的升级版,样式,操作方便
1.xadmin的安装
不推荐:pip install xadmin
推荐源码安装:
xxxdjango2.0-xadmin.zip
|--django2.0-xadmin
|--- xadmin
|---requirements.txt
pip install -r requirements.txt
xadmin复制到项目下
2.相关配置
-
配置settings.py
INSTALLED_APPS=[ ... 'xadmin', 'crispy_forms' ]
-
配置主路由
主路由: path('xadmin/',xadmin.site.urls)
-
迁移同步
python manage.py makemigrations python manage.py migrate
-
注册models
你的app |--admin.py |--xadmin.py -----> xadmin.site.register(xxxModel) xadmin.site.register(Article,ArticleAdmin) xadmin.site.register(Tag)
3.相关设置
-
article/adminx.py
class ArticleAdmin(object): list_display = ['title', 'click_num', 'love_num', 'user'] #显示自己想看的列 search_fields= ['title','id'] #用于检索的列 list_editable= ['click_num','love_num'] #可编辑的列 list_filter=['date','user'] #可用于过滤的列
-
acticle/apps.py
class ArticleConfig(AppConfig): name = 'article' verbose_name = '文章操作'
-
init.py
default_app_config = 'article.apps.ArticleConfig'
-
user/adminx.py:主题设置
class BaseSettings(object): enable_themes = True use_bootswatch = True class GlobalSettings(object): site_title = '博客后台管理' site_footer = '达达的博客公司' # 注册 xadmin.site.register(views.BaseAdminView, BaseSettings) xadmin.site.register(views.CommAdminView, GlobalSettings)
十一、分页:Paginator,Page
paginator = Paginator(articles, 3) # Paginator(对象列表,每页几条记录)
-
分页器属性
print(paginator.count) # 总的条目数 总的记录数 print(paginator.num_pages) # 可以分页的数量 总的页码数 print(paginator.page_range) # 页面的范围
-
方法: get_page()
page = request.GET.get('page',1) page = paginator.get_page(page) # 返回的是page对象 参数就是页码数
-
方法
page.has_next() # 有没有下一页 page.has_previous() # 判断是否存在前一页 page.next_page_number() # 获取下一页的页码数 page.previous_page_number() # 获取前一页的页码数
-
属性:
object_list 当前页的所有对象 number 当前的页码数 paginator 分页器对象
十二、富文本:ckeditor
https://www.jianshu.com/p/f965853ecba1
https://www.cnblogs.com/ianduin/p/7732983.html
https://zhuanlan.zhihu.com/p/78705834
-
安装
pip install django-ckeditor
-
注册应用
在settin.py中添加 INSTALLED_APPS = [ ... 'ckeditor', #注册应用,添加ckeditor富文本编辑器 ‘ckeditor_uploader', #文件上传需要 ]
-
文件上传配置
配置MEDIA_URL和MEDIA_ROOT, 上传路径的根目录就是以MEDIA_ROOT CKEDITOR_UPLOAD_PATH = "uploads/",
-
设置urls.py路径
re_path(r'^ckeditor/', include('ckeditor_uploader.urls')),
-
在models.py中设置
content=RichTextUploadingField(verbose_name=’内容‘) class Article(models.Model): title = models.CharField(max_length=100, verbose_name='标题') desc = models.CharField(max_length=256, verbose_name='简介') content = RichTextUploadingField(verbose_name='内容')
-
迁移和同步
-
访问:xadmin后台
十三、富文本:ueditor
1、安装方法
* 将github整个源码包下载下来
git clone https://github.com/cooljacket/DjangoUeditor
* 然后,假设你的python安装目录是PYTHON_ROOT(我的是D:\soft\py3.5),直接复制DjangoUeditor文件夹到PYTHON_ROOT\Lib\site-packages\下就好了,比如我的就是D:\soft\py3.5\Lib\site-packages\
* 之所以不使用原来的setup.py来安装,是因为我发现,用它的setup脚本会改动代码成原来的样子,也没去深究为什么,最后发现只需要直接复制过去就好了,而且卸载也很方便,直接删除就好了,没有什么依赖项和设置!
2.在Django中安装DjangoUeditor
在INSTALL_APPS里面增加DjangoUeditor app,如下:
INSTALLED_APPS = (
#........
'DjangoUeditor',
)
3、配置urls
url(r'^ueditor/',include('DjangoUeditor.urls' )),
4、在models中的使用
from DjangoUeditor.models import UEditorField
class Blog(models.Model):
Name=models.CharField(,max_length=100,blank=True)
Content=UEditorField(u'内容 ',width=600, height=300, toolbars="full", imagePath="", filePath="", upload_settings={"imageMaxSize":1204000},
settings={},command=None,event_handler=myEventHander(),blank=True)