django搭建一个博客,登录登出

  • 用的是pycharm专业版本,并没有使用虚拟环境,使用的是django2.1,python3.6
  • 写这个项目需要你了解django基本结构与语法,不然在映射和函数之间,你会晕头转向
  • 了解简单的html css JavaScript代码

第一课堂:简单创建项目和app

  • 创建项目
  1. pycharm 人性化,必须专业版
  2. 命令行,进入此目录,写下如下代码
python3 manage.py startproject 项目名字
# manage.py则是每个Django项目中自动生成的一个用于管理项目的脚本文件,需要在cmd窗口中cd到Django项目的manage.py所在的目录后通过python命令执行。其中的command是Django内置的或者你自定义的命令
  • 创建app
命令行进入项目目录
python3 manegy.py startapp app名字
  • 由于我们设计的登录和检测,肯定是一个需要记录时间的,所以我们在settings文件里面设置中国时区
LANGUAGE_CODE = 'zh-hans'

TIME_ZONE = 'Asia/Shanghai'

USE_I18N = True

USE_L10N = True

USE_TZ = False

第二课堂:设计数据模型

  • 数据库模型设计
  1. 明确我们设计的模型需要那些输入:用户名,密码,邮箱地址,创建时间
  2. 有了目标,在models里面,进行相应的设计,一些属性简单易懂
class User(models.Model):

    gender = (
        ('male', "男"),
        ('female', "女"),
    )

    name = models.CharFiel(max_length=128unique=True)
    password = models.CharField(max_length=256)
    email = models.EmailField(unique=True)
    sex = models.CharField(max_length=32choices=gender, default="男")
    c_time = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.name

    class Meta:
        ordering = ["-c_time"]
        verbose_name = "用户"
        verbose_name_plural = "用户"
  • 连接数据库,这里我有几个问题需要解决
  1. 把你的数据库编码全部解决,进入你的数据库中
show variables like '%char%';#显示你数据库字符集列表
set character_set_client=utf8;
  set character_set_connection=utf8;
  set character_set_database=utf8;
  set character_set_results=utf8;
  set character_set_server=utf8;
  set character_set_system=utf8;
  set collation_connection=utf8;
  set collation_database=utf8;
  set collation_server=utf8;
上面代码分行写,分别运行,不要管警告
--------------------- 
作者:胖虎艾春辉 
来源:CSDN 
原文:https://blog.csdn.net/weixin_42479155/article/details/85345973 
版权声明:本文为博主原创文章,转载请附上博文链接!
  1. 如果你是使用navicat强烈建议,你重新检查一遍,字符集一定选utf8
  2. 将你的新建app全部加入settings里面的app注册表里
  3. 激活模型:
python3 manage.py migrate

第三课堂:创建后台:管理人员,路由和视图

  • 在admin里面与你创建的模型进行对接,在admin里面输入
admin.site.register(models.User)
  • 创建超级管理员权限
python3 manage.py createsuperuser
  • 路由需求:主页,登录,注册,登出
  • 搭建映射与函数(在app的views.py)
urls里面的分配:
from django.contrib import admin
from django.urls import path
from login import views
from django.conf.urls import include
from django.urls import re_path
urlpatterns = [
    path('admin/', admin.site.urls),
    path('index/', views.index, name = 'index'),
    path('login/',views.login,name = 'login'),
    #path('',views.base,name ='base'),
    path('',views.index),
    path('register/',views.register,name = 'register'),
    path('logout/',views.logout,name = 'logout'),
]
#**这里我需要提醒,为了避免函数调用出现问题,我们给每一个映射都设计一个命名空间**
  • 在login/view.py里面构建简单映射
from django.shortcuts import render
from django.shortcuts import redirect

# Create your views here.


def index(request):
    pass
    return render(request, 'login/index.html')


def login(request):
    pass
    return render(request, 'login/login.html')


def register(request):
    pass
    return render(request, 'login/register.html')


def logout(request):
    pass
    return redirect("/index/")
# 这里我提醒:导入redirect是为了重定向
render函数有两个参数,第一个request准备返回,固定参数,不要随意改变,第二个参数是需要渲染的页面

django搭建一个博客,登录登出_第1张图片

第四课堂:前端页面设计

  • 如果不继承的话是这样的:



    
    登录



    

欢迎登录!

这样的页面非常丑
  • 使用bootstrap开源框架
  1. 这个框架弥补你对前端开发的不足,

  2. 同时相匹配的jquery下载
    (http://www.bootcss.com/)

  3. 对于静态文件的引入,在settings文件中,它有一个STATICFILES_DIRS的模块,所以在最下面一行加入引导路径

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static"),
]
  • 同事,前端页面不可能都各自编写,而是要有复用性,也就是说你这个html文件可以被继承和扩展
  • 在bootstap文档中,为我们这些小白提供了一个入门模板:


  
    
    
    
    
    Bootstrap 101 Template

    
    

    
    
    
  
  
    

