首页 > 技术文章 > 慕课DJANGO配置

liqianlong 2020-05-23 13:03 原文

重写内置的错误处理视图

在项目urls.py中添加配置
handler500 = "app01.views.page_500"
handler404 = "app01.views.page_404"
handler403 = "app01.views.page_403"
在项目视图中如下填写
from django.core.exceptions import PermissionDenied

def test(request):
    # raise ValueError
    raise PermissionDenied
    return HttpResponse('ok')

def page_500(request):
    return HttpResponse('500')

def page_404(request):
    return HttpResponse('404')

def page_403(request):
    return HttpResponse('403')
切换到生产模式DEBUG=False
View Code

STATIC处理静态文件

在项目settings.py中添加配置

STATIC_URL = '/static/'
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static"),
]
View Code
在项目settings.py中添加配置

MEDIA_URL='/media/'
MEDIA_ROOT=os.path.join(BASE_DIR,'medias')
在项目urls中添加配置

from django.views.static import serve
from django.conf import settings

urlpatterns += [
    url(r'^medias/(?P<path>.*)$',serve,{
        'document_root':settings.MEDIA_ROOT,
    }),
]
View Code

请求对象HttpRequest

请求头信息META
REMOTE_ADDR------请求的IP地址
HTTP_USER_AGENT-----用户请求终端信息
View Code

常见的Content-Type

text/html——超文本标记语言文本(HTML)
text/plain——普通文本  text/xml——XML文档
image/png、image/jpeg、image/gif——图片或图形
application/json ——json数据类型
View Code

响应对象

HttpResponse
HttpResponseRedirect
JsonResponse——响应json
FileResponse——响应文件
View Code

HttpResponse

status查看HTTP响应状态码
status_code查看HTTP响应状态码
content_type设置响应的类型
write()写入响应内容
View Code
def content(request):
    dic = {
        'username':'jamie',
    }
    # return HttpResponse('ok',content_type='text/plain')
    import json
    ret = json.dumps(dic)
    # return HttpResponse(ret,content_type='application/json')
    return JsonResponse(dic)

def status(request):
    # 改变响应状态码
    ret = HttpResponse('status_code', status=404)
    # 重新设置HTTP的状态码
    ret.status_code = 200
    # 打印HTTPS状态码
    print(ret.status_code)
    # 写入响应内容
    ret.write('多写入响应内容')
    return ret

def image(request):
    # pring image
    import os
    from django.conf import settings
    try:
        file_name = os.path.join(settings.BASE_DIR,'medias/images/1111.png')
        f = open(file_name, 'rb')
    except Exception as e:
        print(e)
    return FileResponse(f,content_type='image/png')
    # application/vnd.ms-excel 这样可以导出EXCEL
View Code

使用CLASS重写视图

url(r'^class/',views.classview.as_view(), name='class'),

from django.views.generic import TemplateView

class classview(TemplateView):
    '''class'''
    template_name = 'class.html'
View Code

渲染机制

思考:没有模板引擎怎样在浏览器展示HTML
1. 从磁盘读取html字符串
2. 将满足特定规则的内容进行替换 3. 发送给浏览器展示
View Code
步骤一:从磁盘读取模板文件(get_template)
步骤二:选择合适的模板引擎(select_template)
步骤三:将制定内容对模板进行渲染(render)
步骤四:发送给浏览器显示
View Code

配置选项

APP_DIRS——决定模板引擎是否应该进入每个已安装 的应用中查找模板
每种模板引擎后端都定义了一个惯用的名称作为应用内部存放 模板的子目录名称
DTL——templates目录
Jinja2——jinja2目录
OPTIONS——其他选项配置
View Code

同时支持俩种引擎模板

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        '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',
                'mine.context_processors.const',
            ],
        },
    },
    {
        'BACKEND': 'django.template.backends.jinja2.Jinja2',
        'DIRS': [os.path.join(BASE_DIR, 'jiaja2')],
        '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',
            ],
        },
    },
]
View Code

渲染静态图片

img_url = "/medias/images/1111.png"
return render(request,'image1.html',{'img_url':img_url})
<img src="{{ img_url }}" alt="403报错图片">
View Code

模板标签的使用

