需求
""" 1. 实现用户登录、注册 2. 列出图书列表、出版社列表、作者列表 3. 点击作者,会在新的页面列出该作者出版的图书列表 4. 点击出版社,会列出该出版社旗下图书列表 5. 可以创建、修改、删除 图书、作者、出版社 A. 点击修改书籍按钮,弹出模态框,模态框中展示该书的信息且信息可以修改, B. 书名不可重复,不可修改 C. 修改图书信息时,使用ajax请求发送信息 """
页面展示
项目目录结构(前端用到了jQuery/bootstrap/sweetalert)
app01文件夹
models.py
from django.db import models # Create your models here. """ Book 与Publish多对一;与Author多对多 Author Publish Book2Author """ class Publish(models.Model): """出版社名称和出版社邮箱两个字段是联合索引""" pid = models.AutoField( primary_key=True, verbose_name="主键", ) pub_name = models.CharField( max_length=32, verbose_name="出版社名称", ) pub_addr = models.CharField( max_length=64, verbose_name="出版社地址", ) pub_email = models.EmailField( verbose_name="出版社邮箱", ) class Meda: unique_together = (("pub_name", "pub_email"),) ordering = ['-id'] class Author(models.Model): """作者名字字段是唯一索引""" aid = models.AutoField( primary_key=True, verbose_name="主键", ) author_name = models.CharField( max_length=32, unique=True, verbose_name="作者名字", ) author_gender_choices = ( (1, "男"), (2, "女"), (3, "其他"), ) author_gender = models.IntegerField( choices=author_gender_choices, default=1, verbose_name="作者性别", ) class Book(models.Model): """书籍名称这个字段是唯一索引""" bid = models.AutoField( primary_key=True, verbose_name="主键", ) book_name = models.CharField( max_length=32, verbose_name="书籍名称", unique=True, ) book_price = models.DecimalField( max_digits=8, decimal_places=2, verbose_name="书籍价格", ) book_date = models.DateField( verbose_name="书籍出版日期", ) publish = models.ForeignKey(to="Publish", on_delete=models.CASCADE) authors = models.ManyToManyField(to="Author")
myforms.py
from django import forms from app01.models import * class Mylogin(forms.Form): """登录校验""" username = forms.CharField( label="账号", min_length=3, max_length=9, error_messages={ "required": "账号不能为空", "min_length": "账号不能小于3位", "max_length": "账号不能大于9位", }, widget=forms.widgets.TextInput(attrs={"class": "form-control"}), ) password = forms.CharField( label="密码", min_length=3, max_length=9, error_messages={ "required": "密码不能为空", "min_length": "密码不能小于3位", "max_length": "密码不能大于9位", }, widget=forms.widgets.PasswordInput(attrs={"class": "form-control"}), ) class Myreg(forms.Form): """注册校验""" username = forms.CharField( label="账号", min_length=3, max_length=9, error_messages={ "required": "账号不能为空", "min_length": "账号不能小于3位", "max_length": "账号不能大于9位", }, widget=forms.widgets.TextInput(attrs={"class": "form-control"}), ) password = forms.CharField( label="密码", min_length=3, max_length=9, error_messages={ "required": "密码不能为空", "min_length": "密码不能小于3位", "max_length": "密码不能大于9位", }, widget=forms.widgets.PasswordInput(attrs={"class": "form-control"}), ) confirm_password = forms.CharField( label="确认密码", min_length=3, max_length=9, error_messages={ "required": "确认密码不能为空", "min_length": "密码不能小于3位", "max_length": "密码不能大于9位", }, widget=forms.widgets.PasswordInput(attrs={"class": "form-control"}), ) user_email = forms.EmailField( label="邮箱", error_messages={ "invalid": "邮箱格式不正确", "required": "邮箱不能为空", }, widget=forms.widgets.EmailInput(attrs={"class": "form-control"}), ) def clean_user(self): """校验用户名是否包含特定字符""" username = self.cleaned_data.get("username") if "666" in username: self.add_error("username", "要自己666才行呀!!!") return username def clean(self): """校验密码和确认密码是否一致""" password = self.cleaned_data.get("password") confirm_password = self.cleaned_data.get("confirm_password") if not password == confirm_password: self.add_error("confirm_password", "两次密码不一致!!!") return self.cleaned_data class AddBook(forms.Form): """添加书籍校验""" book_name = forms.CharField( max_length=16, error_messages={ "required": "书名不能为空", "max_length": "书名不能大于16位", }, ) book_price = forms.FloatField( min_value=0.01, max_value=999999.99, error_messages={ "min_value": "最小价格不能小于0.01", "max_value": "最大价格不能大于999999.99", "required": "价格不能为空", }, ) def clean_book_name(self): """校验书名是否重复""" book_name = self.cleaned_data.get("book_name") book_obj = Book.objects.filter( book_name=book_name ).first() if book_obj: self.add_error("book_name", "书籍已存在,请重新输入...") return book_name class SetPassword(forms.Form): old_password = forms.CharField( label="原密码", min_length=3, max_length=9, error_messages={ "required": "原密码不能为空", "min_length": "密码不能小于3位", "max_length": "密码不能大于9位", }, widget=forms.widgets.PasswordInput(attrs={"class": "form-control"}), ) new_password = forms.CharField( label="新密码", min_length=3, max_length=9, error_messages={ "required": "新密码不能为空", "min_length": "新密码不能小于3位", "max_length": "新密码不能大于9位", }, widget=forms.widgets.PasswordInput(attrs={"class": "form-control"}), ) confirm_password = forms.CharField( label="确认密码", min_length=3, max_length=9, error_messages={ "required": "确认密码不能为空", "min_length": "确认密码不能小于3位", "max_length": "确认密码不能大于9位", }, widget=forms.widgets.PasswordInput(attrs={"class": "form-control"}), ) def clean(self): new_password = self.cleaned_data.get("new_password") confirm_password = self.cleaned_data.get("confirm_password") if not new_password == confirm_password: self.add_error("confirm_password", "两次密码不一致,请重新输入...") return self.cleaned_data
test.py
from django.test import TestCase # Create your tests here. import os if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "six_module_one_work.settings") import django django.setup() from app01.models import * # 创建初始系统账户admin # from django.contrib.auth.models import User # user = User.objects.create_superuser(username='admin', password='asd123123', email='123@qq.com') # 创建初始作者表 # author_list = [] # for i in range(1, 6): # author_obj = Author( # author_name='jack%s' % i, # author_gender=1, # ) # author_list.append(author_obj) # Author.objects.bulk_create(author_list) # 创建初始出版社表 # publish_list = [] # for i in range(1, 6): # publish_obj = Publish( # pub_name="北京出版社%s" % i, # pub_addr="北京市%s街道%s巷" % (i, i), # pub_email="%s%s%s@163.com" % (i, i, i), # ) # publish_list.append(publish_obj) # Publish.objects.bulk_create(publish_list) # 创建初始书籍表 # book_list = [] # for i in range(1, 251): # book_obj = Book( # book_name="python%s" % i, # book_price=i, # book_date="2021-02-02", # publish_id=1, # ) # book_list.append(book_obj) # Book.objects.bulk_create(book_list) # 创建作者书籍关系表 # for i in range(1, 126): # book_obj = Book.objects.filter(bid=i).first() # book_obj.authors.add(1, 3, 5) # for i in range(126, 251): # book_obj = Book.objects.filter(bid=i).first() # book_obj.authors.add(2, 4)
views.py
from django.shortcuts import render, HttpResponse, redirect, reverse from django.contrib import auth from app01.myforms import * from django.contrib.auth.decorators import login_required from django.contrib.auth.models import User from app01.models import * from django.core.paginator import Paginator, EmptyPage # Create your views here. FLAG = False def register(request): form_obj = Myreg() if request.method == "POST": form_obj = Myreg(request.POST) if form_obj.is_valid(): if not User.objects.filter(username=request.POST.get("username")).first(): User.objects.create_user( username=request.POST.get("username"), email=request.POST.get("user_email"), password=request.POST.get("password"), ) global FLAG FLAG = True return redirect("/login/") else: title = "swal('注册用户已存在...')" return render(request, "reg.html", locals()) def login(request): form_obj = Mylogin() global FLAG if FLAG: title = "swal('注册成功...')" else: title = "" target_url = request.GET.get("next", "/index/") if request.method == "POST": form_obj = Mylogin(request.POST) if form_obj.is_valid(): username = request.POST.get("username") password = request.POST.get("password") user = auth.authenticate( request, username=username, password=password, ) if user is not None: auth.login(request, user) return redirect(target_url) FLAG = False return render(request, "login.html", locals()) @login_required def index(request): authors = Author.objects.all().order_by("aid") publishs = Publish.objects.all().order_by("pid") book_obj = Book.objects.all().order_by("bid") paginator_obj = Paginator(book_obj, 10) page_num = int(request.GET.get("page", 1)) try: current_page = paginator_obj.page(page_num) except EmptyPage as e: current_page = paginator_obj.page(1) if paginator_obj.num_pages > 11: if page_num-5 < 1: page_range = range(1, 12) elif page_num+5 > paginator_obj.num_pages: page_range = range(paginator_obj.num_pages-10, paginator_obj.num_pages+1) else: page_range = range(page_num-5, page_num+6) else: page_range = range(1, paginator_obj.num_pages+1) return render(request, "index.html", locals()) @login_required def add_book(request): authors = Author.objects.all().order_by("aid") publishs = Publish.objects.all().order_by("pid") form_obj = AddBook() if request.method == "POST": form_obj = AddBook(request.POST) if form_obj.is_valid(): book_obj = Book.objects.create( book_name=request.POST.get("book_name"), book_price=request.POST.get("book_price"), book_date=request.POST.get("book_date"), publish_id=request.POST.get("publish_id"), ) author_list = request.POST.getlist("author_id") book_obj.authors.add(*author_list) return redirect("/index/") return render(request, "add_book.html", locals()) @login_required def delete_book(request, number, page): Book.objects.filter(bid=number).delete() book_obj = Book.objects.all().order_by("bid") paginator_obj = Paginator(book_obj, 10) if page not in paginator_obj.page_range: page -= 1 url = "/index/?page=%s" % page return HttpResponse(url) @login_required def edit_book(request, number, page): print(request.path_info) book_obj = Book.objects.filter(bid=number).first() if request.is_ajax(): Book.objects.filter(bid=number).update( book_price=request.POST.get("book_price"), book_date=request.POST.get("book_date"), publish_id=int(request.POST.get("publish_id")), ) authors_id = request.POST.getlist("authors_id[]") book_obj.authors.set(authors_id) url = "/index/?page=%s" % page return HttpResponse(url) @login_required def show_publish(request, number): publish_obj = Publish.objects.filter(pid=number).first() books_obj = Publish.objects.filter(pid=number).values_list( "book__book_name", "book__book_price", "book__book_date", ).order_by('pid') paginator_obj = Paginator(books_obj, 10) page_num = int(request.GET.get("page", 1)) try: current_page = paginator_obj.page(page_num) except EmptyPage as e: current_page = paginator_obj.page(1) if paginator_obj.num_pages > 11: if page_num-5 < 1: page_range = range(1, 12) elif page_num+5 > paginator_obj.num_pages: page_range = range(paginator_obj.num_pages-10, paginator_obj.num_pages+1) else: page_range = range(page_num-5, page_num+6) else: page_range = range(1, paginator_obj.num_pages+1) if request.method == "POST": Publish.objects.filter(pid=number).update( pub_name=request.POST.get("pub_name"), pub_addr=request.POST.get("pub_addr"), pub_email=request.POST.get("pub_email"), ) url = reverse("app01_show_publish", args=(number,)) return redirect(url) return render(request, "show_publish.html", locals()) @login_required def add_publish(request): if request.method == "POST": if request.POST.get("pub_name") and request.POST.get("pub_addr") and request.POST.get("pub_email"): publish_obj = Publish.objects.create( pub_name=request.POST.get("pub_name"), pub_addr=request.POST.get("pub_addr"), pub_email=request.POST.get("pub_email"), ) if publish_obj: return redirect("/index/") return render(request, "add_publish.html", locals()) @login_required def del_publish(request, name): Publish.objects.filter(pub_name=name).delete() return redirect("/index/") @login_required def show_author(request, number): author_obj = Author.objects.filter(aid=number).first() book_obj = Author.objects.filter(aid=number).values_list( "book__book_name", "book__book_price", "book__book_date", ).order_by('aid') paginator_obj = Paginator(book_obj, 10) page_num = int(request.GET.get("page", 1)) try: current_page = paginator_obj.page(page_num) except EmptyPage as e: current_page = paginator_obj.page(1) if paginator_obj.num_pages > 11: if page_num-5 < 1: page_range = range(1, 12) elif page_num+5 > paginator_obj.num_pages: page_range = range(paginator_obj.num_pages-10, paginator_obj.num_pages+1) else: page_range = range(page_num-5, page_num+6) else: page_range = range(1, paginator_obj.num_pages+1) if request.method == "POST": Author.objects.filter(aid=number).update( author_name=request.POST.get("author_name"), ) url = reverse("app01_show_author", args=(number,)) return redirect(url) return render(request, "show_author.html", locals()) @login_required def add_author(request): if request.method == "POST": if request.POST.get("author_name"): try: author_obj = Author.objects.create( author_name=request.POST.get("author_name"), ) if author_obj: return redirect("/index/") except Exception as e: title = "swal('该作者已存在...')" return render(request, "add_author.html", locals()) @login_required def del_author(request, name): Author.objects.filter(author_name=name).delete() return redirect("/index/") @login_required def logout(request): auth.logout(request) return redirect("/login/") @login_required def set_password(request): form_obj = SetPassword() user = request.user if request.method == "POST": form_obj = SetPassword(request.POST) if form_obj.is_valid(): old_password = request.POST.get("old_password") new_password = request.POST.get("new_password") confirm_password = request.POST.get("confirm_password") if user.check_password(old_password): user.set_password(new_password) user.save() return redirect("/login/") else: title = "swal('原密码输入错误...')" return render(request, "set_password.html", locals())
six_module_one_work文件夹
__init__.py
import pymysql pymysql.install_as_MySQLdb()
settings.py
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': '2021122101', 'HOST': '127.0.0.1', 'PORT': 3306, 'USER': 'root', 'PASSWORD': '123456', } } STATICFILES_DIRS = [ os.path.join(BASE_DIR, "static"), ] LOGIN_URL = "/login/"
urls.py
from django.contrib import admin from django.urls import path from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path("login/", views.login, name="app01_login"), path("reg/", views.register, name="app01_reg"), path("index/", views.index, name="app01_index"), path("add_book/", views.add_book, name="app01_add_book"), path("delete_book/<int:number>/<int:page>/", views.delete_book, name="app01_delete_book"), path("edit_book/<int:number>/<int:page>/", views.edit_book, name="app01_edit_book"), path("show_publish/<int:number>/", views.show_publish, name="app01_show_publish"), path("add_publish/", views.add_publish, name="app01_add_publish"), path("del_publish/<str:name>/", views.del_publish, name="app01_del_publish"), path("show_author/<int:number>/", views.show_author, name="app01_show_author"), path("add_author/", views.add_author, name="app01_add_author"), path("del_author/<str:name>/", views.del_author, name="app01_del_author"), path("logout/", views.logout, name="app01_logout"), path("set_password/", views.set_password, name="app01_set_password"), path("", views.login), ]
templates文件夹
add_author.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> {% load static %} <script src="{% static 'jQuery3.6.js' %}"></script> <link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}"> <script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"></script> <link rel="stylesheet" href="{% static 'sweetalert/sweetalert.css' %}"> <script src="{% static 'sweetalert/sweetalert.min.js' %}"></script> </head> <body> <div class="container"> <div class="row"> <div class="col-md-6 col-md-offset-3"> <h3>添加作者</h3> <a href="{% url 'app01_index' %}" class="pull-right"><button class="btn btn-primary">首页</button></a> <br><br> <form action="" method="post"> {% csrf_token %} <p> 作者姓名: <input type="text" name="author_name" class="form-control"> </p> <p> <input type="submit" class="btn btn-block btn-info"> </p> </form> </div> </div> </div> <script> {{ title|safe }} </script> </body> </html>
add_book.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> {% load static %} <script src="{% static 'jQuery3.6.js' %}"></script> <link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}"> <script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"></script> </head> <body> <div class="container"> <div class="row"> <div class="col-md-6 col-md-offset-3"> <h3 class="text-center">添加书籍</h3> <a href="{% url 'app01_index' %}" class="pull-right"><button class="btn btn-primary">首页</button></a> <br><br> <form action="" method="post" novalidate> {% csrf_token %} <p> 书籍名称: <input type="text" name="book_name" class="form-control"> <span style="color: red">{{ form_obj.book_name.errors.0 }}</span> </p> <p> 书籍价格: <input type="text" name="book_price" class="form-control"> <span style="color: red">{{ form_obj.book_price.errors.0 }}</span> </p> <p> 出版日期: <input type="date" name="book_date" class="form-control"> </p> <p> 出版社: <select name="publish_id" id="" class="form-control"> {% for publish in publishs %} <option value="{{ publish.pk }}">{{ publish.pub_name }}</option> {% endfor %} </select> </p> <p> 作者: <select name="author_id" id="" class="form-control" multiple> {% for author in authors %} <option value="{{ author.pk }}">{{ author.author_name }}</option> {% endfor %} </select> </p> <input type="submit" value="添加" class="btn btn-success btn-block"> </form> </div> </div> </div> </body> </html>
add_publish.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> {% load static %} <script src="{% static 'jQuery3.6.js' %}"></script> <link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}"> <script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"></script> </head> <body> <div class="container"> <div class="row"> <div class="col-md-6 col-md-offset-3"> <h3>添加出版社</h3> <a href="{% url 'app01_index' %}" class="pull-right"><button class="btn btn-primary">首页</button></a> <br><br> <form action="" method="post"> {% csrf_token %} <p> 出版社名称: <input type="text" name="pub_name" class="form-control"> </p> <p> 出版社地址: <input type="text" name="pub_addr" class="form-control"> </p> <p> 出版社邮箱: <input type="text" name="pub_email" class="form-control"> </p> <p> <input type="submit" value="添加" class="btn btn-info btn-block"> </p> </form> </div> </div> </div> </body> </html>
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> {% load static %} <script src="{% static 'jQuery3.6.js' %}"></script> <link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}"> <script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"></script> <link rel="stylesheet" href="{% static 'sweetalert/sweetalert.css' %}"> <script src="{% static 'sweetalert/sweetalert.min.js' %}"></script> </head> <body> <div class="container"> <div class="row"> <nav class="navbar navbar-inverse"> <div class="container-fluid"> <!-- Brand and toggle get grouped for better mobile display --> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">Brand</a> </div> <!-- Collect the nav links, forms, and other content for toggling --> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav"> <li class="active"><a href="#">Link <span class="sr-only">(current)</span></a></li> <li><a href="#">Link</a></li> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a> <ul class="dropdown-menu"> <li><a href="#">Action</a></li> <li><a href="#">Another action</a></li> <li><a href="#">Something else here</a></li> <li role="separator" class="divider"></li> <li><a href="#">Separated link</a></li> <li role="separator" class="divider"></li> <li><a href="#">One more separated link</a></li> </ul> </li> </ul> <form class="navbar-form navbar-left"> <div class="form-group"> <input type="text" class="form-control" placeholder="Search"> </div> <button type="submit" class="btn btn-default">Submit</button> </form> <ul class="nav navbar-nav navbar-right"> <li><a href="#">Link</a></li> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a> <ul class="dropdown-menu"> <li><a href="#">Action</a></li> <li><a href="#">Another action</a></li> <li><a href="#">Something else here</a></li> <li role="separator" class="divider"></li> <li><a href="#">Separated link</a></li> </ul> </li> </ul> </div><!-- /.navbar-collapse --> </div><!-- /.container-fluid --> </nav> <div class="row"> <a href="{% url 'app01_logout' %}"> <button class="btn btn-danger pull-left">退出</button> </a> <a href="{% url 'app01_set_password' %}"> <button class="btn btn-success">修改密码</button> </a> <a href="{% url 'app01_add_book' %}"> <button class="btn btn-primary pull-right">添加书籍</button> </a> <br><br><br> <table class="table table-bordered table-striped table-condensed"> <thead> <tr> <th class="text-center">序号</th> <th class="text-center">书籍名称</th> <th class="text-center">书籍价格</th> <th class="text-center">出版日期</th> <th class="text-center">出版社</th> <th class="text-center">作者</th> <th class="text-center">操作</th> </tr> </thead> <tbody> {% for book in current_page %} <tr class="text-center"> <td> {% if forloop.first %} {{ current_page.start_index }} {% else %} {{ current_page.start_index|add:forloop.counter0 }} {% endif %} </td> <td>{{ book.book_name }}</td> <td>{{ book.book_price }}</td> <td>{{ book.book_date|date:'Y-m-d' }}</td> <td><a href="{% url 'app01_show_publish' book.publish.pid %}">{{ book.publish.pub_name }}</a></td> <td> {% for author in book.authors.all %} {% if forloop.last %} <a href="{% url 'app01_show_author' author.aid %}" target="_blank">{{ author.author_name }}</a> {% else %} <a href="{% url 'app01_show_author' author.aid %}" target="_blank">{{ author.author_name }},</a> {% endif %} {% endfor %} </td> <td> <button class="btn btn-danger btn-xs b2" number_01="{{ book.pk }}" >编辑</button> <button class="btn btn-warning btn-xs b1" number={{ book.pk }}>删除</button> </td> </tr> {% endfor %} <select name="" id="i6" style="display: none"> {% for publish in publishs %} <option value={{ publish.pid }}>{{ publish.pub_name }}</option> {% endfor %} </select> <select name="" id="i7" style="display: none" multiple> {% for author in authors %} <option value={{ author.pk }}>{{ author.author_name }}</option> {% endfor %} </select> </tbody> </table> <nav aria-label="Page navigation" class="text-center"> <ul class="pagination"> <li> <a href="?page=1" aria-label="Previous"> <span aria-hidden="true">首页</span> </a> </li> {% if current_page.has_previous %} <li> <a href="?page={{ current_page.previous_page_number }}" aria-label="Previous"> <span aria-hidden="true">«</span> </a> </li> {% else %} <li class="disabled"> <span aria-hidden="true">«</span> </li> {% endif %} {% for page in page_range %} {% if page == page_num %} <li class="active"><a href="?page={{ page }}">{{ page }}</a></li> {% else %} <li><a href="?page={{ page }}">{{ page }}</a></li> {% endif %} {% endfor %} {% if current_page.has_next %} <li> <a href="?page={{ current_page.next_page_number }}" aria-label="Next"> <span aria-hidden="true">»</span> </a> </li> {% else %} <li class="disabled"> <span aria-hidden="true">»</span> </li> {% endif %} <li> <a href="?page={{ paginator_obj.num_pages }}" aria-label="Previous"> <span aria-hidden="true">尾页</span> </a> </li> </ul> </nav> <!-- Modal --> <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> <h4 class="modal-title" id="myModalLabel">编辑书籍</h4> </div> <div class="modal-body"> <p> 书籍名称: <input type="text" name="book_name" class="form-control" id="i1" disabled> </p> <p> 书籍价格: <input type="text" name="book_price" class="form-control" id="i2"> </p> <p> 出版日期: <input type="date" name="book_date" class="form-control" id="i3"> </p> <p> 出版社: <select name="publish_id" id="i4" class="form-control"> </select> </p> <p> 作者: <select name="authors_id" id="i5" class="form-control" multiple> </select> </p> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">取消</button> <button type="button" class="btn btn-primary b3">保存</button> </div> </div> </div> </div> </div> </div> </div> <script> $(".b1").click(function () { let number = $(this).attr("number"); swal({ title: "确定要删除吗?", text: "删除后书籍就没有了!", type: "warning", showCancelButton: true, confirmButtonClass: "btn-danger", confirmButtonText: "确定!", cancelButtonText: "取消!", closeOnConfirm: false, closeOnCancel: false }, function (isConfirm) { if (isConfirm) { $.ajax({ url: '/delete_book/' + number + '/{{ page_num }}/', type: "post", data: {'csrfmiddlewaretoken': '{{ csrf_token }}'}, success: function (data) { setTimeout(function () { location.href = data; }, 3000); } }); swal("Deleted!", "您已成功删除该书籍", "success"); } else { swal("Cancelled", "您已取消删除该书籍", "error"); } }) }) $(".b2").click(function () { $('#myModal').modal('show'); let value1 = $(this).parentsUntil("tbody").children('td').eq(1).html(); let value2 = $(this).parentsUntil("tbody").children('td').eq(2).html(); let value3 = $(this).parentsUntil("tbody").children('td').eq(3).html(); let value_10 = $(this).parentsUntil("tbody").children("td").eq(4).children('a').html(); let value_11 = $(this).parentsUntil("tbody").children("td").eq(5).children("a"); $("#i1").val(value1); $("#i2").val(value2); $("#i3").val(value3); let value4 = $("#i6").children(); $(value4).each(function () { $("#i4").append($(this)); }) $("#i4").children().each(function () { if ($(this).html() === value_10) { $(this).prop("selected", true); } }) let value5 = $("#i7").children(); $(value5).each(function () { $("#i5").append($(this)); }) let array = new Array(); $(value_11).each(function () { let ss = $(this).html().split(',')[0]; array.push(ss); }) $.each(array, function (index, value) { $("#i5").children("option").each(function () { if ($(this).html() === value) { $(this).prop("selected", true); } }) }) let number = $(this).attr("number_01"); $(".b3").attr("number_02", number); }) $(".b3").click(function () { let book_name = $("#i1").val(); let book_price = $("#i2").val(); let book_date = $("#i3").val(); let publish_id = $("#i4").val(); let authors_id = $("#i5").val(); let number = $(this).attr("number_02"); $.ajax({ url: '/edit_book/' + number + '/{{ page_num }}/', type: "post", data: { 'csrfmiddlewaretoken': '{{ csrf_token }}', 'book_name': book_name, 'book_price': book_price, 'book_date': book_date, 'publish_id': publish_id, 'authors_id': authors_id, }, success: function (data) { setTimeout(function () { {#location.href = data;#} window.location.reload(); }, 2000); } }) swal("modify successfully!", "您已成功修改该书籍", "success"); $('#myModal').modal('hide'); }) </script> </body> </html>
login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> {% load static %} <script src="{% static 'jQuery3.6.js' %}"></script> <link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}"> <script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"></script> <link rel="stylesheet" href="{% static 'sweetalert/sweetalert.css' %}"> <script src="{% static 'sweetalert/sweetalert.min.js' %}"></script> </head> <body> <div class="container"> <div class="row"> <div class="col-md-6 col-md-offset-3"> <h3 class="text-center text-danger">登录</h3> <form action="" method="post" novalidate> {% csrf_token %} {% for form in form_obj %} <p> {{ form.label }}: {{ form }} <span style="color: red">{{ form.errors.0 }}</span> </p> {% endfor %} <input type="submit" value="登录" class="btn btn-block btn-primary"> </form> <p class="pull-right"> <span class="text-danger">没有账号?</span> <a href="{% url 'app01_reg' %}">点击注册</a> </p> </div> </div> </div> <script>{{ title|safe }}</script> </body> </html>
reg.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> {% load static %} <script src="{% static 'jQuery3.6.js' %}"></script> <link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}"> <script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"></script> <link rel="stylesheet" href="{% static 'sweetalert/sweetalert.css' %}"> <script src="{% static 'sweetalert/sweetalert.min.js' %}"></script> </head> <body> <div class="container"> <div class="row"> <div class="col-md-6 col-md-offset-3"> <h3 class="text-center text-warning">注册</h3> <form action="" method="post" novalidate> {% csrf_token %} {% for form in form_obj %} <p> {{ form.label }}: {{ form }} <span style="color: red">{{ form.errors.0 }}</span> </p> {% endfor %} <input type="submit" value="注册" class="btn btn-primary btn-block"> </form> <p class="pull-right"> <span class="text-danger">已有账号?</span> <a href="{% url 'app01_login' %}">点击登录</a> </p> </div> </div> </div> <script>{{ title|safe }}</script> </body> </html>
set_password.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> {% load static %} <script src="{% static 'jQuery3.6.js' %}"></script> <link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}"> <script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"></script> <link rel="stylesheet" href="{% static 'sweetalert/sweetalert.css' %}"> <script src="{% static 'sweetalert/sweetalert.min.js' %}"></script> </head> <body> <div class="container"> <div class="row"> <div class="col-md-6 col-md-offset-3"> <h3 class="text-danger text-center">修改密码</h3> <a href="{% url 'app01_index' %}"> <button class="btn btn-primary pull-right">首页</button> </a> <br><br> <form action="" method="post" novalidate> {% csrf_token %} {% for form in form_obj %} <p> {{ form.label }}: {{ form }} <span style="color: red">{{ form.errors.0 }}</span> </p> {% endfor %} <p> <input type="submit" class="btn btn-success btn-block"> </p> </form> </div> </div> </div> <script> {{ title|safe }} </script> </body> </html>
show_author.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> {% load static %} <script src="{% static 'jQuery3.6.js' %}"></script> <link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}"> <script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"></script> </head> <body> <div class="container"> <div class="row"> <div class="col-md-6 col-md-offset-3"> <h3 class="text-center">作者信息及所出版书籍</h3> <a href="{% url 'app01_index' %}" class="pull-right"><button class="btn btn-primary">首页</button></a> <a href="{% url 'app01_add_author' %}" class="pull-left"><button class="btn btn-danger">添加作者</button></a> <a href="{% url 'app01_del_author' author_obj.author_name %}"><button class="btn btn-warning">删除作者</button></a> <form action="" method="post"> {% csrf_token %} <br><br> <p> 作者姓名: <input type="text" name="author_name" class="form-control" value="{{ author_obj.author_name }}"> </p> <p> <input type="submit" value="更改" class="btn btn-block btn-info"> </p> </form> <table class="table table-bordered table-hover table-condensed"> <thead> <tr> <th class="text-center">书籍名称</th> <th class="text-center">书籍价格</th> <th class="text-center">出版日期</th> </tr> </thead> <tbody> {% for book in current_page %} <tr class="text-center"> <td>{{ book.0 }}</td> <td>{{ book.1 }}</td> <td>{{ book.2|date:'Y-m-d' }}</td> </tr> {% endfor %} </tbody> </table> <nav aria-label="Page navigation" class="text-center"> <ul class="pagination"> {% if current_page.has_previous %} <li> <a href="?page={{ current_page.previous_page_number }}" aria-label="Previous"> <span aria-hidden="true">«</span> </a> </li> {% else %} <li class="disabled"> <span aria-hidden="true">«</span> </li> {% endif %} {% for page in page_range %} {% if page == page_num %} <li class="active"><a href="?page={{ page }}">{{ page }}</a></li> {% else %} <li><a href="?page={{ page }}">{{ page }}</a></li> {% endif %} {% endfor %} {% if current_page.has_next %} <li> <a href="?page={{ current_page.next_page_number }}" aria-label="Next"> <span aria-hidden="true">»</span> </a> </li> {% else %} <li class="disabled"> <span aria-hidden="true">»</span> </li> {% endif %} </ul> </nav> </div> </div> </div> </body> </html>
show_publish.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> {% load static %} <script src="{% static 'jQuery3.6.js' %}"></script> <link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}"> <script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"></script> </head> <body> <div class="container"> <div class="row"> <div class="col-md-6 col-md-offset-3"> <h3 class="text-center">出版社信息及所出版书籍</h3> <a href="{% url 'app01_index' %}" class="pull-right"><button class="btn btn-primary">首页</button></a> <a href="{% url 'app01_add_publish' %}" class="pull-left"><button class="btn btn-danger">添加出版社</button></a> <a href="{% url 'app01_del_publish' publish_obj.pub_name %}"><button class="btn btn-warning">删除出版社</button></a> <form action="" method="post"> {% csrf_token %} <br><br> <p> 出版社名称: <input type="text" name="pub_name" value="{{ publish_obj.pub_name }}" class="form-control"> </p> <p> 出版社地址: <input type="text" name="pub_addr" value="{{ publish_obj.pub_addr }}" class="form-control"> </p> <p> 出版社邮箱: <input type="text" name="pub_email" value="{{ publish_obj.pub_email }}" class="form-control"> </p> <p> <input type="submit" value="更改" class="btn btn-block btn-info"> </p> </form> <table class="table table-bordered table-hover table-condensed"> <thead> <tr> <th class="text-center">书籍名称</th> <th class="text-center">书籍价格</th> <th class="text-center">出版日期</th> </tr> </thead> <tbody> {% for book in current_page %} <tr class="text-center"> <td>{{ book.0 }}</td> <td>{{ book.1 }}</td> <td>{{ book.2|date:'Y-m-d' }}</td> </tr> {% endfor %} </tbody> </table> <nav aria-label="Page navigation" class="text-center"> <ul class="pagination"> {% if current_page.has_previous %} <li> <a href="?page={{ current_page.previous_page_number }}" aria-label="Previous"> <span aria-hidden="true">«</span> </a> </li> {% else %} <li class="disabled"> <span aria-hidden="true">«</span> </li> {% endif %} {% for page in page_range %} {% if page == page_num %} <li class="active"><a href="?page={{ page }}">{{ page }}</a></li> {% else %} <li><a href="?page={{ page }}">{{ page }}</a></li> {% endif %} {% endfor %} {% if current_page.has_next %} <li> <a href="?page={{ current_page.next_page_number }}" aria-label="Next"> <span aria-hidden="true">»</span> </a> </li> {% else %} <li class="disabled"> <span aria-hidden="true">»</span> </li> {% endif %} </ul> </nav> </div> </div> </div> </body> </html>
README.txt
""" 环境配置: Django版本:2.0.1 MySQL版本:5.7.35 MySQL准备数据库:'2021122101' MySQL链接用户名及密码:'root'/'123456' 系统初始化数据: 运行app01.tests.py中注释的代码即可 初始化数据有系统初始登录账号及密码,作者/出版社/书籍/作者书籍关系这几张表数据 功能: 项目启动后,首先进入登录页面,登录页面与注册页面各有a标签链接进行交互切换,注册成功后自动跳转到登陆页面; 首页展示了书籍列表,可以对书籍进行添加、编辑、删除操作;出版社及作者均可进行点击查看,跳转到对应页面查看信息; 点击出版社,页面会展示该出版社所出版的所有书籍,还可对出版社进行添加、编辑、删除操作; 点击作者,弹出新页面,该页面展示该作者所关联的书籍信息,还可对作者进行添加、编辑、删除操作; 首页点击退出,即退出登录回到登录页面; 修改书籍信息,弹出模态框,模态框回显该书籍信息,且书籍名称不可编辑,点击模态框保存按钮发送Ajax请求; 添加书籍信息,书籍名称不能重复; 删除书籍,均有二次确认操作; """
如何一次性将项目所依赖的三方库版本信息导入及导出?
""" pycharm中的命令行输入如下命令即可: 生成requirements.txt文件:pip freeze > requirements.txt 安装requirements.txt依赖:pip install -r requirements.txt """
""" requirements.txt导出信息展示 certifi==2021.5.30 charset-normalizer==2.0.4 click==8.0.1 colorama==0.4.4 DBUtils==2.0.2 decorator==4.4.2 Django==2.0.1 et-xmlfile==1.1.0 Flask==2.0.1 idna==3.2 imageio==2.9.0 imageio-ffmpeg==0.4.5 itsdangerous==2.0.1 Jinja2==3.0.1 MarkupSafe==2.0.1 moviepy==1.0.3 numpy==1.21.2 openpyxl==3.0.7 Pillow==8.3.2 prettytable==2.2.0 proglog==0.1.9 PyMySQL==1.0.2 pytz==2021.3 requests==2.26.0 tqdm==4.62.2 urllib3==1.26.6 wcwidth==0.2.5 Werkzeug==2.0.1 """
该程序已发现的小BUG
""" 编辑书籍信息的模态框,选择作者是多选的下拉框,没有给模态框的取消按钮绑定点击事件,所以当重新选择了作者后点击取消按钮,此时再次点击书籍编辑按钮弹出模态框时,作者的默认选中标签信息与书籍的作者信息不相符。 解决方案:给模态框的取消按钮及右上角关闭按钮都绑定同一个事件,即把作者的多选下拉框的子标签option标签的默认选中属性都取消? """