登录与注册系统

reference:http://www.liujiangblog.com/course/django/104

搭建项目环境

Pycharm创建虚拟环境

修改settings.py时区语言

创建login app

模型层

数据库模型设计

  1. from django.db import models
  2. # Create your models here.
  3. class User(models.Model):
  4. gender = (
  5. ('male', '男'),
  6. ('female', '女'),
  7. )
  8. name = models.CharField(max_length=128, unique=True)
  9. password = models.CharField(max_length=256)
  10. email = models.EmailField(unique=True)
  11. sex = models.CharField(max_length=32, choices=gender, default='男')
  12. c_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间') # 创建时间
  13. def __str__(self):
  14. return self.name
  15. class Meta:
  16. ordering = ['-c_time'] # 时间降序排列
  17. verbose_name = '用户'
  18. verbose_name_plural = '用户'

数据库后端

Django支持Mysql,SQLite,Oracle等,默认使用SQLite

注册app

创建记录和数据表

  1. python manage.py makemigrations
  2. python manage.py migrate

Admin后台

在admin中注册模型

  1. # loginResgiter/settings.py
  2. INSTALLED_APPS = [
  3. 'django.contrib.admin', # 看这里
  4. 'django.contrib.auth',
  5. 'django.contrib.contenttypes',
  6. 'django.contrib.sessions', # 看这里
  7. 'django.contrib.messages',
  8. 'django.contrib.staticfiles',
  9. 'login',
  10. ]
  11. # login/admin.py 显示在admin后台
  12. from django.contrib import admin
  13. # Register your models here.
  14. from . import models
  15. admin.site.register(models.User)

创建超级管理员

  1. python manage.py createsuperuser

视图层+模板层

路由设计

路由设计

访问逻辑

  • 未登录人员,不论是访问index还是login和logout,全部跳转到login界面
  • 已登录人员,访问login会自动跳转到index页面
  • 已登录人员,不允许直接访问register页面,需先logout
  • 登出后,自动跳转到login界面

一级路由

  1. loginRegister/urls.py
  2. from django.contrib import admin
  3. from django.urls import path
  4. from login import views
  5. urlpatterns = [
  6. path('admin/', admin.site.urls),
  7. path('index/', views.index),
  8. path('login/', views.login),
  9. path('register/', views.register),
  10. path('logout/', views.logout),
  11. ]

初步视图编写

  1. from django.shortcuts import render
  2. from django.shortcuts import redirect
  3. # Create your views here.
  4. def index(request):
  5. pass
  6. return render(request, 'login/index.html')
  7. def login(request):
  8. pass
  9. return render(request, 'login/login.html')
  10. def register(request):
  11. pass
  12. return render(request, 'login/register.html')
  13. def logout(request):
  14. pass
  15. return redirect("/login/")

创建所需HTML文件

在login app下创建 tempaltes/login/ ,其下放置index.html, login.html, register.html

登录界面

login()

页面访问和处理数据都在同一个函数中

  • 第一访问页面 /login/ 时,loginRegister/urls.py 路由转发进入login方法,判断到request.method不是post,于是直接返回页面。
  • 写入登录信息,由于 action="/login/" , loginRegister/urls.py 路由转发到login方法,判断request.method为post,处理数据,跳转到index界面

redirect()

传递的值是需要路由转发的,经过loginRegister/urls.py ,查到 /index/ 所属页面

render()

传递的是app内的网页值,系统会直接找到网页,不需要经过loginRegister/urls.py

  1. def login(request):
  2. if request.method == 'POST':
  3. username = request.POST.get('username')
  4. password = request.POST.get('password')
  5. print(username, password)
  6. return redirect('/index/') #返回
  7. return render(request, 'login/login.html')

数据验证

数据验证分前端页面验证和后台服务器验证。前端验证可以通过专门的插件或者自己写JS代码实现,也可以简单地使用HTML5的新特性。

表单

创建表单模型

widgets见

  1. # login/forms.py
  2. from django import forms
  3. class UserForm(forms.Form):
  4. username = forms.CharField(label="用户名", max_length=128)
  5. password = forms.CharField(label="密码", max_length=256, widget=forms.PasswordInput)

视图

  1. def login(request):
  2. if request.method == 'POST':
  3. login_form = forms.UserForm(request.POST)
  4. message = '请检查填写的内容!'
  5. if login_form.is_valid():
  6. username = login_form.cleaned_data.get('username')
  7. password = login_form.cleaned_data.get('password')

页面

为了页面美观等,需要手动渲染样式,input属性在forms.py字段的widgets属性中设置

  1. <div class="form-group">
  2. {{ login_form.username.label_tag }}
  3. {{ login_form.username}}
  4. </div>
  5. <div class="form-group">
  6. {{ login_form.password.label_tag }}
  7. {{ login_form.password }}
  8. </div>