循环控制
{% for item in data_list %} <li>内容</li>
{% endfor %}
条件控制
{% if condition_a %} 满足了A条件
{% elif condition_b %} 满足了B条件
{% else %} 都不满足
{% endif %}
View Code

注释

添加注释
{# 注释内容 #}
与HTML注释的区别 
<!-- 注释内容 -->
View Code

重复循环

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .row1 {
            background-color: pink;
        }
        .row2 {
            background-color: red;
        }
        .row3 {
            background-color: gray;
        }
    </style>
</head>
<body>


<ul>
    {% for foo in tag reversed%}
        <li class="{% cycle 'row1' 'row2' 'row3' %}">{{ forloop.counter }}{{ foo }}</li>
    {% empty %}
        <li>列表要是空就走这里</li>
    {% endfor %}
</ul>

</body>
</html>
View Code

过滤器:对变量进行特殊处理后再渲染?

过滤器语法
{{ value|filter_name: params }}
使用过滤器将字母大写 
{{ value|upper}}
View Code

内置过滤器

def test_tp_filter(request):
    import math
    pi = math.pi
    html = '<h1>lalalalalalalalala</h1>'
    import datetime
    time = datetime.datetime.now()
    user_info = {
        'username': 'jamie',
        'age': None,
        'sex': False,
        'pi': pi,
        'html': html,
        'time': time
    }
    return render(request, 'filter.html', {'userinfo': user_info})
View Code
日期对象格式化
{{ value|date:"D d M Y" }}
默认值显示
{{ value|default:"" }} # 为none时候显示我
{{ value|default_if_none:“无" }} # 为空false显示我
数字四舍五入显示
{{ value | floatformat:3 }}
富文本内容转义显示 
{{ value|safe }}
字符串截取
{{ value|truncatechars:9 }}
{{ value|truncatechars_html:9 }} # 不算Html字符
{{ value|truncatewords:2 }}
View Code

自定义过滤器

步骤一:在app目录下新建包templatetags
polls/ 
    __init__.py
    models.py
    templatetags/ 
        __init__.py
        poll_extras.py
    views.py


步骤二:实现过滤器poll_filter.py 
from django import template
register = template.Library()

def warning(value):
    """ 将第一个字符变红 """
    return '<span class="red">' + value[0] +'</span>'+ value[1:]

register.filter('warning', warning)


步骤三:在模板中使用过滤器 
{% load poll_filter %}
{{ value| warning|safe }} 
切记:添加自定义过滤器后记得重启开发服务器
View Code

模板抽象和继承

步骤一:将可变的部分圈出来(base.html)
{% block sidebar %} 
    <!--菜单栏的内容 -->
{% endblock %}


步骤二:继承父模板
{% extends "base.html" %}


步骤三:填充新的内容(index.html)
{% extends "base.html" %}
{% block sidebar %}
    <!-- 新的菜单栏的内容 -->
{% endblock %}


步骤四:复用父模板的内容(可选)
{% extends "base.html" %} {% block sidebar %}
    {{ supper }}
    <!-- 新的菜单栏的内容 --> 
{% endblock %}
View Code

在模板中添加公共部分

步骤一:将可变的部分拆出来(footer.html)
<footer> 
这是页脚公共的部分
</footer>


步骤二:将拆出来的部分包进来(index.html)
{% extends "base.html" %} 
{% block content %}
    <!– 页面主要内容区域-->
    {# 公用的footer #}
    {% include "footer.html" %}
{% endblock %}
View Code

Django工具及管理

常用的内置命令(mine是一个app应用)

检查djangoORM模型
python manage.py check
生成同步原语
python manage.py makemigrations
模型同步
python manage.py migrate
收集依赖中的静态文件
python manage.py collectstatic
django控制台
python manage.py shell
清除过期会话
python manage.py clearsessions
View Code

自定义Django命令行工具

第一步:创建指定的目录及文件结构
mine/ 
    __init__.py
    models.py 
    management/
        __init__.py 
        commands/
            __init__.py
            update.py 
    urls.py
        views.py


第二步:实现自定义命令 
实现django.core.management.base.BaseCommand的子类
添加命令参数add_arguments 
处理命令逻辑handle
显示处理过程(self.stdout.write/self.stderr.write)


"""
update.py 
更新订单状态 

订单超过半小时不支付,取消订单,释放库存
"""
from django.core.management.base import BaseCommand


class Command(BaseCommand):
    help = """
        更新订单状态
        回收订单
        
    """

    def add_arguments(self, parser):
        """
        添加命令的参数
        argparse
        https://docs.python.org/3/library/argparse.html

        1. 回收所有超时未支付的订单
        python manage.py update --all
        2. 指定回收某一个订单
        python manage.py update --one 20001
        :param parser:
        :return:
        """
        # 添加参数 dest匹配参数,交给handel处理,
        parser.add_argument(
            '--all',
            # 不需要加参数的意思,但是还没确定
            action='store_true',
            dest='all',
            default=False,
            help='回收所有超时未支付的订单'
        )

        parser.add_argument(
            '--one',
            action='store',
            dest='one',
            default=False,
            help='指定回收某一个订单'
        )

    def handle(self, *args, **options):
        if options['all']:
            self.stdout.write('开始回收订单')
            # 逻辑处理
            self.stdout.write('-------')
            self.stdout.write('处理完成')
        elif options['one']:
            self.stdout.write('开始回收订单{}'.format(options['one']))
        else:
            self.stderr.write('指令异常')
View Code

Django中间件的开发和使用

上下文处理器,为模板添加全局变量,utils是创建在项目里面的公用脚本目录

渲染上下文Context
请求上下文RequestContext
连接views(视图)和templates(模板)
场景举例: 在每个页面都显示IP地址,多个页面展示购物车信息


TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        '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',
                'mine.context_processors.const', # 这里定义上下文的路径
            ],
        },
    },
]



