Django Blog之用户登录认证

用户登录认证

一、需要的知识点

1 Bootstrap

2 Ajax

3 Auth

4 jQuery

二、setting配置

"""
Django settings for blog project.

Generated by 'django-admin startproject' using Django 1.11.11.

For more information on this file, see
https://docs.djangoproject.com/en/1.11/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.11/ref/settings/
"""

import os

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '7@j(4&32%59mi%f*wtx#18b#-kldw-8@p5-((j3o0(5wtkt1(d'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app01',
]

MIDDLEWARE = [
    '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',
]

ROOT_URLCONF = 'blog.urls'

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',
            ],
        },
    },
]

WSGI_APPLICATION = 'blog.wsgi.application'

# Database
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases

# DATABASES = {
#     'default': {
#         'ENGINE': 'django.db.backends.sqlite3',
#         'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
#     }
# }


DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'myblog',
        "USER": "root",
        "PASSWORD": "111111",
        "HOST": "127.0.0.1",
        "PORT": 3306
    }
}

# Password validation
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

# Internationalization
# https://docs.djangoproject.com/en/1.11/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True
AUTH_USER_MODEL = "app01.UserInfo"
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.11/howto/static-files/

STATIC_URL = '/static/'
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'static')
]
setting

重点在于将下列内容写入setting中,以此使用auth模块

AUTH_USER_MODEL = "app01.UserInfo"  #(app名.Django默认用户表)

三、表结构的设计

开发完成一个项目先需要完成的是表结构的设计,现列出此项目需要的所有表

from django.db import models
from django.contrib.auth.models import AbstractUser

# Create your models here.

# 用户表
class UserInfo(AbstractUser):
    nid = models.AutoField(primary_key=True)
    telephone = models.CharField(max_length=11, null=True, unique=True, verbose_name="电话号码")
    create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    image = models.FileField(upload_to='image/', default="/image/default.png", verbose_name="头像地址")

    blog = models.OneToOneField(to="Blog", to_field='nid', null=True)

    def __str__(self):
        return self.username

    class Meta:
        verbose_name = "用户表"
        db_table = verbose_name
        verbose_name_plural = verbose_name


# 博客表
class Blog(models.Model):
    nid = models.AutoField(primary_key=True)
    title = models.CharField(max_length=64, verbose_name="博客标题")
    site = models.CharField(max_length=32, unique=True, verbose_name="博客后缀")
    theme = models.CharField(max_length=32, verbose_name="博客主题")

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = "博客表"
        db_table = verbose_name
        verbose_name_plural = verbose_name

# 博客文章分类表
class Category(models.Model):
    nid = models.AutoField(primary_key=True)
    title = models.CharField(max_length=32, verbose_name="分类标题")
    blog = models.ForeignKey(to="Blog", to_field='nid', verbose_name="所属博客")

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = "博客分类表"
        db_table = verbose_name
        verbose_name_plural = verbose_name


# 博客文章标签表
class Tag(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32, verbose_name="标签名称")
    blog = models.ForeignKey(to="Blog", to_field="nid", verbose_name="所属博客")

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = "标签信息表"
        db_table = verbose_name
        verbose_name_plural = verbose_name

# 文章表
class Article(models.Model):
    nid = models.AutoField(primary_key=True)
    title = models.CharField(max_length=50, verbose_name="文章标题")
    desc = models.CharField(max_length=255, verbose_name="文章描述")
    create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    user = models.ForeignKey(to="UserInfo",to_field='nid', verbose_name="所属用户")
    category = models.ForeignKey(to='Category', to_field='nid', null=True, verbose_name="所属分类")
    tag = models.ManyToManyField(to="Tag",
                                 through="Article2Tag",
                                 through_fields=("article","tag"),
                                 verbose_name="所属标签")

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = "文章表"
        db_table = verbose_name
        verbose_name_plural = verbose_name


