Django Blog之用户登录认证
用户登录认证
一、需要的知识点
1 Bootstrap
2 Ajax
3 Auth
4 jQuery
二、setting配置
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
""" 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中,以此使用auth模块
AUTH_USER_MODEL = "app01.UserInfo" #(app名.Django默认用户表)
三、表结构的设计
开发完成一个项目先需要完成的是表结构的设计,现列出此项目需要的所有表
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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")
登录页面函数
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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")
图片验证函数
# 图片验证码 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
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!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) } } }) })