图片验证码

django-simple-captcha 提供了验证码功能

安装

注册到app列表

写入app列表,而且captcha要写入数据库

修改forms.py

**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', 'placeholder': "Username",'autofocus': ''}))
    password = forms.CharField(label="密码", max_length=256, widget=forms.PasswordInput(attrs={'class': 'form-control',  'placeholder': "Password"}))
    captcha = CaptchaField(label='验证码')

添加路由

path('captcha/', include('captcha.urls'))   # 增加这一行

session会话

保存用户的状态、数据,可用于验证用户是否登录

登录

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 = '密码不正确!'
                return render(request, 'login/login.html', locals())

登出

def logout(request):
    if request.session.get('is_login', None):
        request.session.flush()
        return redirect('/login/')
    return redirect('/login/')

注册

register()

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.get('username')
            password1 = register_form.cleaned_data.get('password1')
            password2 = register_form.cleaned_data.get('password2')
            email = register_form.cleaned_data.get('email')
            sex = register_form.cleaned_data.get('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 = password1
                new_user.email = email
                new_user.sex = sex
                new_user.save()

                return redirect('/login/')
        else:
            return render(request, 'login/register.html', locals())
    register_form = forms.RegisterForm()
    return render(request, 'login/register.html', locals())

加密

# import hashlib
def hash_code(s, salt='mysite'):
    h = hashlib.sha256()
    s += salt
    h.update(s.encode())
    return h.hexdigest()

Github管理项目

requirements.txt

requirements.txt文件是一个项目的依赖文件。

进入虚拟环境,切换到项目根目录下,使用pip工具的freeze参数。

(venv)
~/PycharmProjects/loginRegister
▶ pip3 freeze > ./requirements.txt

他人如果拷贝了我们的代码,要安装第三方库依赖的话,只需要:

pip install -r requirements.txt

就可以一次性安装好所有的库了。

.gitignore

在项目代码中,有一些文件是不能上传的,比如密码文件、数据库文件、核心配置文件等等,还有一些是不用上传的,比如临时文件。为了让git自动忽略这些文件,我们需要创建一个忽略名单。

在项目根目录下新建一个.gitignore文件

.gitignore文件里写入下面的内容:

.gitignore
venv
.idea
settings.py
db.sqlite3
mysite/__pycache__/

这些文件将不会上传到Github中,也不会进行版本管理

特殊文件处理

有些文件是项目必需但又会泄露隐私,可以在相同路径下创建类似文件,如 [settings.example.py](http://settings.example.py) ,把敏感信息删除或修改。

说明文件

[README.md](http://readme.md) 在文件里写入项目说明,使用方法,注意事项等等所有你认为需要说明的东西

许可文件

代码授权许可。。。

使用Github仓库源码

  • 创建虚拟环境
  • 使用pip安装第三方依赖
  • 修改settings.example.py文件为settings.py
  • 运行migrate命令,创建数据库和数据表
  • 运行python manage.py runserver启动服务器

重用app

打包app

打包的本质,就是封装你的源代码和文件成为一种新的数据包装格式,有利于传输、分发和安装。在Django中打包一个app只需要下面八个步骤:

文件准备

在你的Django项目目录外面,为我们的login应用,准备一个父目录,这里取名django-login-register

额外提醒:

为你的app选择一个合适的名字:在取名前,去PyPi搜索一下是否有重名或冲突的app(包)已经存在。建议给app的名字加上“django-”的前缀。名字不能和任何Django的contrib packages中的app重名,例如auth、admin、messages等等。

拷贝文件

将mysite/login目录中的所有内容拷贝到django-login-register目录内。将login/migrations目录中,除了__init__.py外的文件全部删除,这些被删除的文件是我们先前在本地数据库的操作记录,不应该打包到里面。

创建说明文档

创建一个说明文档django-login-register/README.rst,写入下面的内容:

=====
登录和注册系统
=====
## 这是一个用户登录和注册教学项目
## 这是一个可重用的登录和注册APP
## 该项目教程发布在www.liujiangblog.com
## 简单的使用步骤:
1. 创建虚拟环境
2. 使用pip安装第三方依赖
3. 添加相应的路由
4. 配置settings
5. 运行migrate命令,创建数据库和数据表
6. 链接你的index页面
7. 运行python manage.py runserver启动服务器
## 路由设置:
from django.contrib import admin
from django.urls import path, include
from login import views
urlpatterns = [ path('admin/', admin.site.urls), path('index/', views.index), path('login/', views.login), path('register/', views.register), path('logout/', views.logout), path('confirm/', views.user_confirm), path('captcha/', include('captcha.urls'))
]
## settings配置:
1. 在INSTALLED_APPS中添加‘login’,'captcha'
2. 默认使用Sqlite数据库
3. LANGUAGE_CODE = 'zh-hans'
4. TIME_ZONE = 'Asia/Shanghai'
5. USE_TZ = False
# 邮件服务设置
6. EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
7. EMAIL_HOST = 'smtp.sina.com'
8. EMAIL_PORT = 25
9. EMAIL_HOST_USER = 'xxxx@sina.com'
10. EMAIL_HOST_PASSWORD = 'xxxxx'
# 注册有效期天数
11. CONFIRM_DAYS = 7

这其实是一个纯文本文件,内容和格式完全自由,但核心要点是注明你的app功能和简单的使用方法。

添加授权声明

创建一个django-login-register/LICENSE版权申明文件。大多数Django相关的app都基于BSD版权。如果不是发布到正式场合,可以不写。

创建setup.py脚本

创建一个django-login-register/setup.py文件,包含了编译和安装app的配置细节。这种配置脚本的具体语法,请前往setuptools的官方文档获取详细的教程。下面是一个范例,大多数情况下,你在此基础上改改就可以了:

iption='一个通用的用户注册和登录系统',
    long_description=README,
    url='https://www.liujiangblog.com/',
    author='liujiang',
    author_email='yourname@example.com',
    classifiers=[
        'Environment :: Web Environment',
        'Framework :: Django',
        'Framework :: Django :: 2.2',  # replace "X.Y" as appropriate
        'Intended Audience :: Developers',
        'License :: OSI Approved :: BSD License',  # example license
        'Operating System :: OS Independent',
        'Programming Language :: Python',
        # Replace these appropriately if you are stuck on Python 2.
        'Programming Language :: Python :: 3',
        'Programming Language :: Python :: 3.6',
        'Programming Language :: Python :: 3.7',
        'Topic :: Internet :: WWW/HTTP',
        'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
    ],
)

例子中的配置项看起来有点复杂,实际简单得不要不要的。耐心点,就完全不是问题。

需要注意的是,如果你的readme文件中有中文,那么在setup.py文件的open方法中要指定encoding='utf-8',否则会出现编码错误。

创建MANIFEST文件

默认情况下,只有Python的模块和包会被打包进我们的app内。为了包含一些其它的文件,比如静态文件、templates模板等非Python语言编写的文件,需要创建一个django-login-register/MANIFEST.in文件,并写入下面的内容:

include LICENSE
include README.rst
recursive-include login/static *
recursive-include login/templates *
recursive-include docs *

添加doc目录

该步骤可选,但是强烈推荐将详细的说明文档一起打包。创建一个空的目录django-login-register/docs,用于放置app相关的所有文档。同时确认在django-login-register/MANIFEST.in文件内有一行recursive-include docs *。需要注意的是,如果docs目录是空的,那么它不会被打包进去。

执行打包动作

django-login-register目录内,运行python setup.py sdist命令。这将会创建一个dist目录,并生成django-login-register-1.0.tar.gz文件。同时生成一个django_login_register.egg-info文件夹。

八个步骤完成了,我们的app也就打包好了。

使用打包好的app

实际使用时,我们只需要使用django-login-register-1.0.tar.gz这个文件就可以了。

在安装包的时候,最好是以个人用户的身份安装,而不是全系统范围的身份。这样可以有效减少给别的用户带去的影响或被别的用户影响。当然,最好的方式是在virtualenv环境,这种类似隔离的沙盒环境中使用(此时,不需要--user选项)。

安装

pip install django-login-register-1.0.tar.gz
pip list  # 查看安装环境

在虚拟环境中使用pip安装的时候,一定要注意pip和Python的对应关系,所有的重点都是,你必须确保包被安装在了正确的位置。

最后需要提醒的是,这种方式安装后,app的文件会放在Python环境的site-packages中,而不是以源代码的形式放在我们认为的项目中。我们可以import login,可以在settings中注册‘login’,但要修改login中的源码,则需要去site-packages中。

一定要注意,pip安装的时候,使用的名字是django-login-register-1.0.tar.gz,而不是pip install login。实际使用中import的时候是‘import login’,而不是‘import django-login-register’。

安装成功后,再安装依赖包django-simple-captcha等等,然后在新Django项目的INSTALLED_APPS设置中注册login和captcha,按照使用说明,添加路由,修改settings配置,创建数据表,链接新的index页面,然后启动服务器,就可以使用这个app了。

卸载

pip uninstall django-login-register

对于新手,一定要清楚的是:以使用一个第三方库的形式来重用这个app