# 文章细节表
class ArticleDetail(models.Model):
    nid = models.AutoField(primary_key=True)
    content = models.TextField(verbose_name="文章内容")
    article = models.OneToOneField(to="Article", to_field="nid", verbose_name="文章id")

    def __str__(self):
        return self.content

    class Meta:
        verbose_name = "文章细节表"
        db_table = verbose_name
        verbose_name_plural = verbose_name

# 文章与标签表
class Article2Tag(models.Model):
    '''
    文章与标签表
    '''
    nid = models.AutoField(primary_key=True)
    article = models.ForeignKey(to="Article", to_field="nid", verbose_name="文章")
    tag = models.ForeignKey(to="Tag", to_field="nid", verbose_name="标签")

    def __str__(self):
        v = self.article.title+"--"+self.tag.name

    class Meta:
        unique_together=[
            ("article","tag")
        ]


# 文章点赞踩灭表
class ArticleUpDown(models.Model):
    nid = models.AutoField(primary_key=True)
    user = models.ForeignKey(to="UserInfo", null=True, verbose_name="点赞用户")
    article = models.ForeignKey(to="Article", null=True, verbose_name="点赞文章")
    is_up = models.BooleanField(default=True, verbose_name="是否点赞")


    class Meta:
        verbose_name = "文章点赞踩灭"
        db_table = verbose_name
        verbose_name_plural = verbose_name
        unique_together = [
            ("user", "article"),
        ]


# 评论表
class Comment(models.Model):
    nid = models.AutoField(primary_key=True)
    user = models.ForeignKey(to="UserInfo",to_field="nid", verbose_name="评论者")
    article = models.ForeignKey(to="Article", to_field="nid", verbose_name="评论文章")
    content = models.CharField(max_length=255, verbose_name="评论内容")
    create_time = models.DateTimeField(auto_now_add=True, verbose_name="评论时间")

    parent_comment = models.ForeignKey("self", null=True)

    def __str__(self):
        return self.content

    class Meta:
        verbose_name = "评论表"
        db_table = verbose_name
        verbose_name_plural = verbose_name
表结构

四、URL

from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
    url(r'^index/', views.index),   #首页
    url(r'^login/', views.login),   #登录页面
    url(r'^get_valid_img/', views.get_valid_img),   #获取图片验证
    url(r'^$', views.login),    #无效路径返回登录页面
]

五、views

首页函数

def index(request):
    # 如果数据库找不到此用户,跳转到登录页面
    if not request.user.username:
        return redirect("/login/")
    return render(request, "index.html")

登录页面函数

def login(request):
    if request.is_ajax():
        user = request.POST.get("user")
        pwd = request.POST.get("pwd")
        valid_code = request.POST.get("valid_code")
        res = {"state": False, "msg": None}

        valid_str = request.session.get("valid_str")    #通过session取到用户输入的验证码信息

        if valid_code.upper() == valid_str.upper():
            user = auth.authenticate(username=user,password=pwd) #从数据库进行比对,没有用户则返回空

            if user:
                res["state"] = True
                auth.login(request, user)  #登录校验
            else:
                res["msg"] = "用户名或密码错误"
        else:
            res["msg"] = "验证码错误"

        return JsonResponse(res) #对res进行序列化

    return render(request, "login.html")
login页面

图片验证函数