你好,世界!

  • 最后我们设计的网页基础模板,里面加入了自己改造的导航条:
{% load staticfiles %}


  
    
    
    
    
    {% block title %}base{% endblock %}

    
    

    
    
    
    {% block css %}{% endblock %}
  
  
    

    {% block content %}{% endblock %}


    
    
    
    
  


  1. 通过页面顶端的{% load staticfiles %}加载后,才可以使用static方法;
  2. 通过{% block title %}base{% endblock %},设置了一个动态的页面title块;
  3. 通过{% block css %}{% endblock %},设置了一个动态的css加载块;
  4. 通过{% block content %}{% endblock %},为具体页面的主体内容留下接口;
  5. 通过{% static ‘bootstrap-3.3.7-dist/css/bootstrap.min.css’ %}将样式文件指向了我们的实际静态文件,下面的js脚本也是同样的道理
  • 修改login.html文件对base文件进行拓展:
{% extends 'base.html' %}
{% load staticfiles %}
{% block title %}登录{% endblock %}
{% block css %}{% endblock %}


{% block content %}
    
{% endblock %}
  1. 通过{% extends ‘base.html’ %}继承了‘base.html’模板的内容;
  2. 通过{% block title %}登录{% endblock %}设置了专门的title;
  3. 通过block css引入了针对性的login.css样式文件;
  4. 主体内容定义在block content内部
  5. 添加了一个重置按钮
  • 在static目录下新建一个css文件夹,在里面新建login.css文件,在里面设置css样式,具体样式是这样