from utils import constants
def const(request):
    addr = '湖南'
    return {
        'constants': constants.UserList,
        'addr':addr,
    }


# Utils是个创建在项目下的目录
# !/usr/bin/env python
# _*_ coding:utf-8 _*_
# Author: Jamie

UserList = ['吊哥','傻逼']


模板调用
{% for foo in constants %}
    {{ foo }}
{% endfor %}

{{ addr }}
View Code

中间件,过滤请求,拦截请求

场景1:用户非法请求拦截
添加IP地址黑名单,在名单内的用户限制访问
场景2:模拟用户登录
实现简单的用户登录中间件


步骤一:实现中间件,处理业务逻辑 
    方式1:函数式自定义中间件
    方式2: OOP(面向对象)自定义中间件
步骤二:激活中间件,添加到setting.py配置


'''
保存在Utils目录里面,公共方法,ip_middleware.py
'''
from django.http import HttpResponse
from weibo.models import WeiboUser

def ip_middleware(get_response):

    def middleware(request):

        # 请求到达前的业务逻辑
        print('请求到达前的业务逻辑')
        # 请求不满足业务规则:IP被限制
        ip = request.META.get('REMOTE_ADDR', None)
        ip_disable_list = [
            '127.0.0.1'
        ]
        print(ip)
        # for ip_dis in ip_disable_list:
        #     if ip_dis == ip:
        if ip in ip_disable_list:
                return HttpResponse('not allowed', status=403)
        reponse = get_response(request)

        # 在视图函数调用之后的业务逻辑
        print('在视图函数调用之后的业务逻辑')
        return reponse

    return middleware


class MallAuthMiddleware(object):
    """ 自定义的登录验证中间件 """

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request, *args, **kwargs):
        print('MallAuthMiddleware请求到达前的业务逻辑')
        # 请求不满足业务规则:IP被限制

        user_id = request.session.get('user_id', None)
        print('middle:%s' %user_id)
        if user_id:
            user = WeiboUser.users.get(pk=user_id)
        else:
            user = None

        request.my_user = user
        print('--------------', user)
        reponse = self.get_response(request)

        # 在视图函数调用之后的业务逻辑
        print('MallAuthMiddleware在视图函数调用之后的业务逻辑')
        return reponse


MIDDLEWARE = [
    # 'debug_toolbar.middleware.DebugToolbarMiddleware',
    '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',
    # 'utils.middleware.ip_middleware',
    'utils.middleware.MallAuthMiddleware'
]
View Code

另一篇实例 https://www.cnblogs.com/jokerbj/p/8173820.html

Django扩展

