图书管理系统v1.0
middlewares.py
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import redirect
class AutuMiddleWare(MiddlewareMixin):
def process_request(self,request):
if request.path in ["/login/","/register/","/get_valid_img/"]:
return None
if not request.user.is_authenticated:
return redirect("/login/")
models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
class Book(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)
class UserInfo(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
class UsernameMobileAuthBackend(ModelBackend):
"""用户名或手机登录"""
def authenticate(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:
return None
return None
class UserForm(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": "确认密码不能为空"})
def clean_user(self):
val=self.cleaned_data.get("user")
ret=UserInfo.objects.filter(user=val).first()
if not ret:
return val
else:
raise ValidationError("用户名已存在")
def clean_tel(self):
val=self.cleaned_data.get("tel")
ret=UserInfo.objects.filter(tel=val).first()
if not ret:
return val
else:
raise ValidationError("电话号码已注册")
def clean_email(self):
val=self.cleaned_data.get("email")
ret=UserInfo.objects.filter(email=val).first()
if not ret:
return val
else:
raise ValidationError("邮箱已注册")
def clean(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
def add(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")
def books(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})
def delbook(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))
def editbook(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"))
def register(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())
def login(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())
def get_valid_img(request):
from PIL import Image,ImageFont,ImageDraw
from io import BytesIO
def get_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 in range(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=40
for i in range(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 in range(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
BASE_DIR = Path(__file__).resolve(strict=True).parent.parent
SECRET_KEY = 'eje_%rl=ab5ibd@l8@ru!0+$9m*-#dlcnlw!$du@nq5@7ewlwl'
DEBUG = True
ALLOWED_HOSTS = []
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'
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME':'booksys',
'USER':'root',
'PASSWORD':'yf8629976',
'HOST':'127.0.0.1',
'PORT':3306
}
}
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',
},
]
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
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),
]
addbook.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<title>Title</title>
<style>
.container{
margin-top: 50px;
}
</style>
</head>
<body>
<div style="text-align: center;padding-bottom: 20px">
<h2>添加书籍</h2>
</div>
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<form>
{% csrf_token %}
<div class="form-group">
<label for="title">书籍名称</label>
<input type="text" class="form-control" id="title" placeholder="Title">
</div>
<div class="form-group">
<label for="price">价格</label>
<input type="text" class="form-control" id="price" placeholder="Price">
</div>
<div class="form-group">
<label for="pub_date">出版日期</label>
<input type="date" class="form-control" id="pub_date">
</div>
<div class="form-group">
<label for="publish">出版社</label>
<input type="text" class="form-control" id="publish" placeholder="Publish">
</div>
<button type="button" class="btn btn-success pull-right" id="submit">提交</button>
</form>
</div>
</div>
</div>
<script>
$("#submit").click(function () {
$.ajax({
type:"POST",
url:"/books/add/",
data:{
title:$("#title").val(),
price:$("#price").val(),
pub_date:$("#pub_date").val(),
publish:$("#publish").val(),
csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val()
},
success:function (response) {
var obj = JSON.parse(response);
if (obj.state) {
location.href="/books/"
}
}
})
})
</script>
</body>
</html>
editbook.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<title>Title</title>
<style>
.container{
margin-top: 50px;
}
</style>
</head>
<body>
<div style="text-align: center;padding-bottom: 20px">
<h2>编辑书籍</h2>
<p>共有<span style="color: red">33</span>条数据</p>
</div>
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<form action="/books/edit/{{ edit_book.id }}" method="post">
{% csrf_token %}
<div class="form-group">
<label for="title">书籍名称</label>
<input type="text" class="form-control" id="title" placeholder="" name="title" value={{ edit_book.title }}>
</div>
<div class="form-group">
<label for="price">价格</label>
<input type="text" class="form-control" id="price" placeholder="" name="price" value={{ edit_book.price }}>
</div>
<div class="form-group">
<label for="pub_date">出版日期</label>
<input type="date" class="form-control" id="pub_date" name="pub_date" value={{ edit_book.pub_date | date:"Y-m-d" }}>
</div>
<div class="form-group">
<label for="publish">出版社</label>
<input type="text" class="form-control" id="publish" placeholder="" name="publish" value={{ edit_book.publish }}>
</div>
<button type="submit" class="btn btn-success pull-right">提交</button>
</form>
</div>
</div>
</div>
</body>
</html>
books.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<title>Title</title>
</head>
<body>
<div style="text-align: center;padding-bottom: 20px">
<h2>查看书籍</h2>
<p>共有<span style="color: red">33</span>条数据</p>
</div>
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<a href="/books/add/" class="btn btn-primary">添加书籍</a>
{% csrf_token %}
<table class="table table-striped table-hover">
<thead>
<tr>
<th>编号</th>
<th>书籍名称</th>
<th>价格</th>
<th>出版日期</th>
<th>出版社</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for book in book_list %}
<tr>
<td>{{ book.id }}</td>
<td>{{ book.title }}</td>
<td>{{ book.price }}</td>
<td>{{ book.pub_date | date:"Y-m-d"}}</td>
<td>{{ book.publish }}</td>
<td>
<button class="btn btn-danger btn-sm btn-sm delbtn" bid="{{ book.id }}">删除</button>
<a href="/books/edit/{{ book.id }}" class="btn btn-warning btn-sm">编辑</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<nav style="text-align: center;">
<ul class="pagination" id="pager">
{% if book_list.has_previous %}
<li class="previous"><a href="/books/?page={{ book_list.previous_page_number }}">上一页</a></li>
{% else %}
<li class="previous disabled"><a href="#">上一页</a></li>
{% endif %}
{% for num in paginator.page_range %}
{% if num == currentPage %}
<li class="item active"><a href="/books/?page={{ num }}">{{ num }}</a></li>
{% else %}
<li class="item"><a href="/books/?page={{ num }}">{{ num }}</a></li>
{% endif %}
{% endfor %}
{% if book_list.has_next %}
<li class="next"><a href="/books/?page={{ book_list.next_page_number }}">下一页</a></li>
{% else %}
<li class="next disabled"><a href="#">下一页</a></li>
{% endif %}
</ul></nav>
</div>
</div>
</div>
<script>
$(".delbtn").click(function () {
var bid=$(this).attr("bid");
var ele=$(this).parent().parent();
if(window.confirm("你真的确定删除吗?")){
$.ajax({
url:"/books/delete/"+bid,
type:"post",
data:{
csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val()
},
success:function (response) {
var obj=JSON.parse(response);
if(obj.state){
ele.remove()
}
}
})
}
})
</script>
</body>
</html>
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<title>Title</title>
<style type="text/css">
#formdiv{
margin-top: 50px;
}
</style>
</head>
<body>
<h2 style="text-align: center;margin-top: 50px">用户登录</h2>
<div class="container">
<div class="row">
<div class="col-md-4 col-md-offset-4">
<form action="" method="post" id="formdiv" novalidate>
{% csrf_token %}
<div>
<label for="user">手机号</label>
<p><input type="text" name="name" id="name" class="form-control"></p>
</div>
<div>
<label for="pwd">密码</label>
<p><input type="password" name="pwd" id="pwd" class="form-control"></p>
</div>
<div class="form-group">
<label for="">验证码</label>
<div class="row">
<div class="col-xs-8">
<input type="text" class="form-control" id="validcode">
</div>
<div class="col-xs-4">
<img id="validimg" height="40px" width="100px" src="/get_valid_img/" alt="">
</div>
</div>
</div>
<button type="button" class="btn btn-success pull-right" id="login_btn">登录</button>
<a class="btn btn-success" href="/register/">注册</a>
<span class="error"></span>
<button type="reset" class="btn btn-success pull-right" style="margin-right: 20px">重置</button>
</form>
</div>
</div>
</div>
<!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
<script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
<!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
<script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script type="text/javascript">
$("#login_btn").click(function () {
$.ajax({
url:"",
type:"post",
data:{
user:$("#name").val(),
pwd:$("#pwd").val(),
validcode:$("#validcode").val(),
csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val(),
},
success:function (data) {
{# $.get("/get_valid_img/");#}
$("#validimg")[0].src+="?";
$("#validcode").val("")
if(data.user){
location.href="/"
}else {
$(".error").html(data.err_msg).css({"color":"red","margin-left":"20px"})
}
}
})
});
$("#validimg").click(function () {
this.src+="?";
})
</script>
</body>
</html>
register.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<title>用户注册</title>
<style type="text/css">
#regdiv{
margin-top: 50px;
}
</style>
</head>
<body>
<h2 style="text-align: center;margin-top: 50px">用户注册</h2>
<div class="container">
<div class="row">
<div class="col-md-4 col-md-offset-4">
<div id="regdiv">
{% csrf_token %}
{% for field in form %}
<div class="form-group">
<label for="">{{ field.label }}</label>
{{ field }}<span class="error" style="color: red">{{ field.errors.0 }}</span>
{% if field.label == "确认密码" %}
<span class="error" style="color: red">{{ clean_error.0 }}</span>
{% endif %}
</div>
{% endfor %}
<div class="form-group">
<label for="">验证码</label>
<div class="row">
<div class="col-xs-8">
<input type="text" class="form-control" id="validcode">
</div>
<div class="col-xs-4">
<img id="validimg" height="40px" width="100px" src="/get_valid_img/" alt="">
</div>
</div>
</div>
<button class="btn btn-success pull-right register_btn">注册</button>
<a class="btn btn-success" href="/login/">登录</a>
<button type="reset" class="btn btn-success pull-right" style="margin-right: 20px">重置</button>
</div>
</div>
</div>
</div>
<!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
<script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
<!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
<script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script>
$(".register_btn").click(function () {
$.ajax({
url:"",
type:"post",
data:{
tel:$("#id_tel").val(),
email:$("#id_email").val(),
username:$("#id_username").val(),
password:$("#id_password").val(),
r_pwd:$("#id_r_pwd").val(),
validcode:$("#validcode").val(),
csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val()
},
success:function (response) {
if(response.user){
location.href="/login";
}else {
$(".error").html("");
$(".form-group").removeClass("has-error");
$.each(response.err_msg,function (i,j) {
$("#id_"+i).next().html(j[0]).css("color","red").parent().addClass("has-error")
})
}
}
})
});
$("#validimg").click(function () {
this.src+="?";
})
</script>
</body>
</html>