好好吃饭 按时睡觉 不要抱怨 心怀善念 坚持做自己喜欢做的事 用心感受生活的每一个细节 沉淀 再沉淀 因为你要成为一个温柔而强大的人
一、需求分析,数据库表设计
需求分析:
1、登录注册功能;
2、首页;
3、分别展示出书籍页面,作者页面,出版社页面;
4、书籍页面功能有添加书本、编辑、删除;
5、作者页面功能有添加作者、编辑、删除、作者详情;
6、出版社页面功能有添加出版社、编辑、删除
数据库表设计
一共五张表
用户表 User: name | password | register_time
图书表 Book: title | price | publish_time | publish|author
(ps:publish和authors是外键字段)
出版社表 Publish: name | addr | email
作者表 Author: name | age | authordetail
作者详情表 AuthorDetail: phone | addr
一个出版社可以出版多本书籍,但一本书只能在一个出版社出版(一对多)
一个作者可以写多本书,一本书也可有多个作者(多对多)
一个作者对应一个详情信息(一对一)
二、Django环境配置
⚠️还要在项目或应用的init文件中写入下面代码,告诉Django使用的是mysql数据库:
import pymysql
pymysql.install_as_MySQLdb()
三、图书管理系统的登录、注册
1、路由配置(urls.py)
url(r'^$', views.login,name='login'), # 精确定位路由,默认打开就是登录界面
url(r'^register/', views.register,name='register'),
2、前端页面
登录界面(login.html)
Title
注册界面(register.html)
Title
3、后端逻辑(views.py)
'''
登录功能逻辑思路:
从前端获取姓名和密码;
判断姓名和密码是否为空;
从数据库的user表中查出用户姓名和密码;
循环列表得到用户对象;
将用户名和密码与前端得到的名字和密码进行比对;
如果比对成功则登录成功跳转到home页面;
如果比对不成功则返回一个登录失败页面,显示返回注册
'''
def login(request):
if request.method == 'POST':
name = request.POST.get('name')
password = request.POST.get('password')
if name and password:
user_list=models.User.objects.values('name','password')
for user in user_list:
if name==user.get('name'):
if password==user.get('password'):
return redirect(reverse('home'))
else:
return HttpResponse('密码错啦!')
else:
return HttpResponse('请输入用户名和密码!')
return render(request, 'login.html', locals())
'''
注册功能逻辑:
从前端获取姓名和密码;
判断姓名和密码是否为空;
从数据库的user表中查出用户姓名;
for循环出用户姓名对象;
判断前端输入的名字是否在用户姓名对象里的名字中;
如果名字存在则发出提示信息;
如果不存在则进入创建姓名和密码到数据库中;
创建完成跳转到登录界面;
'''
def register(request):
if request.method == 'POST':
name = request.POST.get('name')
password = request.POST.get('password')
if name and password:
username_list = models.User.objects.values('name')
for username in username_list:
if name in username.get('name'):
return HttpResponse('用户已存在,请直接登录!')
else:
models.User.objects.create(name=name, password=password)
else:
return HttpResponse('请输入用户名和密码!')
return redirect(reverse('login'))
return render(request, 'register.html')
四、home主页面搭建
1、路由配置(urls.py)
这里主要是给他一个反向解析的名字,无论前端url名字怎么变化,后端都能匹配到这个路由,而且在不同的视图函数中都能使用这个名字来定位到要解析的路由对应的视图函数。
url(r'^home/', views.home,name='home'),
2、前端页面(home.html)
首先要导入bootstrap样式,在里面找自己想要的样式拷贝过来修改。bootstrap样式传送门:https://v3.bootcss.com/
主页面应用的逻辑很少,主要是页面的搭建和数据的渲染。
{#导航条开始#}
{#导航条结束#}
{#左边栏开始#}
3、后端逻辑(views.py)
对位填充,返回到主页面
def home(request):
return render(request, 'home.html')
五、图书列表页面,作者列表页面,出版社页面搭建
1、路由配置(urls.py)
url(r'^book_list/', views.book_list,name='book_list'),
url(r'^author_list/', views.author_list,name='author_list'),
url(r'^publish_list/', views.publish_list,name='publish_list'),
2、后端逻辑(views.py)
因为要先从数据库中查询出所有信息,然后渲染到前端页面,所以先写逻辑。
这里查询出来的是个queryset对象,是个列表,对象还能继续点他的属性,这里显示名字是因为在模型表中用_ str_自定义print,在模型层加入了如下代码def __str__(self): return '作者对象的名字:%s'%self.name
,下面的是查询所有作者信息,查询出来是作者的QuerySet 对象:
, , , , , ]>
# 书籍列表
def book_list(request):
# 先查询出所有书籍信息,将内容渲染到前端
book_list = models.Book.objects.all()
return render(request, 'book_list.html', locals())
# 作者列表
def author_list(request):
# 查询出所有作者信息,将内容渲染到前端
author_list = models.Author.objects.all()
return render(request, 'author_list.html', locals())
# 出版社列表
def publish_list(request):
# 查询出所有出版社信息,将内容渲染到前端
publish_list = models.Publish.objects.all()
return render(request, 'publish_list.html', locals())
3、前端页面(book_list.html,author_list.html,publish_list.html)
book_list.html
{% extends 'home.html' %}
{% block content %}
添加书籍
id
title
price
publish
publish_time
authors
actions
{% for book in book_list %}
{{ book.pk }}
{{ book.title }}
{{ book.price }}
{{ book.publish.name }}
{{ book.publish_time|date:'Y-m-d' }}
{% for author_obj in book.authors.all %}
{% if forloop.last %}
{{ author_obj.name }}
{% else %}
{{ author_obj.name }}、
{% endif %}
{% endfor %}
编辑
删除
{% endfor %}
{% endblock %}
:在每个 {% for %}循环里有一个称为 forloop的模板变量,这个变量有一些提示循环进度信息的属性。
forloop.counter 是一个表示当前循环的执行次数的整数计数器。 这个计数器是从1开始的,所以在第一次循环时 forloop.counter 将会被设置为1。
forloop.counter0 类似于 forloop.counter ,但是它是从0计数的。 第一次执行循环时这个变量会被设置为0。
{% for item in todo_list %}
{{ forloop.counter }}: {{ item }}
{% endfor %}
forloop.revcounter 是表示循环中剩余项的整型变量。 在循环初次执行时 forloop.revcounter 将被设置为序列中项的总数。 最后一次循环执行中,这个变量将被置1。
forloop.revcounter0 类似于 forloop.revcounter ,但它以0做为结束索引。在第一次执行循环时,该变量会被置为序列的项的个数减1。
forloop.first 是一个布尔值,如果该迭代是第一次执行,那么它被置为True,需要特殊处理第一个元素时很方便:
{% for object in objects %}
{% if forloop.first %}
{% else %}
{% endif %}
{{ object }}
{% endfor %}
forloop.last 是一个布尔值;在最后一次执行循环时被置为True。 一个常见的用法是在一系列的链接之间放置管道符(|)
{% for link in links %}
{{ link }}{% if not forloop.last %} | {% endif %}
{% endfor %}
输出结果是:Link1 | Link2 | Link3 | Link4
另一个常见的用途是为列表的每个单词的加上逗号。
Favorite places:
{% for p in places %}
{{ p }}{% if not forloop.last %}, {% endif %}
{% endfor %}
输出结果是:厦门,广州,上海
forloop.parentloop 在嵌套的循环中, forloop.parentloop引用父级循环的 forloop 对象。举个:
{% for country in countries %}
{% for city in country.city_list %}
Country #{{ forloop.parentloop.counter }}
City #{{ forloop.counter }}
{{ city }}
{% endfor %}
{% endfor %}
⚠️forloop 变量只在循环内部可用。模板解析器遇到 {% endfor %} 时, forloop 随之消失,不可访问了。
⚠️Context和forloop变量
在一个 {% for %} 块中,已存在的变量会被移除,以避免 forloop 变量被覆盖。 Django会把这个变量移动到 forloop.parentloop 中。通常我们不用担心这个问题,但是一旦我们在模板中定义了 forloop 这个变量(当然我们反对这样做),在 {% for %} 块中它会在 forloop.parentloop 被重新命名。
author_list.html
{% extends 'home.html' %}
{% block content %}
添加作者
id
name
age
authordetail
action
{% for author in author_list %}
{{ author.pk }}
{{ author.name }}
{{ author.age }}
作者信息
编辑
删除
{% endfor %}
{% endblock %}
publish_list.html
{% extends 'home.html' %}
{% block content %}
添加出版社
id
name
addr
email
action
{% for publish in publish_list %}
{{ publish.pk }}
{{ publish.name }}
{{ publish.addr }}
{{ publish.email }}
编辑
删除
{% endfor %}
{% endblock %}
六、图书页面之添加书籍
1、路由配置(urls.py)
url(r'^add_book/', views.add_book,name='book_add'),
2、 前端页面(add_book.html)
{% extends 'home.html' %}
{% block content %}
添加书籍
{% endblock %}
3、后端逻辑(views.py)
def add_book(request):
if request.method == 'POST':
title = request.POST.get('title')
price = request.POST.get('price')
# publish拿到的是publish的id
publish_id = request.POST.get('publish')
publish_date = request.POST.get('date')
authors = request.POST.getlist('authors') # [1,2,3]
# 数据库新增数据,⚠️book表中的只有publish,但是他是外键字段foreignkey,会自动增加_id变成publish_id,因此更新的时候这里还是要写publish_id
book_obj = models.Book.objects.create(title=title, price=price, publish_id=publish_id,
publish_time=publish_date)
# authors是多对多字段,去到书籍与作者的第三张表手动创建关系,因为authors拿出来是个列表,所以将它打散添加
book_obj.authors.add(*authors)
# 跳转到图书的展示页面
return redirect(reverse('book_list'))
# 将出版社和作者数据全部传递给添加页面
publish_list = models.Publish.objects.all()
author_list = models.Author.objects.all()
# get请求返回一个添加页面
return render(request, 'add_book.html', locals())
七、图书页面之编辑书籍
1、路由配置(urls.py)
url(r'^edit_book/(\d+)', views.edit_book,name='book_edit'),
2、 前端页面(edit_book.html)
编辑书籍之前,要把原信息都展示出来
{% extends 'home.html' %}
{% block content %}
编辑书籍
{% endblock %}
3、后端逻辑(views.py)
def edit_book(request, edit_id):
# 获取要编辑的对象
edit_obj = models.Book.objects.filter(pk=edit_id).first()
if request.method == 'POST':
title = request.POST.get('title')
price = request.POST.get('price')
publish_date = request.POST.get('date')
publish_id = request.POST.get('publish')
# 因为一本书的作者不止一个,所以要用getlist取值
authors = request.POST.getlist('authors')
# 根据要编辑的id更新数据库中的信息
models.Book.objects.filter(pk=edit_id).update(title=title, price=price, publish_time=publish_date,
publish_id=publish_id)
# 更新作者,set里面要放可迭代对象
edit_obj.authors.set(authors)
return redirect(reverse('book_list'))
publish_list = models.Publish.objects.all()
author_list = models.Author.objects.all()
return render(request, 'edit_book.html', locals())
八、图书页面之删除书籍
1、路由配置(urls.py)
url(r'^delete_book/(\d+)', views.delete_book,name='book_delete'),
2、 后端逻辑(views.py)
因为删除书籍只要直接删除就好了,没有页面展示。
def delete_book(request, delete_id):
# 根据要删除对象的id来删除对应的书籍
models.Book.objects.filter(pk=delete_id).delete()
return redirect(reverse('book_list'))
九、作者页面之添加作者
1、路由配置(urls.py)
url(r'^add_author/', views.add_author,name='author_add'),
2、 前端页面(add_author.html)
{% extends 'home.html' %}
{% block content %}
添加作者
{% endblock %}
3、后端逻辑(views.py)
def add_author(request):
if request.method == 'POST':
name = request.POST.get('name')
age = request.POST.get('age')
phone = request.POST.get('phone')
addr = request.POST.get('addr')
# 新增作者,与之一对一关系的作者详情表也要新增信息
# 首先新增作者详情表中的数据,赋值给作者详情对象
authordetail_obj = models.AuthorDetail.objects.create(phone=phone, addr=addr)
# 因为是一对一的关系,所以在作者表中新增数据时,作者详情这个外键是和作者详情对象的主键绑定的
models.Author.objects.create(name=name, age=age, authordetail_id=authordetail_obj.pk)
return redirect(reverse('author_list'))
return render(request, 'add_author.html', locals())
十、作者页面之编辑作者
1、路由配置(urls.py)
url(r'^edit_author/(\d+)', views.edit_author,name='author_edit'),
2、 前端页面(edit_author.html)
{% extends 'home.html' %}
{% block content %}
编辑作者信息
{% endblock %}
3、后端逻辑(views.py)
def edit_author(request, edit_id):
# 先获取要编辑的对象
edit_obj = models.Author.objects.filter(pk=edit_id).first()
if request.method == 'POST':
name = request.POST.get('name')
age = request.POST.get('age')
models.Author.objects.filter(pk=edit_id).update(name=name, age=age)
return redirect(reverse('author_list'))
authordetail_list = models.AuthorDetail.objects.all()
return render(request, 'edit_author.html', locals())
十一、作者页面之作者详情
1、路由配置(urls.py)
url(r'^author_detail/(\d+)', views.author_detail,name='author_detail'),
2、 前端页面(author_detail.html)
这里是跳到另外一个页面
Title
作者信息
id
{# name #}
phone
addr
{% for authordetail in authordetail_list %}
{{ authordetail.pk }}
{# {{ author_name }} #}
{{ authordetail.phone }}
{{ authordetail.addr }}
{% endfor %}
返回
3、后端逻辑(views.py)
def author_detail(request, detail_id):
author_obj = models.Author.objects.filter(pk=detail_id).first()
authordetail_list = models.AuthorDetail.objects.filter(pk=author_obj.authordetail_id).all()
return render(request, 'author_detail.html', locals())
十二、作者页面之删除作者
1、路由配置(urls.py)
url(r'^delete_author/(\d+)', views.delete_author,name='author_delete'),
2、后端逻辑(views.py)
def delete_author(request, delete_id):
models.Author.objects.filter(pk=delete_id).delete()
return redirect(reverse('author_list'))
十三、出版社页面之添加出版社
1、路由配置(urls.py)
url(r'^add_publish/', views.add_publish,name='publish_add'),
2、 前端页面(edit_publish.html)
{% extends 'home.html' %}
{% block content %}
编辑出版社
{% endblock %}
3、后端逻辑(views.py)
def add_publish(request):
if request.method == 'POST':
name = request.POST.get('name')
addr = request.POST.get('addr')
email = request.POST.get('email')
publish_obj = models.Publish.objects.create(name=name, addr=addr, email=email)
return redirect(reverse('publish_list'))
return render(request, 'add_publish.html', locals())
十四、出版社页面之编辑出版社
1、路由配置(urls.py)
url(r'^edit_publish/(\d+)', views.edit_publish,name='publish_edit'),
2、 前端页面(edit_book.html)
{% extends 'home.html' %}
{% block content %}
编辑书籍
{% endblock %}
3、后端逻辑(views.py)
def edit_publish(request, edit_id):
edit_obj = models.Publish.objects.filter(pk=edit_id).first()
if request.method == 'POST':
name = request.POST.get('name')
addr = request.POST.get('addr')
email = request.POST.get('email')
models.Publish.objects.filter(pk=edit_id).update(name=name, addr=addr, email=email)
return redirect(reverse('publish_list'))
return render(request, 'edit_publish.html', locals())
十五、出版社页面之删除出版社
1、路由配置(urls.py)
url(r'^delete_publish/(\d+)', views.delete_publish,name='publish_delete'),
2、后端逻辑(views.py)
def delete_publish(request, delete_id):
models.Publish.objects.filter(pk=delete_id).delete()
return redirect(reverse('publish_list'))