DRF(Django REST Framework)REST接口框架
django-cms 内容管理系统 
django-debug-toolbar 调试工具 pypi.org搜索,要对应JDANGO版本
django-channels Websocket通信
View Code

表单重复提交

支付时,快速点击,多次提交会有什么问题? csfttoken

BUG邮件通知

1.发送文字邮件
2.发送HTML邮件
3.发送带附件的邮件 
4.发送多个邮件
5.打破连接限制,连接复用


第一步:邮件配置
第二步:准备邮件内容
第三步:发送邮件


'''
SETTINGS.PY
'''
# 邮件发送配置
EMAIL_HOST = 'smtp.qq.com'
EMAIL_HOST_USER = 'navcat@foxmail.com'
EMAIL_HOST_PASSWORD = 'vgppwryinupwbfgb'
# 自己发送,from django.core.mail import send_mail  send_mail(邮件主题,邮件内容,发件人,发送给谁,是个列表)

# 触发异常就会给ADMINS发邮件,DEBUG = False
SERVER_EMAIL = 'navcat@foxmail.com'
ADMINS = [('admin', 'navcat@foxmail.com')]
View Code

https://docs.djangoproject.com/en/1.11/topics/email/

日志记录配置

logging的四个部分
1.Loggers——日志记录入口
2.Handlers——决定处理logger中消息的方式
3.Filters——对日志进行条件控制
4.Formatters——日志记录的文本顺序(格式)



Logger的级别
DEBUG:用于调试目的的底层系统信息
INFO:普通的系统信息
WARNING:警告,较小的问题,不影响执行顺序
ERROR:错误,较大的问题  CRITICAL:严重,致命的问题



'''
SETTINGS.PY
'''
# 日志的配置
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'verbose': {
            'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
        },
        'simple': {
            'format': '%(levelname)s %(message)s'
        },
    },
    'handlers': {
        'sql_log_file': {
            'level': 'DEBUG',
            'class': 'logging.FileHandler',
            'filename': os.path.join(BASE_DIR, 'log/sql.log'),
        },
        'log_index_file': {
            'level': 'DEBUG',
            'class': 'logging.FileHandler',
            'formatter': 'verbose',
            'filename': os.path.join(BASE_DIR, 'log/index.log'),
        },
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
            # 'formatter': 'simple'
        },
        'mail_admins': {
            'level': 'ERROR',
            'class': 'django.utils.log.AdminEmailHandler',
            # 'filters': ['special']
        }
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['sql_log_file',],
            'level': 'DEBUG',
            'propagate': True,
        },
        'index': {
            'handlers': ['log_index_file', 'console'],
            'level': 'DEBUG',
        }
    },
}
View Code

上传图片方式

# !/usr/bin/env python
# _*_ coding:utf-8 _*_
# Author: Jamie


import re
from django import forms
from weibo import models
class UserLoginForm(forms.Form):
    username = forms.CharField(label='用户名',max_length=64)
    password = forms.CharField(label='密码',max_length=64,widget=forms.PasswordInput)
    verify_code = forms.CharField(label='验证码',max_length=64)

    def clean_username(self):
        username = self.cleaned_data['username']
        pattern = r'^0{0,1}1[0-9]{10}$'
        if not re.search(pattern,username):
            raise forms.ValidationError('请输入正确的手机号码')
        return username

    def clean(self):
        cleand_data = super().clean()
        username = cleand_data.get('username',None)
        password = cleand_data.get('password',None)
        if username and password:
            user_list = models.WeiboUser.users.filter(username=username)
            if user_list.count() == 0:
                raise forms.ValidationError('用户名不存在')
            if not user_list.filter(password=password).exists*():
                raise forms.ValidationError('密码错误')
        return cleand_data


class UserForm(forms.ModelForm):
    class Meta:
        model = models.WeiboUser
        fields = ['username','password']
        widgets = {
            'password':forms.PasswordInput(attrs={
                'class':'text-error',
            })
        }
        labels = {
            'username':'手机号码',
        }
        error_messages = {
            'username':{
                'required':'请输入手机号码',
                'max_length':'最长不超过32',
            }
        }

class AvatarUploadForm(forms.Form):
    remark = forms.CharField(label='备注',max_length=32)
    touxiang = forms.FileField(label='头像')

