from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import redirect
classAutuMiddleWare(MiddlewareMixin):defprocess_request(self,request):if request.path in["/login/","/register/","/get_valid_img/"]:returnNoneifnot request.user.is_authenticated:return redirect("/login/")
models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
# Create your models here.classBook(models.Model):id=models.AutoField(primary_key=True)
title=models.CharField(max_length=32)
state=models.BooleanField()
pub_date=models.DateField()
price=models.DecimalField(max_digits=8,decimal_places=2)
publish=models.CharField(max_length=32)classUserInfo(AbstractUser):
tel=models.CharField(max_length=11)
email = models.EmailField(blank=True,null=True)
views.py
from django.shortcuts import render,HttpResponse,redirect
from book.models import Book,UserInfo
from django.urls import reverse
from django.forms import widgets
from django import forms
from django.core.exceptions import ValidationError
import random
import json
from django.core.paginator import Paginator,EmptyPage,PageNotAnInteger
from django.http import JsonResponse
from django.contrib import auth
from django.contrib.auth.backends import ModelBackend
from django.db.models import Q
# Create your views here.classUsernameMobileAuthBackend(ModelBackend):"""用户名或手机登录"""defauthenticate(self, request, username=None, password=None,**kwargs):"""判断用户名(手机号码)和密码是否正确"""
query_set = UserInfo.objects.filter( Q(username=username)| Q(tel=username))try:if query_set.exists():
user = query_set.get()if user.check_password(password):return user
except:returnNonereturnNoneclassUserForm(forms.Form):
tel = forms.CharField(max_length=12,min_length=10,
label="手机号",
widget=widgets.NumberInput(attrs={"class":"form-control"}),
error_messages={"required":"手机号不能为空","invalid":"手机号有错误"})
email = forms.EmailField(label="邮箱",
widget=widgets.EmailInput(attrs={"class":"form-control"}),
error_messages={"required":"邮箱不能为空","invalid":"邮箱格式错误"})
username=forms.CharField(max_length=32,min_length=4,
label="用户名",
widget=widgets.TextInput(attrs={"class":"form-control"}),
error_messages={"required":"用户名不能为空","min_length":"用户名最低四个字符"})
password=forms.CharField(max_length=32,min_length=4,
label="密码",
widget=widgets.PasswordInput(attrs={"class":"form-control"}),
error_messages={"required":"密码不能为空","min_length":"密码最低四个字符"})
r_pwd=forms.CharField(max_length=32,min_length=4,
label="确认密码",
widget=widgets.PasswordInput(attrs={"class":"form-control"}),
error_messages={"required":"确认密码不能为空"})defclean_user(self):
val=self.cleaned_data.get("user")
ret=UserInfo.objects.filter(user=val).first()ifnot ret:return val
else:raise ValidationError("用户名已存在")defclean_tel(self):
val=self.cleaned_data.get("tel")
ret=UserInfo.objects.filter(tel=val).first()ifnot ret:return val
else:raise ValidationError("电话号码已注册")defclean_email(self):
val=self.cleaned_data.get("email")
ret=UserInfo.objects.filter(email=val).first()ifnot ret:return val
else:raise ValidationError("邮箱已注册")defclean(self):
pwd=self.cleaned_data.get("pwd")
r_pwd=self.cleaned_data.get(("r_pwd"))if pwd and r_pwd:if pwd==r_pwd:return self.cleaned_data
else:raise ValidationError("两次密码不一致!")else:return self.cleaned_data
defadd(request):if request.method =="POST":
data = request.POST.dict()del data["csrfmiddlewaretoken"]
data["state"]=True
response ={"state":True}try:
book_obj = Book.objects.create(**data)except Exception as e:
response ={"state":False}return HttpResponse(json.dumps(response))else:return render(request,"addbook.html")defbooks(request):
book_list = Book.objects.all()
paginator = Paginator(book_list,10)
page = request.GET.get('page',1)
currentPage =int(page)# 如果页数十分多时,换另外一种显示方式if paginator.num_pages >11:if currentPage -5<1:
pageRange =range(1,11)elif currentPage +5> paginator.num_pages:
pageRange =range(currentPage -5, paginator.num_pages +1)else:
pageRange =range(currentPage -5, currentPage +5)else:
pageRange = paginator.page_range
try:
book_list = paginator.page(page)except PageNotAnInteger:
book_list = paginator.page(1)except EmptyPage:
book_list = paginator.page(paginator.num_pages)return render(request,"books.html",{"book_list": book_list,"paginator": paginator,"currentPage": currentPage})# 批量插入数据# book_list=[]# for i in range(1,101):# book=Book(title="book_%s"%i,state="1",pub_date="2020-06-07",price=i*i,publish="黄河出版社")# book_list.append(book)# Book.objects.bulk_create(book_list)defdelbook(requset,delete_book_id):
response={"state":True}try:
Book.objects.filter(id=delete_book_id).delete()except Exception as e:
response={"state":False}return HttpResponse(json.dumps(response))defeditbook(request,edit_book_id):if request.method=="GET":
edit_book=Book.objects.filter(id=edit_book_id)[0]return render(request,"editbook.html",{"edit_book":edit_book})else:
title=request.POST.get("title")
price=request.POST.get("price")
pub_date=request.POST.get("pub_date")
publish=request.POST.get("publish")
Book.objects.filter(id=edit_book_id).update(title=title,price=price,pub_date=pub_date,publish=publish)return redirect(reverse("books"))defregister(request):if request.method=="POST":print(request.POST)
form=UserForm(request.POST)
response={"user":None,"err_msg":""}if form.is_valid():del form.cleaned_data["r_pwd"]
UserInfo.objects.create_user(**form.cleaned_data)
response["user"]="1"else:
clean_error=form.errors.get("__all__")
response["err_msg"]=form.errors
return JsonResponse(response)
form=UserForm()return render(request,"register.html",locals())deflogin(request):if request.is_ajax():
user=request.POST.get("user")
pwd=request.POST.get("pwd")
validcode=request.POST.get("validcode")
response={"user":None,"err_msg":""}if validcode.upper()==request.session.get("keep_str").upper():
get_valid_img(request)
user_obj=auth.authenticate(username=user,password=pwd)if user_obj:
auth.login(request,user_obj)
response["user"]=user
else:
response["err_msg"]="用户名或者密码错误!"else:
response["err_msg"]="验证码错误!"return JsonResponse(response)return render(request,"login.html",locals())defget_valid_img(request):from PIL import Image,ImageFont,ImageDraw
from io import BytesIO
defget_random_color():return(random.randint(0,255),random.randint(0,255),random.randint(0,255))
img = Image.new("RGB",(100,40), get_random_color())
draw = ImageDraw.Draw(img)
font = ImageFont.truetype("static/font/kumo.ttf",32)
keep_str=""for i inrange(4):
random_num=str(random.randint(0,9))
random_low=chr(random.randint(97,122))
random_upper=chr(random.randint(65,90))
random_char=random.choice([random_num,random_low,random_upper])
draw.text((i*20+10,0),random_char,get_random_color(),font=font)
keep_str+=random_char
width=100
height=40for i inrange(5):
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 inrange(5):
draw.point([random.randint(0,width),random.randint(0,height)],fill=get_random_color())
x1=random.randint(0,width)
y1=random.randint(0,height)
draw.arc((x1,y1,x1+4,y1+4),0,90,fill=get_random_color())
f=BytesIO()
img.save(f,"png")
data=f.getvalue()
request.session["keep_str"]=keep_str
print(keep_str)return HttpResponse(data)
settings.py
"""
Django settings for booksys project.
Generated by 'django-admin startproject' using Django 3.1.
For more information on this file, see
https://docs.djangoproject.com/en/dev/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/dev/ref/settings/
"""import os
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve(strict=True).parent.parent
# Quick-start development settings - unsuitable for production# See https://docs.djangoproject.com/en/dev/howto/deployment/checklist/# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY ='eje_%rl=ab5ibd@l8@ru!0+$9m*-#dlcnlw!$du@nq5@7ewlwl'# 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','book.apps.BookConfig',]
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','book.middlewares.AutuMiddleWare',]
ROOT_URLCONF ='booksys.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 ='booksys.wsgi.application'# Database# https://docs.djangoproject.com/en/dev/ref/settings/#databases
DATABASES ={'default':{'ENGINE':'django.db.backends.mysql','NAME':'booksys',# 要连接的数据库,连接前需要创建好'USER':'root',# 连接数据库的用户名'PASSWORD':'yf8629976',# 连接数据库的密码'HOST':'127.0.0.1',# 连接主机,默认本级'PORT':3306# 端口 默认3306}}# Password validation# https://docs.djangoproject.com/en/dev/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/dev/topics/i18n/
LANGUAGE_CODE ='en-us'
TIME_ZONE ='UTC'
USE_I18N =True
USE_L10N =True
USE_TZ =True# Static files (CSS, JavaScript, Images)# https://docs.djangoproject.com/en/dev/howto/static-files/
STATIC_URL ='/static/'
STATICFILES_DIRS=[
os.path.join(BASE_DIR,"static")]
AUTH_USER_MODEL="book.UserInfo"
AUTHENTICATION_BACKENDS =['book.views.UsernameMobileAuthBackend']
SESSION_SAVE_EVERY_REQUEST =True
SESSION_EXPIRE_AT_BROWSER_CLOSE =True
urls.py
"""booksys URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/dev/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""from django.contrib import admin
from django.urls import path,re_path
from book.views import add,books,delbook,editbook,register,login,get_valid_img
urlpatterns =[
path('admin/', admin.site.urls),
path('books/add/', add),
path('books/', books,),
re_path('^$', books,name="books"),
re_path('books/delete/(\d+)', delbook),
re_path('books/edit/(\d+)', editbook),
re_path('register/', register),
re_path('login/', login),
re_path('get_valid_img/',get_valid_img),]