body{
    background-image: url("8b13632762d0f703a7484cf103fa513d2697c521.jpg");
}
.form-login{
    max-width: 330px;
    padding: 15px;
    margin: 0 auto;
}
.form-login .form-control{
    position: relative;
    height: auto;
    -webkit-box-sizing: border-box;
     -moz-box-sizing: border-box;
    box-sizing: border-box;
    padding: 10px;
    font-size: 16px;
}
.form-login .form-control:focus{
    z-index: 2;
}
.form-login input[type = "text"]{
    margin-bottom: -1px;
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
}
.form-login input[type = password]{
    margin-bottom: 10px;
    border-bottom-left-radius: 0;
    border-bottom-left-radius: 0;
}
  • 同时,如果你想加入背景的话,可以在body属性的css文件下添加background-image属性 = url(建议你的背景图片放在同一个文件夹下,这样就没有必要去寻找了

第五课堂:登录视图

  • 我们希望用户通过login页面填写表单和用户名密码,并且是POST的方式发送到服务器/login/地址,服务器通过视图函数,接受并处理这些请求:
def login(request):
    if request.method == "POST":
        username = request.POST.get('username')
        password = request.POST.get('password')
        print(username, password)
        return redirect('/index/')
    return render(request, 'login/login.html')
解释:
1. 每一个视图函数都至少接受一个参数,并且是第一位置参数,该参数封装了当前请求的所有数据
2. request.method分装了数据请求大写POST,将执行if语句
3. get('username')的键名字是html表单中input元素中name属性定义的值,所以不能忘记添加name属性
4. 利用redirect方法,将页面重定向到index页
5. 但是你这样也是不成功的,为什么呢?因为django有一部分的内置防御功能,解决问题就是在所有的form里面,添加:{% csrf_token %}
  • 数据验证,实现必填字段不能为空,密码用圆点代替隐藏
def login(request):
    if request.method == "POST":
        username = request.POST.get('username', None)
        password = request.POST.get('password', None)
        if username and password:  # 确保用户名和密码都不为空
            username = username.strip()
            # 用户名字符合法性验证
            # 密码长度验证
            # 更多的其它验证.....            
            return redirect('/index/')
    return render(request, 'login/login.html')
  • 连接数据库并且进行验证:
def login(request):
    if request.method == "POST":
        username = request.POST.get('username', None)
        password = request.POST.get('password', None)
        if username and password:  # 确保用户名和密码都不为空
            username = username.strip()
            # 用户名字符合法性验证
            # 密码长度验证
            # 更多的其它验证.....
            try:
                user = models.User.objects.get(name=username)
            except:
                return render(request, 'login/login.html')
            if user.password == password:
                return redirect('/index/')
    return render(request, 'login/login.html')
解释:
1. 导入models模块
2. models.User.objects.get(name=username)是Django提供的最常用的数据查询API,因为我们之前设计好了数据库的表

  • 添加提示信息
def login(request):
    if request.method == "POST":
        username = request.POST.get('username', None)
        password = request.POST.get('password', None)
        message = "所有字段都必须填写!"
        if username and password:  # 确保用户名和密码都不为空
            username = username.strip()
            # 用户名字符合法性验证
            # 密码长度验证
            # 更多的其它验证.....
            try:
                user = models.User.objects.get(name=username)
                if user.password == password:
                    return redirect('/index/')
                else:
                    message = "密码不正确!"
            except:
                message = "用户名不存在!"
        return render(request, 'login/login.html', {"message": message})
    return render(request, 'login/login.html')
  • 对于登录页面进行修改:

django搭建一个博客,登录登出_第2张图片

第6课堂:设计表单

  • 原理:django在内部集成了一个表单功能,以面对对象的方式,直接使用python代码生成html表单代码:准备和重构数据用于页面渲染;
    为数据创建HTML表单元素;
    接收和处理用户从表单发送过来的数据
  • 创建表单forms,就是在login这个app下创建forms.py文件
from django import forms


class UserForm(forms.Form):
    username = forms.CharField(label="用户名", max_length=128)
    password = forms.CharField(label="密码", max_length=256, widget=forms.PasswordInput)
解释:
1. 导入forms模块
2. 所有的表单都需要继承自forms.Form类
3. 每个表单字段都有自己的字段类型比如CharField,它们分别对应一种HTML语言中
内的一个input元素 4. label参数用于设置
  • 相应的对映射进行修改
def login(request):
    if request.method == "POST":
        login_form = forms.UserForm(request.POST)
        message = "请检查填写的内容!"
        if login_form.is_valid():
            username = login_form.cleaned_data['username']
            password = login_form.cleaned_data['password']
            try:
                user = models.User.objects.get(name=username)
                if user.password == password:
                    return redirect('/index/')
                else:
                    message = "密码不正确!"
            except:
                message = "用户不存在!"
        return render(request, 'login/login.html', locals())

    login_form = forms.UserForm()
    return render(request, 'login/login.html', locals())
1. 对于请求不是post的返回空的表格
2. 对于post表格,接收表单数据,并验证
3. 采用is_valid进行验证,验证过程有:#先来归纳一下整个流程
#(1)首先is_valid()起手,看seld.errors中是否值,只要有值就是flase
#(2)接着分析errors.里面判断_errors是都为空,如果为空返回self.full_clean(),否则返回self._errors
#(3)现在就要看full_clean(),是何方神圣了,里面设置_errors和cleaned_data这两个字典,一个存错误字段,一个存储正确字段。
#(4)在full_clean最后有一句self._clean_fields(),表示校验字段
#(5)在_clean_fields函数中开始循环校验每个字段,真正校验字段的是field.clean(value),怎么校验的不管
#(6)在_clean_fields中可以看到,会将字段分别添加到_errors和cleaned_data这两个字典中
#(7)结尾部分还设置了钩子,找clean_XX形式的,有就执行。执行错误信息也会添加到_errors中
#(8)整个校验过程完成
4. 验证成功后可以从表单对象的cleaned_data数据字典中获取表单的具体值
5. 此外使用了locals这个函数,它返回当前所有的本地变量字典,直接打包,提高了效率
  • 修改html页面:
{% extends 'base.html' %}
{% load staticfiles %}
{% block title %}登录{% endblock %}
{% block css %}{% endblock %}


{% block content %}
    
{% if message %}
{ { message }}
{% endif %} {% csrf_token %}

欢迎登录

{ { login_form }}
{% endblock %} 1. 使用一个{ {login_form}}就直接完成了表单内容的生成工作,而这个变量来自在视图函数中生成的form实例的变量名,同时,locals将其传入 2. 使用post的时候,必添加{% csrf_token %}用于处理csrf安全机制 3. 实际上除了通过{ { login_form }}简单地将表单渲染到HTML页面中了,还有下面几种方式: { { login_form.as_table }} 将表单渲染成一个表格元素,每个输入框作为一个标签 { { login_form.as_p }} 将表单的每个输入框包裹在一个

标签内 { { login_form.as_ul }} 将表单渲染成一个列表元素,每个输入框作为一个

  • 标签
    • 但其实这个一点也不好看,我有强迫症,所以手动渲染:
    { { login_form.username.label_tag }} { { login_form.username}}
    { { login_form.password.label_tag }} { { login_form.password }}
    • 为了还原bootstarp框架一个清白,我们再次修改forms代码:
    from django import forms
    
    class UserForm(forms.Form):
        username = forms.CharField(label="用户名", max_length=128, widget=forms.TextInput(attrs={'class': 'form-control'}))
        password = forms.CharField(label="密码", max_length=256, widget=forms.PasswordInput(attrs={'class': 'form-contro
    

    第七课堂: 图片验证码

    • 为了防止爬虫无限制的爬你的网站,导致你的服务器瘫痪,为此,我们需要提供验证码功能
    • 步骤
    1. 看你的系统,我的系统是ubuntu18.04所以,我使用命令行输入
    pip3 install django-simple-captcha
    但是我遇到了问题上面显示我的mysqldb不能安装
    没办法,只能sudo apt-get install python3-mysql解决了
    
    1. 注册app,captcha是一个系统内置的app,记住,不需要你取新建这个名字的app,而是只需要你在app列表进行注册就行
    2. 同时,在终端下执行下列语句:这句话的意思是将验证码自己制造的表推送到目的地
    python3 manage.py migrate
    
    1. 使用二级路由,加入内置的路由,这是我个人的设置大家可以仿照一下
    from django.contrib import admin
    from django.urls import path
    from login import views
    from django.conf.urls import include
    from django.urls import re_path
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('index/', views.index, name = 'index'),
        path('login/',views.login,name = 'login'),
        #path('',views.base,name ='base'),
        path('register/',views.register,name = 'register'),
        path('logout/',views.logout,name = 'logout'),
        re_path(r'^captcha',include('captcha.urls'))#添加captcha相对应的网址
    ]
    
    
    1. 在forms里面添加captchafield,这个文件下代码如下
    from django import forms
    #添加图形验证码
    from captcha.fields import CaptchaField
    
    class UserForm(forms.Form):
        username = forms.CharField(label="用户名:",max_length=128,widget=forms.TextInput(attrs={'class': 'form-control'}))
    
        password = forms.CharField(label="密码:",max_length=256,widget=forms.PasswordInput(attrs={'class': 'form-control'}))
    
        captcha = CaptchaField(label='验证码')
    
    1. 修改login.html
      
    { { login_form.username.label_tag }} { { login_form.username }}
    { { login_form.password.label_tag }} { { login_form.password}}
    { { login_form.captcha.errors }}#指示用户,你的验证码有问题 { { login_form.captcha.label_tag }} { { login_form.captcha }}
    • 虽然页面有点抽,但是框架还是不错的,is_valid()是内置的forms的验证方法
      django搭建一个博客,登录登出_第3张图片

    第八课堂: sessions会话

    • 因为http协议特性,每一次来自于用户的浏览器请求是无状态的、独立的,也就是说无法保存用户状态,你可以在网页中尝试你把cookies进行关闭,看看你能不能访问天猫淘宝等
    • 所有现代网站通常将cookies保存不重要的东西,大部分重要的东西通过sessions会话功能进行保存在服务器端
    • django提供了一个通用sessions框架,并且可以使用多种sessions数据保存方式
    1. 保存在数据库里面
    2. 保存到缓存
    3. 保存到文件里
    4. 保存在cookies内
    • django默认session框架,你不要修改就行,大致是这样,在settings文件下
    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',#sessions会话窗口,相当于认证你是不是用户还是陌生人
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'login',
        'captcha'
    ]
    
    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',#启用sessions
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]
    
    • sessions 用法
    class backends.base.SessionBase
            # 这是所有会话对象的基类,包含标准的字典方法:
            __getitem__(key)
                Example: fav_color = request.session['fav_color']
            __setitem__(key, value)
                Example: request.session['fav_color'] = 'blue'
            __delitem__(key)
                Example: del request.session['fav_color']  # 如果不存在会抛出异常
            __contains__(key)
                Example: 'fav_color' in request.session
            get(key, default=None)
                Example: fav_color = request.session.get('fav_color', 'red')
            pop(key, default=__not_given)
                Example: fav_color = request.session.pop('fav_color', 'blue')
            # 类似字典数据类型的内置方法
            keys()
            items()
            setdefault()
            clear()
    
    
            # 它还有下面的方法:
            flush()
                # 删除当前的会话数据和会话cookie。经常用在用户退出后,删除会话。
    
            set_test_cookie()
                # 设置一个测试cookie,用于探测用户浏览器是否支持cookies。由于cookie的工作机制,你只有在下次用户请求的时候才可以测试。
            test_cookie_worked()
                # 返回True或者False,取决于用户的浏览器是否接受测试cookie。你必须在之前先调用set_test_cookie()方法。
            delete_test_cookie()
                # 删除测试cookie。
            set_expiry(value)
                # 设置cookie的有效期。可以传递不同类型的参数值:
            • 如果值是一个整数,session将在对应的秒数后失效。例如request.session.set_expiry(300) 将在300秒后失效.
            • 如果值是一个datetime或者timedelta对象, 会话将在指定的日期失效
            • 如果为0,在用户关闭浏览器后失效
            • 如果为None,则将使用全局会话失效策略
            失效时间从上一次会话被修改的时刻开始计时。
    
            get_expiry_age()
                # 返回多少秒后失效的秒数。对于没有自定义失效时间的会话,这等同于SESSION_COOKIE_AGE.
                # 这个方法接受2个可选的关键字参数
            • modification:会话的最后修改时间(datetime对象)。默认是当前时间。
            •expiry: 会话失效信息,可以是datetime对象,也可以是int或None
    
            get_expiry_date()
                # 和上面的方法类似,只是返回的是日期
    
            get_expire_at_browser_close()
                # 返回True或False,根据用户会话是否是浏览器关闭后就结束。
    
            clear_expired()
                # 删除已经失效的会话数据。
            cycle_key()
                # 创建一个新的会话秘钥用于保持当前的会话数据。django.contrib.auth.login() 会调用这个方法。
    
    • 步骤
    1. 使用session,修改login视图函数
    def login(request):
        if request.session.get('is_login',None):
            return redirect('/index/')
        if request.method == "POST":
            login_form = forms.UserForm(request.POST)
            message = "请检查填写的内容"
            if login_form.is_valid():
                username = login_form.cleaned_data['username']
                password = login_form.cleaned_data['password']
    
                #用户名字符合法性验证
                #密码长度验证
                try :
                    user = models.User.objects.get(name=username)
                    if user.password == password:
                        request.session['is_login'] = True
                        request.session['user_id'] = user.id
                        request.session['user_name'] = user.name
                        return redirect('/index/')
    
                    else:
                        message = "密码不正确"
                except:
                    message = "用户名不存在"
            return render(request,'login/login.html',locals())
        login_form = forms.UserForm
        return render(request, 'login/login.html',locals())
    
    • 修改页面,不要担心request没有加载出来,它是内置的,只是不同步,导致没有提示而已
    
            
            
    
    1. 修改index内容
    {% extends 'base.html' %}
    {% block title %}主页{% endblock %}
    {% block content %}
        {% if request.session.is_login %}
        

    你好,{ { request.session.user_name }}!欢迎回来!

    {% else %}

    你尚未登录,只能访问公开内容!

    {% endif %} {% endblock %}

    第九课堂: 注册

    • 竟然登录都已经写好了登录代码,那么你需要一个注册代码,这样才使得和前后端通信完美
    • 步骤
    1. 我们在login的forms文件中在userform的下面新建一个类,那就是我们的注册类
    class RegisterForm(forms.Form):
        gender = (
            ('male',"男"),
            ('female',"女"),
        )
        username = forms.CharField(label="用户名",max_length=128,widget=forms.TextInput(attrs={'class':'form-control'}))
        password1 = forms.CharField(label="密码",max_length=256,widget=forms.PasswordInput(attrs={'class':'form-control'}))
        password2 = forms.CharField(label="确认密码",max_length=256,widget=forms.PasswordInput(attrs={'class':'form-control'}))
        email = forms.EmailField(label="邮箱地址",widget=forms.EmailInput(attrs={'class':'form-control'}))
        sex = forms.ChoiceField(label='性别',choices=gender)
        captcha = CaptchaField(label='验证码')
        解释:
        1. gender字典里面和user模型中的一样,可以当成常量使用
        2. password1和2是为了检验两次输入密码的相同性,防止误输入密码
        3. email是一个邮箱输入框
        4. sex是一个select下拉框
    
    1. 为了与表单相适应,我们在register.html进行对login依样画葫芦
    {% extends 'base.html' %}
    {% load staticfiles %}
    {% block title %}注册{% endblock %}
    {% block content %}
       
    {% if message %}
    { { message }}
    {% endif %} {% csrf_token %}

    欢迎注册

    { { register_form.username.label_tag }} { { register_form.username}}
    { { register_form.password1.label_tag }} { { register_form.password1 }}
    { { register_form.password2.label_tag }} { { register_form.password2 }}
    { { register_form.email.label_tag }} { { register_form.email }}
    { { register_form.sex.label_tag }} { { register_form.sex }}
    { { register_form.captcha.errors }} { { register_form.captcha.label_tag }} { { register_form.captcha }}
    {% endblock %}
    • 完善views里面的映射函数,和url构建的想对应
    def register(request):
        if request.session.get('is_login',None):
            #思考一下,登录状态下注册,肯定不可行
    
           return  redirect('index/')
        if request.method == "POST":
            register_form = forms.RegisterForm(request.POST)
            message = "请检查填写的内容"
            if register_form.is_valid():
                username = register_form.cleaned_data['username']
                password1 = register_form.cleaned_data['password1']
                password2 = register_form.cleaned_data['password2']
                email = register_form.cleaned_data['email']
                sex = register_form.cleaned_data['sex']
                if password1 != password2:
                    message = "两次输入的密码不同"
                    return  render(request,'login/register.html',locals())
                else:
                    same_name_user = models.User.objects.filter(name=username)
                    if same_name_user:
                        message = '用户已经存在,请重新选择用户名'
                        return render(request,'login/register.html',locals())
                    same_email_user = models.User.objects.filter(email=email)
                    if same_email_user:
                        message = '该邮箱地址已经被注册,请使用别的邮箱'
                        return render(request,'login/register.html',locals())
                    #当然在上述都没错误的话,我们开始使用我们的东西了
                    new_user = models.User()#对于数据库里面表进行实例化,方便使用
                    new_user.name = username
                    new_user.password =hash_code(password1)
                    new_user.email = email
                    new_user.sex = sex
                    new_user.save()#进行保存
                    return  redirect('/login/')#重定向到指定的位置
        register_form = forms.RegisterForm()
        return render(request,'login/register.html',locals())
    
    • 思考一下,想阿里等大公司,你的密码肯定不可能是显示出来的密码,肯定加密了,对此,我们也使用加密
    在views中加入一下
    import hashlib
    
    def hash_code(s, salt='mysite'):# 加点盐
       h = hashlib.sha256()
       s += salt
       h.update(s.encode())  # update方法只接收bytes类型
       return h.hexdigest()
       同时对login中password的比较进行修改
       if user.password == hash_code(password):  # 哈希值和数据库内的值进行比对
     new_user.password = hash_code(password1)  # 使用加密密码
    ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190120121651475.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjQ3OTE1NQ==,size_16,color_FFFFFF,t_70)
    # 使用sha256算法,将输入密码单向转换为字符串储存在数据库中,这样的话,用户隐私得到很大保护
    
    • 对相应的登录和注册进行修改
    就是对应的密码储存,或者比对需要进行相应的加密就行
    def login(request):
        if request.session.get('is_login',None):
            return redirect('/index/')
        if request.method == "POST":
            login_form = forms.UserForm(request.POST)
            message = "请检查填写的内容"
            if login_form.is_valid():
                username = login_form.cleaned_data['username']
                password = login_form.cleaned_data['password']
    
                #用户名字符合法性验证
                #密码长度验证
                try :
                    user = models.User.objects.get(name=username)
                    # 1.
                    # 导入models模块
                    # 2.
                    # models.User.objects.get(name=username)
                    # 是Django提供的最常用的数据查询API, 因为我们之前设计好了数据库的表
                    if not user.has_confirmed:#进行邮件确认
                        message = "用户还未通过邮件确认"
                        return render(request, 'login/login.html',locals())
                    # if user.password == password:将密码与数据库里面值进行比对,而不是提取出来,浪费时间
                    # 好像数据库里面的东西拿出来会自动反转
                    print(user.password)
                    if user.password == hash_code(password):
                        request.session['is_login'] = True
                        request.session['user_id'] = user.id
                        request.session['user_name'] = user.name
                        return redirect('/index/')
    
                    else:
                        message = "密码不正确"
                except:
                    message = "用户名不存在"
            #  return render(request, 'login/login.html', {"message": message})
            return render(request,'login/login.html',locals())#local更为强大,所有的有关内容,均传递
        login_form = forms.UserForm
        return render(request, 'login/login.html',locals())
    
    
    def register(request):
        if request.session.get('is_login',None):
            #思考一下,登录状态下注册,肯定不可行
           return  redirect('index/')
        if request.method == "POST":
            register_form = forms.RegisterForm(request.POST)
            message = "请检查填写的内容"
            if register_form.is_valid():
                username = register_form.cleaned_data['username']
                password1 = register_form.cleaned_data['password1']
                password2 = register_form.cleaned_data['password2']
                email = register_form.cleaned_data['email']
                sex = register_form.cleaned_data['sex']
                if password1 != password2:
                    message = "两次输入的密码不同"
                    return  render(request,'login/register.html',locals())
                else:
                    same_name_user = models.User.objects.filter(name=username)
                    if same_name_user:
                        message = '用户已经存在,请重新选择用户名'
                        return render(request,'login/register.html',locals())
                    same_email_user = models.User.objects.filter(email=email)
                    if same_email_user:
                        message = '该邮箱地址已经被注册,请使用别的邮箱'
                        return render(request,'login/register.html',locals())
                    #当然在上述都没错误的话,我们开始使用我们的东西了
                    new_user = models.User()#对于数据库里面表进行实例化,方便使用
                    new_user.name = username
                    new_user.password =hash_code(password1)
                    new_user.email = email
                    new_user.sex = sex
                    new_user.save()#进行保存
    
    
                    code = make_confirm_string(new_user)
                    send_email(email,code)
                    return render(request,'login/confirm.html',locals())#跳转到等待邮件确认页面
        register_form = forms.RegisterForm()
        return render(request,'login/register.html',locals())
    

    django搭建一个博客,登录登出_第4张图片

    第十课堂: 发送邮件

    • 在django中发送邮件需要在settings中配置参数
    # 邮件配置
    EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
    #是否使用SSL加密,qq企业邮箱要求使用,我们又不是企业邮箱,所以不要使用ssl加密
    
    EMAIL_HOST = 'smtp.163.com'
    #指定的smtp服务器名称
    EMAIL_PORT = 25
    EMAIL_HOST_USER = '[email protected]'
    EMAIL_HOST_PASSWORD = 'qq1685715822'#授权码
    
    # 注册有效期天数
    CONFIRM_DAYS = 7
    
    • 先写一个例子,在django里面发邮件的样式:
    在mysite文件夹创建一个send_mail.py
    import os
    from django.core.mail import EmailMultiAlternatives
    from django.core.mail import send_mail
    
    os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'
    
    if __name__ == '__main__':
        # send_mail(
        #     '测试邮件',
        #     '邮件验证',
        #     '[email protected]',
        #     ['[email protected]']
        # )
        # 某些邮件公司可能不开放smtp服务
        # 某些公司要求使用ssl安全机制
        # 某些smtp服务对主机名格式有要求
        subject,from_email,to = '测试邮件','[email protected]','[email protected]'
        text_content = '欢迎'
        html_content = '

    欢迎访问艾春辉的主页

    ' msg = EmailMultiAlternatives(subject,text_content,from_email,[to]) msg.attach_alternative(html_content,"text/html") msg.send()

    django搭建一个博客,登录登出_第5张图片

    第十一课堂:确认邮件注册:

    • 我们需要创建一个邮件注册表,用来保存用户的确认码和注册时间
    • 在/login/models.py文件中写入
    from django.db import models
    
    # Create your models here.
    
    class User(models.Model):
    
        gender = (
            ('male', "男"),
            ('female', "女"),
        )
    
        name = models.CharField(max_length=128, unique=True)
        password = models.CharField(max_length=256)
        email = models.EmailField(unique=True)
        sex = models.CharField(max_length=32, choices=gender, default="男")
        c_time = models.DateTimeField(auto_now_add=True)
        has_confirmed = models.BooleanField(default=False)
    
        def __str__(self):
            return self.name
    
        class Meta:
            ordering = ["-c_time"]
            verbose_name = "用户"
            verbose_name_plural = "用户"
    
    
    class ConfirmString(models.Model):
        code = models.CharField(max_length=256)
        user = models.OneToOneField('User')
        c_time = models.DateTimeField(auto_now_add=True)
    
        def __str__(self):
            return self.user.name + ":   " + self.code
    
        class Meta:
    
            ordering = ["-c_time"]
            verbose_name = "确认码"
            verbose_name_plural = "确认码"
    #user模型中增加了确认邮件是否注册的bool型值
    #注册模型保存了用户和注册码之间的关系,一对一形式
    c_time就是注册时间
    
    • 在终端里执行:python3 manage.py migrate
    • 在/login/admin里面将模型注册进入
    • 修改注册模型
    def register(request):
        if request.session.get('is_login', None):
            # 登录状态不允许注册。你可以修改这条原则!
            return redirect("/index/")
        if request.method == "POST":
            register_form = forms.RegisterForm(request.POST)
            message = "请检查填写的内容!"
            if register_form.is_valid():  # 获取数据
                username = register_form.cleaned_data['username']
                password1 = register_form.cleaned_data['password1']
                password2 = register_form.cleaned_data['password2']
                email = register_form.cleaned_data['email']
                sex = register_form.cleaned_data['sex']
                if password1 != password2:  # 判断两次密码是否相同
                    message = "两次输入的密码不同!"
                    return render(request, 'login/register.html', locals())
                else:
                    same_name_user = models.User.objects.filter(name=username)
                    if same_name_user:  # 用户名唯一
                        message = '用户已经存在,请重新选择用户名!'
                        return render(request, 'login/register.html', locals())
                    same_email_user = models.User.objects.filter(email=email)
                    if same_email_user:  # 邮箱地址唯一
                        message = '该邮箱地址已被注册,请使用别的邮箱!'
                        return render(request, 'login/register.html', locals())
    
                    # 当一切都OK的情况下,创建新用户
    
                    new_user = models.User()
                    new_user.name = username
                    new_user.password = hash_code(password1)  # 使用加密密码
                    new_user.email = email
                    new_user.sex = sex
                    new_user.save()
    
                    code = make_confirm_string(new_user)
                    send_email(email, code)
    
                    message = '请前往注册邮箱,进行邮件确认!'
                    return render(request, 'login/confirm.html', locals())  # 跳转到等待邮件确认页面。
        register_form = forms.RegisterForm()
        return render(request, 'login/register.html', locals())
    #其实就是多了两行代码
    
    • 在views里面添加make_confirm_string(创建确认码对象)
    def make_confirm_string(user):
        now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        code = hash_code(user.name, now)
        models.ConfirmString.objects.create(code=code, user=user,)
        return code
    
    • 创建一个发送邮件函数:
    def send_email(email, code):
    
        from django.core.mail import EmailMultiAlternatives
    
        subject = '来自艾春辉的注册确认邮件'
    
        text_content = '''感谢注册'''
    
        html_content = '''
                        

    感谢注册www.aichunhui.cn

    请点击站点链接完成注册确认!

    此链接有效期为{}天!

    '''.format('127.0.0.1:8000', code, settings.CONFIRM_DAYS) msg = EmailMultiAlternatives(subject, text_content, settings.EMAIL_HOST_USER, [email]) msg.attach_alternative(html_content, "text/html") msg.send()
    • 发送注册的邮件都解决了,那么我们现在来处理邮件确认请求
    def user_confirm(request):
        code = request.GET.get('code', None)
        message = ''
        try:
            confirm = models.ConfirmString.objects.get(code=code)
        except:
            message = '无效的确认请求!'
            return render(request, 'login/confirm.html', locals())
    
        c_time = confirm.c_time
        now = datetime.datetime.now()
        if now > c_time + datetime.timedelta(settings.CONFIRM_DAYS):
            confirm.user.delete()
            message = '您的邮件已经过期!请重新注册!'
            return render(request, 'login/confirm.html', locals())
        else:
            confirm.user.has_confirmed = True
            confirm.user.save()
            confirm.delete()
            message = '感谢确认,请使用账户登录!'
            return render(request, 'login/confirm.html', locals())
    
    
    • 在template里面写入一个confirm.html
    {% extends 'base.html' %}
    {% block title %}注册确认{% endblock %}
    {% block content %}
        

    { { message }}

    {% endblock %}
    • 在login中比对密码时候进行比对是否注册:插入以下代码
    
    if not user.has_confirmed:
        message = "该用户还未通过邮件确认!"
        return render(request, 'login/login.html', locals())
    
    • 最后看我的views里面所有的代码:
    from django.shortcuts import render
    from django.shortcuts import redirect
    from . import models
    #导入本地的,不是使用默认的from django import forms
    from . import forms
    from django.conf import settings
    import hashlib
    import datetime
    from mysite import settings
    # Create your views here.
    def user_confirm(request):
        code = request.GET.get('code', None)
        message = ''
        try:
            confirm = models.ConfirmString.objects.get(code=code)
        except:
            message = '无效的确认请求!'
            return render(request, 'login/confirm.html', locals())
    
        c_time = confirm.c_time
        now = datetime.datetime.now()
        if now > c_time + datetime.timedelta(settings.CONFIRM_DAYS):
            confirm.user.delete()
            message = '您的邮件已经过期!请重新注册!'
            return render(request, 'login/confirm.html', locals())
        else:
            confirm.user.has_confirmed = True
            confirm.user.save()
            confirm.delete()
            message = '感谢确认,请使用账户登录!'
            return render(request, 'login/confirm.html', locals())
    
    
    def send_email(email, code):
    
        from django.core.mail import EmailMultiAlternatives
    
        subject = '来自艾春辉的注册确认邮件'
    
        text_content = '''感谢注册'''
    
        html_content = '''
                        

    感谢注册www.aichunhui.cn

    请点击站点链接完成注册确认!

    此链接有效期为{}天!

    '''.format('127.0.0.1:8000', code, settings.CONFIRM_DAYS) msg = EmailMultiAlternatives(subject, text_content, settings.EMAIL_HOST_USER, [email]) msg.attach_alternative(html_content, "text/html") msg.send() def make_confirm_string(user): now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") code = hash_code(user.name, now) models.ConfirmString.objects.create(code=code, user=user,) return code def hash_code(s, salt = 'mysite'): #使用sha256 h = hashlib.sha256() s += salt h.update(s.encode())#update方法只接受bytes流类型 return h.hexdigest() def index(request): return render(request, 'login/index.html') def login(request): if request.session.get('is_login',None): return redirect('/index/') if request.method == "POST": login_form = forms.UserForm(request.POST) message = "请检查填写的内容" if login_form.is_valid(): username = login_form.cleaned_data['username'] password = login_form.cleaned_data['password'] #用户名字符合法性验证 #密码长度验证 try : user = models.User.objects.get(name=username) # 1. # 导入models模块 # 2. # models.User.objects.get(name=username) # 是Django提供的最常用的数据查询API, 因为我们之前设计好了数据库的表 if not user.has_confirmed:#进行邮件确认 message = "用户还未通过邮件确认" return render(request, 'login/login.html',locals()) # if user.password == password:将密码与数据库里面值进行比对,而不是提取出来,浪费时间 # 好像数据库里面的东西拿出来会自动反转 print(user.password) if user.password == hash_code(password): request.session['is_login'] = True request.session['user_id'] = user.id request.session['user_name'] = user.name return redirect('/index/') else: message = "密码不正确" except: message = "用户名不存在" # return render(request, 'login/login.html', {"message": message}) return render(request,'login/login.html',locals())#local更为强大,所有的有关内容,均传递 login_form = forms.UserForm return render(request, 'login/login.html',locals()) def register(request): if request.session.get('is_login',None): #思考一下,登录状态下注册,肯定不可行 return redirect('index/') if request.method == "POST": register_form = forms.RegisterForm(request.POST) message = "请检查填写的内容" if register_form.is_valid(): username = register_form.cleaned_data['username'] password1 = register_form.cleaned_data['password1'] password2 = register_form.cleaned_data['password2'] email = register_form.cleaned_data['email'] sex = register_form.cleaned_data['sex'] if password1 != password2: message = "两次输入的密码不同" return render(request,'login/register.html',locals()) else: same_name_user = models.User.objects.filter(name=username) if same_name_user: message = '用户已经存在,请重新选择用户名' return render(request,'login/register.html',locals()) same_email_user = models.User.objects.filter(email=email) if same_email_user: message = '该邮箱地址已经被注册,请使用别的邮箱' return render(request,'login/register.html',locals()) #当然在上述都没错误的话,我们开始使用我们的东西了 new_user = models.User()#对于数据库里面表进行实例化,方便使用 new_user.name = username new_user.password =hash_code(password1) new_user.email = email new_user.sex = sex new_user.save()#进行保存 code = make_confirm_string(new_user) send_email(email,code) return render(request,'login/confirm.html',locals())#跳转到等待邮件确认页面 register_form = forms.RegisterForm() return render(request,'login/register.html',locals()) def logout(request): if not request.session.get('is_login',None): #如果本来就没有登录,也就没有等出一说 return redirect("/index/") request.session.flush() # 或者使用下面的方法 # del request.session['is_login'] # del request.session['user_id'] # del request.session['user_name'] return redirect("/index/")
    • url里面代码:
    from django.contrib import admin
    from django.urls import path
    from login import views
    from django.conf.urls import include
    from django.urls import re_path
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('index/', views.index, name='index'),
        path('login/', views.login, name='login'),
        # path('',views.base,name ='base'),
        path('', views.index),
        path('register/', views.register, name='register'),
        path('logout/', views.logout, name='logout'),
        re_path(r'^captcha/', include('captcha.urls'), name='captchas'),  # 添加captcha相对应的网址
        re_path(r'^confirm/$', views.user_confirm, name='cofirms')
    ]
    
    

    结课:

    • 源码地址
    • 借鉴自刘江先生的博客

    你可能感兴趣的:(学生,python,django,python)