class WeiboImageForm(forms.ModelForm):
    content = forms.CharField(label='微博内容',max_length=256,widget=forms.Textarea(attrs={'placeholder':'请输入微博内容'}))
    class Meta:
        model = models.WeiboImage
        fields = ['image']

    def save(self,user,commit=False):
        obj = super().save(commit)
        data = self.cleaned_data
        content = self.cleaned_data['content']
        #1 创建微博记录
        weibo = models.Weibo.objects.create(user=user,content=content)
        #2 修改微博关联关系
        obj.weibo = weibo
        obj.save()
        return obj
FORMS
def upload_one(request):
    if request.method == 'POST':
        file = request.FILES.get('touxiang',None)
        import os
        from dalaohu import settings
        filename = os.path.join(settings.MEDIA_ROOT,'touxiang')
        with open(filename,'wb+') as f:
            for i in file.chunks():
                f.write(i)
            print('上传陈功了')
    return render(request,'upload_one.html')

def upload_two(request):
    if request.method == 'POST':
        form = forms.AvatarUploadForm(request.POST,request.FILES)
        if form.is_valid():
            file = request.FILES.get('touxiang', None)
            import os
            from dalaohu import settings
            filename = os.path.join(settings.MEDIA_ROOT, 'touxiang1')
            with open(filename, 'wb+') as f:
                for i in file.chunks():
                    f.write(i)
                print('上传陈功了')
    else:
        form = forms.AvatarUploadForm()
    return render(request,'upload_two.html',{'form':form})

def upload_three(request):
    if request.method == 'POST':
        user = WeiboUser.users.get(pk=1)
        form = forms.WeiboImageForm(request.POST,request.FILES)
        if form.is_valid():
            obj = form.save(user,False)
            print('保存陈功了',obj.pk)
    else:
        form = forms.WeiboImageForm()
    return render(request,'upload_three.html',{
        'form':form
    })
VIEWS

自带登录验证

import re

from django import forms
from django.forms import widgets
from django.forms import fields
from django.contrib.auth import authenticate, login
from django.contrib.auth.models import User

from utils.verify import VerifyCode

class UserLoginForm(forms.Form):
    """ 用户登录表单 """
    username = forms.CharField(label='用户名', max_length=64,widget=widgets.TextInput(attrs={'class':'form-control','placeholder':'请输入用户名'}),
                               error_messages={
                                   'required': '请输入用户名',
                               }
                               )
    password = forms.CharField(label='密码', max_length=64,widget=widgets.PasswordInput(attrs={'class':'form-control','placeholder':'请输入密码'}),
                               error_messages={
                                   'required': '请输入密码',
                               })
    verify_code = forms.CharField(label='验证码', max_length=4,widget=widgets.TextInput(attrs={'class':'form-control','placeholder':'验证码'}),
                               error_messages={
                                   'required': '请输入验证码',
                               })

    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.request = request

    # def clean_username(self):
    #     """ 验证用户名 hook 钩子函数"""
    #     username = self.cleaned_data['username']
    #     print(username)
    #     # 判断用户名是否为手机号码
    #     pattern = r'^0{0,1}1[0-9]{10}$'
    #     if not re.search(pattern, username):
    #         raise forms.ValidationError('请输入正确的手机号码')
    #     return username

    def clean_verify_code(self):
        """ 验证用户输入的验证码是否正确 """
        verify_code = self.cleaned_data['verify_code']
        if not verify_code:
            raise forms.ValidationError('请输入验证码')
        client = VerifyCode(self.request)
        if not client.validate_code(verify_code):
            raise forms.ValidationError('验证码不正确')
        return verify_code

    def clean(self):
        cleaned_data = super().clean()
        print(cleaned_data)
        # 获取用户名和密码 ,不建议使用[]的方式
        # username = cleaned_data['username']

        username = cleaned_data.get('username', None)
        password = cleaned_data.get('password', None)
        if username and password:
            # 查询用户名和密码匹配的用户
            user_list = User.objects.filter(username=username)
            if user_list.count() == 0:
                raise forms.ValidationError('用户名不存在')
            # # 验证密码是否正确
            # if not user_list.filter(password=password).exists():
            #     raise forms.ValidationError('密码错误')
            if not authenticate(username=username, password=password):
                raise forms.ValidationError('密码错误')
        return cleaned_data