# 图片验证码
def get_valid_img(request):

    import PIL

    from PIL import Image
    from PIL import ImageDraw, ImageFont
    import random

    def get_random_color():
        return (random.randint(0,255),random.randint(0,255), random.randint(0,255))

    image = Image.new("RGB", (255, 38), get_random_color())

    # 生成五个随机字符串
    draw = ImageDraw.Draw(image)
    font = ImageFont.truetype("static/fonts/kumo.ttf", size=32)
    temp = []
    for i in range(5):
        random_num = str(random.randint(0, 9))
        random_low_alpha = chr(random.randint(97, 122))    #生成a到z之间的一个字母
        random_up_alpha = chr(random.randint(65, 90))      #生成A到Z之间的一个字母
        random_char = random.choice([random_num, random_low_alpha, random_up_alpha])
        draw.text((24+i*36,0), random_char, get_random_color(), font=font)
        #保存随机字符
        temp.append(random_char)
    # 噪点噪线
    width = 255
    height=40
    # 噪线
    for i in range(10):
        x1=random.randint(0,width)
        x2=random.randint(0,width)
        y1=random.randint(0,height)
        y2=random.randint(0,height)
        draw.line((x1,y1,x2,y2),fill=get_random_color())
    # 噪点
    for i in range(20):
        draw.point([random.randint(0, width), random.randint(0, height)], fill=get_random_color())
        x = random.randint(0, width)
        y = random.randint(0, height)
        draw.arc((x, y, x + 4, y + 4), 0, 90, fill=get_random_color())

    #在内存生成图片
    from io import BytesIO
    f = BytesIO()
    image.save(f, "png")
    data = f.getvalue()   #获取图片的数据
    f.close()

    # ["a","2","2","s"]
    valid_str = "".join(temp)  #将生成的图片中的列表转换成字符串  "a22s"
    print("valid_str", valid_str)
    print("*"*120)
    print(temp)


    request.session["valid_str"] = valid_str  #将图片中字符串存到session表中

    return HttpResponse(data) #返回获取的图片数据

六、主页HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
hello {{ request.user.username }}
<h6>您的邮箱是{{ request.user.email }}</h6>
</body>
</html>

七、登录HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录页面</title>

{#    <script src="/static/bs/bootstrap.min.css"></script>#}
    <link rel="stylesheet" href="/static/bs/bootstrap.min.css">
    <style>
        .container{
            margin-top:120px;
        }
    </style>
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-md-6 col-md-offset-3">
            <form action="">
{#                {% csrf_token %}#}
                <div class="form-group">
                    <label for="user">用户名:</label>
                    <input type="text" id="user" class="form-control" placeholder="username">
                </div>
                <div class="form-group">
                    <label for="user">密码:</label>
                    <input type="password" id="pwd" class="form-control" placeholder="password">
                </div>
                <div class="form-group">
                    <label for="valid_code">验证码:</label>
                    <div class="row">
                        <div class="col-md-6">
                            <input type="text" class="form-control" id="valid_code">
                        </div>
                        <div class="col-md-6">
                            <img height="38" width="255" src="/get_valid_img" alt="">
{#                            <input type="text" class="form-control">#}
                        </div>
                    </div>
                </div>
                <input type="button" class="btn btn-default login_btn" value="提交"><span class="error" style="color:red;"></span>
            </form>
        </div>
    </div>
</div>
<script src="/static/js/jquery-3.2.1.min.js"></script>
<script src="/static/csrf/init_ajax.js"></script>
<script>
    $(".login_btn").on('click',function () {
        $.ajax({
            url:'',
            type:'post',
            data:{
                {#csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val(),#}
                user:$("#user").val(),
                pwd:$("#pwd").val(),
                valid_code:$("#valid_code").val()
            },
            success:function (data) {
                console.log(data);
                if(data.state){
                    location.href="/index/"
                }
                else {
                    $(".error").text(data.msg)
                }
            }
        })
    })
</script>
</body>
</html>
登录页面

script代码

$(".login_btn").on('click',function () {
        $.ajax({
            url:'',
            type:'post',
            data:{
                {#csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val(),#}
                user:$("#user").val(),
                pwd:$("#pwd").val(),
                valid_code:$("#valid_code").val()
            },
            success:function (data) {
                console.log(data);
                if(data.state){
                    location.href="/index/"
                }
                else {
                    $(".error").text(data.msg)
                }
            }
        })
    })

 

posted @ 2018-04-14 18:49  amyleell  阅读(206)  评论(0编辑  收藏  举报