用Django制作一个简单的图书管理软件,包含作者管理、出版社管理、图书管理三个功能。
# 开发环境
Python:3.80
Django:3.0.2
Pycharm:2019
创建项目(my_books)
创建APP
为了增强项目的可读性,我们将分别创建作者管理(author)、出版社管理(publish)、图书管理(book)三个APP。这里我们使用一个小技巧,创建一个apps目录,把所有APP应用都安装到这里,便于管理。
然后apps目录上右键选择:Mark Directory as --> Sources Root
setting.py中添加以下代码:
# setting.py
import sys
sys.path.insert(0,os.path.join(BASE_DIR,'apps'))
# 使用pycharm创建APP
python manage.py startapp author # 创建作者应用
python manage.py startapp publish # 创建出版社应用
python manage.py startapp book # 创建图书应用
创建好的APP拖动到apps文件夹下(弹出对话框,取消勾选Search for references)
settings.py文件中找到INSTALLED_APPS并新增以下代码:
# settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# 下面三个是新增的
'author',
'publish',
'book',
]
URL路由
my_books目录下的urls.py为总路由引用(author、publish、book)下的urls.py文件。
# my_books下的urls.py
from django.contrib import admin
from django.urls import path,include
urlpatterns = [
path('admin/', admin.site.urls), # 后台管理
path('author/',include('author.urls')), # 作者管理
path('publish/',include('publish.urls')), # 出版社管理
path('book/',include('book.urls')), # 图书管理
]
然后在每个APP下面单独创建urls.py文件
前端模板(Template)
在templates目录下创建前端静态模板,用来接收或传递后端数据,base.html为父级文件。
显示所有作者:author_list.html、新增作者:author_add.html、修改作者:author_edit.html
显示所有出版社:publish_list.html、新增出版社:publish_add.html、编辑出版社:publish_edit.html
显示所有图书:book_list.html、新增图书:book_add.html、编辑图书:book_edit.html
# base.html 父级模板,其他模板将继承base.html
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8" />
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimal-ui">
{% block title %}<title>父级模板</title>{% endblock %}
{% block keywords %}<meta name="keywords" content="" />{% endblock %}
{% block description %}<meta name="description" content="" />{% endblock %}
{% block css %}<link rel="stylesheet" type="text/css" href="/images/css/common.css" />{% endblock %}
</head>
<body>
{% block nav %}
<nav>
<div class="container">
<ul>
<li><a href="{% url 'book' %}"><i></i>主页</a></li>
<li><a href="{% url 'book' %}"><i></i>图书管理</a></li>
<li><a href="{% url 'author' %}"><i></i>作者管理</a></li>
<li><a href="{% url 'publish' %}"><i></i>出版社管理</a></li>
</ul>
</div>
</nav>
{% endblock %}
<main>
{% block content %}{% endblock %}
</main>
{% block footer %}
<footer>
<p>简单的图书管理系统,适合初学者作为项目练习,请勿用于实际生产</p>
<p><span>技术支持:<a href="">极禾科技</a></span></p>
</footer>
{% endblock %}
</body>
</html>
作者管理功能
数据模型(Model):
# author目录下的models.py
from django.db import models
class Author(models.Model):
"""图书作者模型"""
name = models.CharField('作者',max_length=32)
mobile = models.CharField('电话',max_length=32)
class Meta:
verbose_name = '作者'
verbose_name_plural = '图书作者'
def __str__(self):
return self.name
执行数据迁移:
# pycharm中依次执行下列命令
python manage.py makemigrations
python manage.py migrate
编写视图函数(View):
# author目录下的views.py
from django.shortcuts import render,redirect
from author.models import Author
def author_list(request):
"""作者管理"""
authors = Author.objects.all()
context = {
'authors':authors,
}
return render(request,'author_list.html',context)
def author_add(request):
"""新增作者"""
if request.method == 'POST':
name = request.POST.get('name')
mobile = request.POST.get('mobile')
try:
Author.objects.create(name=name,mobile=mobile)
return redirect('/author/')
except:
error = '数据出错'
return render(request,'author_add.html')
def author_edit(request,author_id):
"""修改作者"""
authors = None
if request.method == 'POST':
name = request.POST.get('name')
mobile = request.POST.get('mobile')
# 第一种方式
# authors.name = name
# authors.mobile = mobile
# authors.save()
# 第二种方式
try:
Author.objects.filter(pk=author_id).update(name=name,mobile=mobile)
return redirect('/author/')
except:
error = '修改失败'
else:
authors = Author.objects.get(pk=author_id)
context = {
'authors':authors,
}
return render(request,'author_edit.html',context)
def author_del(request,author_id):
"""删除作者"""
author_list_del = Author.objects.filter(id=author_id).filter()
if author_list_del:
try:
author_list_del.delete()
return redirect('/author/')
except:
error = '删除失败'
else:
error = '作者删除失败'
context = {
'error':error,
}
return render(request, 'author_list.html', context)
作者APP路由设置:
# author目录下的urls.py
from django.urls import path
from author import views
urlpatterns = [
path('',views.author_list,name='author'), # 作者管理
path('add/',views.author_add,name='author_add'), # 新增作者
path('edit/<int:author_id>',views.author_edit,name='author_edit'), # 修改作者
path('del/<int:author_id>',views.author_del,name='author_del'), # 删除作者
]
模板文件(Template):
# author_list.html
{% extends 'base.html' %}
{% block title %}<title>作者管理</title>{% endblock %}
<main>
{% block content %}
<div class="search">
<form action="" method="POST">
<input type="text" name="search_text" placeholder="请出入搜索关键字">
<button type="submit" class="search_btn">搜索</button>
</form>
<div class="add_btn">
<a href="{% url 'author' %}add/">新增</a>
</div>
</div>
<table>
<thead>
<tr>
<th>编号</th>
<th>作者</th>
<th>电话</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for author in authors %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ author.name }}</td>
<td>{{ author.mobile }}</td>
<td><a href="{% url 'author' %}edit/{{ author.id }}">修改</a><a href="{% url 'author' %}del/{{ author.id }}">删除</a></td>
</tr>
{% empty %}
<tr><td>没有作者</td></tr>
{% endfor %}
</tbody>
</table>
{% if error %}
<div class="error">{{ error }}</div>
{% endif %}
{% endblock %}
</main>
# author_add.htm
{% extends 'base.html' %}
{% block title %}<title>新增作者</title>{% endblock %}
<main>
{% block content %}
<form class="form1" action="" method="post">
<h2>新增作者</h2>
{% csrf_token %}
<p><input type="text" name="name" id="name" placeholder="姓名" autocomplete="off"><label for="name">请输入作者名字</label></p>
<p><input type="text" name="mobile" id="mobile" placeholder="电话"><label for="mobile">请输入作者电话</label></p>
<div class="button">
<button type="submit" class="btn_save">保存</button>
<a href="" class="btn_cancel">取消</a>
</div>
</form>
{% endblock %}
</main>
# author_edit.html
{% extends 'base.html' %}
{% block title %}<title>修改作者</title>{% endblock %}
<main>
{% block content %}
<form class="form1" action="" method="post">
<h2>修改作者</h2>
{% csrf_token %}
<p><input type="text" name="name" id="name" placeholder="姓名" autocomplete="off" value="{{ authors.name }}"><label for="name">请输入作者名字</label></p>
<p><input type="text" name="mobile" id="mobile" placeholder="电话" value="{{ authors.mobile }}"><label for="mobile">请输入作者电话</label></p>
<div class="button">
<button type="submit" class="btn_save">保存</button>
<a href="" class="btn_cancel">取消</a>
</div>
</form>
{% endblock %}
</main>
出版社管理功能
数据模型(Model):
# publish目录下的models.py
from django.db import models
class Publish(models.Model):
"""出版社模型"""
name = models.CharField('出版社',max_length=32)
mobile = models.CharField('电话',max_length=32)
city = models.CharField('城市',max_length=32)
def __str__(self):
return self.name
执行数据迁移:
# pycharm中依次执行下列命令
python manage.py makemigrations
python manage.py migrate
编写视图函数(View):
# publish目录下的views.py
from django.shortcuts import render,redirect
from publish.models import Publish
def publish_list(request):
"""出版社管理"""
publish_all = Publish.objects.all()
context = {
'publish_all':publish_all,
}
return render(request,'publish_list.html',context)
def publish_add(request):
"""新增出版社"""
if request.method == 'POST':
name = request.POST.get('name')
city = request.POST.get('city')
try:
Publish.objects.create(name=name,city=city)
return redirect('/publish/')
except:
error = '新增出版社失败'
return render(request,'publish_add.html')
def publish_edit(request,publish_id):
"""修改出版社"""
publish_edit_id = None
if request.method == 'POST':
name = request.POST.get('name')
city = request.POST.get('city')
try:
Publish.objects.filter(id=publish_id).update(name=name,city=city)
return redirect('/publish/')
except:
error = '修改失败'
else:
publish_edit_id = Publish.objects.filter(id=publish_id).first()
context = {
'publish_edit_id':publish_edit_id,
}
return render(request,'publish_edit.html',context)
def publish_del(request,publish_id):
"""删除出版社"""
publish_del_list = Publish.objects.filter(id=publish_id).first()
if publish_del_list:
try:
publish_del_list.delete()
return redirect('/publish/')
except:
error = '删除失败'
else:
error = '删除失败'
context = {
'error':error,
}
return render(request, 'publish_list.html', context)
出版社管理路由设置:
# publish目录下的urls.py
from django.urls import path
from publish import views
urlpatterns = [
path('',views.publish_list,name='publish'), # 出版社管理
path('add/',views.publish_add,name='publish_add'), # 新增出版社
path('edit/<int:publish_id>',views.publish_edit,name='publish_edit'), # 修改出版社
path('del/<int:publish_id>',views.publish_del,name='publish_del'), # 删除出版社
]
模板文件(Template):
# publist_list.html
{% extends 'base.html' %}
{% block title %}<title>出版社管理</title>{% endblock %}
<main>
{% block content %}
<div class="search">
<form accept="" method="POST">
<input type="text" name="search_text" placeholder="请出入搜索关键字">
<button type="submit" class="search_btn">搜索</button>
</form>
<div class="add_btn">
<a href="{% url 'publish_add' %}">新增</a>
</div>
</div>
<table>
<thead>
<tr>
<th>编号</th>
<th>出版社</th>
<th>城市</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for publish in publish_all %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ publish.name }}</td>
<td>{{ publish.city }}</td>
<td><a href="{% url 'publish' %}edit/{{ publish.id }}">修改</a><a href="{% url 'publish' %}del/{{ publish.id }}">删除</a></td>
</tr>
{% empty %}
<tr><td>没有出版社</td></tr>
{% endfor %}
</tbody>
</table>
{% if error %}
<div class="error">{{ error }}</div>
{% endif %}
{% endblock %}
</main>
# publist_add.html
{% extends 'base.html' %}
{% block title %}<title>新增出版社</title>{% endblock %}
<main>
{% block content %}
<form class="form1" action="" method="post">
<h2>新增出版社</h2>
{% csrf_token %}
<p><input type="text" name="name" id="name" placeholder="出版社" autocomplete="off"><label for="name">请输入出版社名称</label></p>
<p><input type="text" name="city" id="city" placeholder="城市" autocomplete="off"><label for="city">请输入城市</label></p>
<div class="button">
<button type="submit" class="btn_save">保存</button>
<a href="" class="btn_cancel">取消</a>
</div>
</form>
{% endblock %}
</main>
# publist_edit.html
{% extends 'base.html' %}
{% block title %}<title>修改出版社</title>{% endblock %}
<main>
{% block content %}
<form class="form1" action="" method="post">
<h2>修改出版社</h2>
{% csrf_token %}
<p><input type="text" name="name" id="name" placeholder="出版社" autocomplete="off" value="{{ publish_edit_id.name }}"><label for="name">请输入出版社名称</label></p>
<p><input type="text" name="city" id="city" placeholder="城市" autocomplete="off" value="{{ publish_edit_id.city }}"><label for="city">请输入城市</label></p>
<div class="button">
<button type="submit" class="btn_save">保存</button>
<a href="" class="btn_cancel">取消</a>
</div>
</form>
{% endblock %}
</main>
图书管理功能
数据模型(Model):
# book目录下的models.py
from django.db import models
from author.models import Author
from publish.models import Publish
class Book(models.Model):
"""图书模型"""
title = models.CharField('图书',max_length=64)
price = models.CharField('价格',max_length=32)
pub_date = models.DateField('出版日期',auto_now_add=True)
author = models.ManyToManyField('author.Author',verbose_name='作者')
publish = models.ForeignKey('publish.Publish',verbose_name='出版社',on_delete=models.CASCADE)
class Meta:
verbose_name = '图书'
verbose_name_plural = '图书管理'
def __str__(self):
return self.title
执行数据迁移:
# pycharm中依次执行下列命令
python manage.py makemigrations
python manage.py migrate
视图函数(View):
# book目录下的views.py
from django.shortcuts import render,redirect
from book.models import Book
from author.models import Author
from publish.models import Publish
def book_list(request):
"""图书管理"""
book_all = Book.objects.all()
context = {
'book_all':book_all,
}
return render(request,'book_list.html',context)
def book_add(request):
"""新增图书"""
error = ''
author_all = Author.objects.all() # 查询出所有作者,给前端使用
publish_all = Publish.objects.all() # 查询所有出版社
if request.method == 'POST':
title = request.POST.get('title')
price = request.POST.get('price')
author = request.POST.getlist('author')
publish = request.POST.get('publish')
if title == '' or price == '':
error = '不能为空,请输入内容'
else:
book_add_list = Book.objects.create(title=title,price=price,publish_id=publish)
# book和author是多对多关系,这里需要使用正向查询:按字段进行添加作者
book_add_list.author.add(*author)
return redirect('/book/')
context = {
'error':error,
'author_all':author_all,
'publish_all':publish_all,
}
return render(request,'book_add.html',context)
def book_edit(request,book_id):
"""修改图书"""
author_all = Author.objects.all() # 查询出所有作者,给前端使用
publish_all = Publish.objects.all() # 查询所有出版社
book_edit_list = Book.objects.filter(id=book_id).first()
# 基于前端传过来的ID查询出目前这本书的当前作者信息,编辑时把已选作者勾选上
author_select = book_edit_list.author.all()
if request.method == 'POST':
title = request.POST.get('title')
price = request.POST.get('price')
author = set(request.POST.getlist('author'))
publish = request.POST.get('publish')
try:
books_edit = Book.objects.filter(id=book_id).update(title=title,price=price,publish=publish)
book_edit_list.author.set(author)
return redirect('/book/')
except:
error = '修改失败'
context = {
'author_all': author_all,
'publish_all': publish_all,
'author_select':author_select,
'book_edit_list':book_edit_list,
}
return render(request,'book_edit.html',context)
def book_del(request,book_id):
"""删除图书"""
book_del_list = Book.objects.filter(id=book_id).first()
if book_del_list:
try:
book_del_list.delete()
return redirect('/book/')
except:
error = '删除失败'
else:
error = '删除失败'
context = {
'error':error,
}
return render(request, 'book_list.html',context)
图书管理路由设置:
# book目录下的urls.py
from django.urls import path
from book import views
urlpatterns = [
path('',views.book_list,name='book'), # 图书管理
path('add/',views.book_add,name='book_add'), # 新增图书
path('edit/<int:book_id>',views.book_edit,name='book_edit'), # 修改图书
path('del/<int:book_id>',views.book_del,name='book_del'), # 删除图书
]
模板文件(Template):
# book_list.html
{% extends 'base.html' %}
{% block title %}<title>图书管理</title>{% endblock %}
<main>
{% block content %}
<div class="search">
<form accept="" method="POST">
<span>类型:</span>
<select>
<option value="全部">全部</option>
<option value="作者">作者</option>
<option value="出版社">出版社</option>
</select>
<input type="text" name="search_text" placeholder="请出入搜索关键字">
<button type="submit" class="search_btn">搜索</button>
</form>
<div class="add_btn">
<a href="{% url 'book_add' %}">新增</a>
</div>
</div>
<table>
<thead>
<tr>
<th>编号</th>
<th>图书</th>
<th>价格</th>
<th>作者</th>
<th>出版社</th>
<th>出版日期</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for books in book_all %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ books.title }}</td>
<td>{{ books.price }}</td>
<td>{% for authors in books.author.all %}<a>{{ authors }}</a>{% endfor %}</td>
<td>{{ books.publish }}</td>
<td>{{ books.pub_date }}</td>
<td><a href="{% url 'book' %}edit/{{ books.id }}">修改</a><a href="{% url 'book' %}del/{{ books.id }}">删除</a></td>
</tr>
{% empty %}
<tr><td>没有数据</td></tr>
{% endfor %}
</tbody>
</table>
{% if error %}
<div class="error">{{ error }}</div>
{% endif %}
{% endblock %}
</main>
# book_add.html
{% extends 'base.html' %}
{% block title %}<title>新增图书</title>{% endblock %}
<main>
{% block content %}
<form class="form1" action="" method="post">
<h2>新增图书</h2>
{% csrf_token %}
<p><input type="text" name="title" id="title" placeholder="图书名称" autocomplete="off"><label for="title">请输入图书名称</label></p>
<p><input type="text" name="price" id="price" placeholder="价格"><label for="price">请输入价格</label></p>
<p><select name="author" multiple="multiple">
{% for author in author_all %}
<option value="{{ author.id }}">{{ author.name }}</option>
{% endfor %}
</select>
<label for="size">请选择作者</label>
</p>
<p><select name="publish">
{% for publish in publish_all %}
<option value="{{ publish.id }}">{{ publish.name }}</option>
{% endfor %}
</select>
<label for="size">请选择出版社</label>
</p>
<div class="button">
<button type="submit" class="btn_save">保存</button>
<a href="" class="btn_cancel">取消</a>
</div>
</form>
{% if error %}
<div>{{ error }}</div>
{% endif %}
{% endblock %}
</main>
# book_edit.html
{% extends 'base.html' %}
{% block title %}<title>修改图书</title>{% endblock %}
<main>
{% block content %}
<form class="form1" action="" method="post">
<h2>修改图书</h2>
{% csrf_token %}
<p><input type="text" name="title" id="title" placeholder="图书名称" autocomplete="off" value="{{ book_edit_list.title }}"><label for="title">请输入图书名称</label></p>
<p><input type="text" name="price" id="price" placeholder="价格" value="{{ book_edit_list.price }}"><label for="price">请输入价格</label></p>
<p><select name="author" multiple="multiple">
{% for author_select in author_select %}
<option value="{{ author_select.id }}" selected>{{ author_select.name }}</option>
{% endfor %}
{% for author in author_all %}
<option value="{{ author.id }}">{{ author.name }}</option>
{% endfor %}
</select>
<label for="author">请选择作者</label>
</p>
<p><select name="publish">
<option value="{{ book_edit_list.publish.id }}" selected>{{ book_edit_list.publish.name }}</option>
{% for publish in publish_all %}
<option value="{{ publish.id }}">{{ publish.name }}</option>
{% endfor %}
</select>
<label for="publish">请选择出版社</label>
</p>
<div class="button">
<button type="submit" class="btn_save">保存</button>
<a href="" class="btn_cancel">取消</a>
</div>
</form>
{% endblock %}
</main>
未完待续(抽空写代码注释)