class UserRegistForm(forms.Form):
    """ 用户注册表单 """
    username = forms.CharField(label='用户名', max_length=64)
    nickname = forms.CharField(label='昵称', max_length=64)
    password = forms.CharField(label='密码', max_length=64, widget=forms.PasswordInput)
    password_repeat = forms.CharField(label='重复密码', max_length=64, widget=forms.PasswordInput)
    verify_code = forms.CharField(label='验证码', max_length=4)

    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.request = request

    def clean_username(self):
        """ 验证用户名是否已经被注册 """
        data = self.cleaned_data['username']
        if User.objects.filter(username=data).exists():
            raise forms.ValidationError('用户名已存在')
        return data

    def clean_verify_code(self):
        """ 验证用户输入的验证码是否正确 """
        verify_code = self.cleaned_data['verify_code']
        if not verify_code:
            raise forms.ValidationError('请输入验证码')
        client = VerifyCode(self.request)
        if not client.validate_code(verify_code):
            raise forms.ValidationError('您输入的验证码不正确')
        return verify_code

    def clean(self):
        cleaned_data = super().clean()
        password = cleaned_data.get('password', None)
        password_repeat = cleaned_data.get('password_repeat', None)
        if password and password_repeat:
            if password != password_repeat:
                raise forms.ValidationError('两次密码输入不一致')
        return cleaned_data

    def register(self):
        """ 注册方法 """
        data = self.cleaned_data
        # 1. 创建用户
        User.objects.create_user(username=data['username'],
                                 password=data['password'],
                                 level=0,
                                 nickname='昵称')
        # 2. 自动登录
        user = authenticate(username=data['username'],
                     password=data['password'])
        login(self.request, user)
        return user
FORMS
from django.contrib.auth import authenticate, login, logout
from utils.verify import VerifyCode
from weibo.forms import UserLoginForm,UserRegistForm
from django.contrib.auth.models import User
def user_add(request):
    '''创建用户'''
    user = User.objects.create_user('liqianlong','lal@126.com',123456)
    return HttpResponse('创建账号成功')

def user_login1(request):
    """ 用户登录 """
    # 如果登录是从其他页面跳转过来的,会带next参数,如果有next参数,登录完成后,需要调转到
    # next所对应的地址,否则,跳转到首页上去
    next_url = request.GET.get('next', 'weibo:index')

    if request.method == 'POST':
        form = UserLoginForm(request=request, data=request.POST)
        # print(request.POST)
        # client = VerifyCode(request)
        # code = request.POST.get('verify_code', None)
        # rest = client.validate_code(code)
        # print('验证结果:', rest)
        # 表单是否通过了验证
        if form.is_valid():
            # 执行登录
            data = form.cleaned_data

            # ## 使用自定义的方式实现登录
            # # 查询用户信息 [MD5]加密算法,不可逆的加密算法 1243 -> sdfadfad
            # user = User.objects.get(username=data['username'], password=data['password'])
            # # 设置用户ID到session
            # request.session[constants.LOGIN_SESSION_ID] = user.id
            # # 登录后的跳转
            # return redirect('index')

            ### 使用django-auth来实现登录
            user = authenticate(request, username=data['username'], password=data['password'])
            print('view:%s' %user.id)
            if user is not None:
                ### 为了测试自定义中间件加的session
                request.session['user_id'] = user.id
                login(request, user)
                # 登录后的跳转
                return redirect(next_url)
        else:
            print(form.errors)
    else:
        form = UserLoginForm(request)
    return render(request, 'login.html', {'form': form,'next_url':next_url})


def user_logout(request):
    """ 用户退出登录 """
    logout(request)
    return redirect('weibo:user_login1')


import logging
logger = logging.getLogger('index')
logger.debug('调试信息')
logger.info('普通信息')
logger.error("异常")

@login_required
def index(request):
    # 记录调试信息
    print('登录成功,打开首页',request.my_user)
    return render(request,'wbindex.html')

def user_register(request):
    """  用户注册 """
    if request.method == 'POST':
        form = UserRegistForm(request=request, data=request.POST)
        if form.is_valid():
            # 调用注册方法
            form.register()
            return redirect('index')
        else:
            print(form.errors)
    else:
        form = UserRegistForm(request=request)
    return render(request, 'register.html', {
        'form': form
    })

def code(request):
    client = VerifyCode(request)
    return client.gen_code()
VIEWS
    # 用户登录
    url(r'^user/user_add/$', views.user_add, name='user_add'),
    url(r'^user/login/$', views.user_login1, name='user_login1'),
    # 用户退出
    url(r'^user/logout/$', views.user_logout, name='user_logout'),
    # 用户注册
    url(r'^user/register/$', views.user_register, name='user_register'),
    # 验证码
    url(r'^user/code/$', views.code, name='verify_code'),
    # index
    url(r'^user/index/$', views.index, name='index'),
URLS
"""
生成验证码:
1. 准备素材
字体(ttf),文字内容,颜色,干扰线
2. 画验证码
pip install Pillow   、random
创建图片
记录文字内容,django session【服务器,python代码】
abcdefg  cookie 【浏览器】

(1) 第一次请求,cookie + session 对应关系生成
(2) 第二次请求,携带了cookie,找到对应的session【提交表单】
    请求带上验证码参数 与 session中的验证码进行比较
3. io文件流
BytesIO
"""
import random

import os

from PIL import Image, ImageDraw, ImageFont
from django.conf import settings
from io import BytesIO

from django.http import HttpResponse


class VerifyCode(object):
    """ 验证码类 """

    def __init__(self, dj_request):
        self.dj_request = dj_request
        # 验证码长度
        self.code_len = 4
        # 验证码图片尺寸
        self.img_width = 100
        self.img_height = 30

        # django中session的名称
        self.session_key = 'verify_code'

    def gen_code(self):
        """ 生成验证码 """
        # 1. 使用随机数生成验证码字符串
        code = self._get_vcode()
        # 2. 把验证码存在的session
        self.dj_request.session[self.session_key] = code
        # 3. 准备随机元素(背景颜色、验证码文字的颜色、干扰线、)
        font_color = ['black', 'darkblue', 'darkred', 'brown', 'green', 'darkmagenta', 'cyan', 'darkcyan']
        # RGB随机背景色
        bg_color = (random.randrange(230, 255), random.randrange(230, 255), random.randrange(230, 255))
        # 字体路径
        font_path = os.path.join(settings.BASE_DIR, 'medias', 'fonts', 'timesbi.ttf')

        # 创建图片
        im = Image.new('RGB', (self.img_width, self.img_height), bg_color)
        draw = ImageDraw.Draw(im)

        # 画干扰线
        # 随机条数,到底画几条
        for i in range(random.randrange(1, int(self.code_len / 2) + 1)):
            # 线条的颜色
            line_color = random.choice(font_color)
            # 线条的位置
            point = (
                random.randrange(0, self.img_width * 0.2),
                random.randrange(0, self.img_height),
                random.randrange(self.img_width - self.img_width * 0.2, self.img_width),
                random.randrange(0, self.img_height))
            # 线条的宽度
            width = random.randrange(1, 4)
            draw.line(point, fill=line_color, width=width)

        # 画验证码
        for index, char in enumerate(code):
            code_color = random.choice(font_color)
            # 指定字体
            font_size = random.randrange(15, 25)
            font = ImageFont.truetype(font_path, font_size)
            point = (index * self.img_width / self.code_len,
                     random.randrange(0, self.img_height / 3))
            draw.text(point, char, font=font, fill=code_color)

        buf = BytesIO()
        im.save(buf, 'gif')
        return HttpResponse(buf.getvalue(), 'image/gif')

    def _get_vcode(self):
        random_str = 'ABCDEFGHIGKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz23456789'
        code_list = random.sample(list(random_str), self.code_len)
        code = ''.join(code_list)
        return code

    def validate_code(self, code):
        """ 验证验证码是否正确 """
        # 1. 转变大小写
        code = str(code).lower()
        vcode = self.dj_request.session.get(self.session_key, '')
        # if vcode.lower() == code:
        #     return True
        # return False
        return vcode.lower() == code

# if __name__ == '__main__':
#     client = VerifyCode(None)
#     client.gen_code()
verify

其他settings配置

# orm时间查询时候要是false
USE_TZ = False

# 使用自定义模型的时候,当没有经过验证就会走这里
LOGIN_URL = '/weibo/user/login/'

# CSRF 跨站请求伪造的另一个种解决方法,这样相当于植入到COOKIE中,模板通过jquery.cookie可以获取到
CSRF_USE_SESSIONS=False
View Code

文件备份脚本 

import os
import os.path


class FileBackup(object):
    """
    文本文件备份
    """

    def __init__(self, src, dist):
        """
        构造方法
        :param src: 目录 需要备份的文件目录
        :param dist: 目录 备份后的目录
        """
        self.src = src
        self.dist = dist

    def read_files(self):
        """
        读取src目录下的所有文件
        """
        ls = os.listdir(self.src)
        print(ls)
        for l in ls:
            # 循环处理每一个文件/文件夹
            # self.backup_file(l)
            self.backup_file2(l)

    def backup_file(self, file_name):
        """
        处理备份
        :param file_name: 文件/文件夹的名称
        """
        # 1. 判断dist是否存在,如果不存在,要创建这个目录
        if not os.path.exists(self.dist):
            os.makedirs(self.dist)
            print('指定的目录不存在,创建完成')

        # 2. 判断文件是否为我们要备份的文件

        # 拼接文件的完整路径
        full_src_path = os.path.join(self.src, file_name)
        full_dist_path = os.path.join(self.dist, file_name)

        # 首先要判断是否为文件夹,然后借助于文件的后缀名进行判断
        if os.path.isfile(full_src_path) and os.path.splitext(full_src_path)[-1].lower() == '.txt':
            print(full_src_path)
            # 3. 读取文件内容
            with open(full_dist_path, 'w', encoding='utf-8') as f_dist:
                print('>> 开始备份【{0}】'.format(file_name))
                with open(full_src_path, 'r', encoding='utf-8') as f_src:
                    while True:
                        rest = f_src.read(100)
                        if not rest:
                            break
                        # 4. 把读取到的内容写入到新的文件中
                        f_dist.write(rest)
                    f_dist.flush()
                print('>>> 【{0}】备份完成'.format(file_name))
        else:
            print('文件类型不符合备份要求,跳过>>')

    def backup_file2(self, file_name):
        """
        处理备份-优化版本
        :param file_name: 文件/文件夹的名称
        """
        # 1. 判断dist是否存在,如果不存在,要创建这个目录
        if not os.path.exists(self.dist):
            os.makedirs(self.dist)
            print('指定的目录不存在,创建完成')

        # 2. 判断文件是否为我们要备份的文件

        # 拼接文件的完整路径
        full_src_path = os.path.join(self.src, file_name)
        full_dist_path = os.path.join(self.dist, file_name)

        # 首先要判断是否为文件夹,然后借助于文件的后缀名进行判断
        if os.path.isfile(full_src_path) and os.path.splitext(full_src_path)[-1].lower() == '.txt':
            # 3. 读取文件内容
            with open(full_dist_path, 'w', encoding='utf-8') as f_dist, \
                open(full_src_path, 'r', encoding='utf-8') as f_src:
                print('>> 开始备份【{0}】'.format(file_name))
                while True:
                    rest = f_src.read(100)
                    if not rest:
                        break
                    # 4. 把读取到的内容写入到新的文件中
                    f_dist.write(rest)
                f_dist.flush()
                print('>>> 【{0}】备份完成'.format(file_name))
        else:
            print('文件类型不符合备份要求,跳过>>')


if __name__ == '__main__':
    # # 要备份的文件目录地址
    # src_path = 'C:\\Users\\yima1\\Desktop\\py_learn\\chapter04\\src'
    # # 备份后的目录地址
    # dist_path = 'C:\\Users\\yima1\\Desktop\\py_learn\\chapter04\\dist'

    # 当前代码的目录名称
    # C:\Users\yima1\Desktop\py_learn\chapter04\   test_backup.py
    base_path = os.path.dirname(os.path.abspath(__file__))
    # 要备份的文件目录地址
    src_path = os.path.join(base_path, 'src')
    print(src_path)
    # 备份后的目录地址
    dist_path = os.path.join(base_path, 'dist')
    print(dist_path)
    bak = FileBackup(src_path, dist_path)
    bak.read_files()

BACKUPFILE
View Code 

 

 


推荐阅读