Django图书管理系统(前端对数据库的增删改查)

墨蓝 2022-01-05 17:13 271阅读 0赞

图书管理系统

出版社的管理

源码位置:https://gitee.com/machangwei-8/learning\_materials/tree/master/%E9%A1%B9%E7%9B%AE/bookmanager

1.设计URL

  1. urlpatterns = [
  2.   url(r'^publisher_list/', views.publisher_list),
  3. ]

1.1环境准备

创建项目bookmanager。app名字修改成对应的。

1286512-20190613150308419-284465823.png

1286512-20190613150431394-798244200.png

settings

  1. BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) #项目目录
  2. DEBUG = True #debug模式,测试的时候使用true

创建数据库: create database bookmanager;

  1. #settings.py设置数据库配置
  2. DATABASES = {
  3. 'default': {
  4. 'ENGINE': 'django.db.backends.mysql',
  5. 'NAME': 'bookmanager',
  6. 'HOST':'127.0.0.1',
  7. 'PORT':3306,
  8. 'USER':'root',
  9. 'PASSWORD':'123',
  10. }
  11. }
  12. #init中使用pymysql
  13. import pymysql
  14. pymysql.install_as_MySQLdb()
  15. #models.py中创建表
  16. from django.db import models
  17. # Create your models here.
  18. class Publisher(models.Model):
  19. pid=models.AutoField(primary_key=True) #修改主键名字,使用自己创建的主键
  20. name=models.CharField(max_length=32)

刚刚配置将USER配置成了USR,导致执行makegrations报错:

1286512-20190613153005972-1048994677.png

迁移文件生成:

1286512-20190613153318074-2092359446.png

迁移文件中生成表名,字段名等:

1286512-20190613153429123-2368573.png

再添加一个字段。它提示添加个默认值或者退出:

1286512-20190613153717462-242065525.png

退出后,添加默认值再操作,添加字段,出错

1286512-20190613154658053-1594462157.png

1286512-20190613154821419-1530938986.png

最终执行的迁移文件是这个内容,我再这里面添加一下这个字段:

1286512-20190613155149850-1782822416.png

然后再models里面添加这个,相当于一开始就在models里加了这个字段然后执行了makegragions。这样表里的内容和迁移文件对应上了。

1286512-20190613160214422-19826161.png

1286512-20190613161203074-1575164414.png

似乎执行改变了一次就生成一个文件:

1286512-20190613161514089-41623545.png

刚才出问题了,将这些删掉,再执行试试。

1286512-20190613161805265-1483764188.png

生成数据库表:

1286512-20190613162116612-600652353.png

添加并上传:

1286512-20190613162642247-316655027.png

展示出版社,设置url

  1. from app01 import views
  2. urlpatterns = [
  3. url(r'^admin/', admin.site.urls),
  4. url(r'^publisher_list/', views.publisher_list),
  5. ]
  6. def publisher_list(request):
  7. #显示一个含出版社信息的页面
  8. return render(request,'publisher_list.html')

ContractedBlock.gif ExpandedBlockStart.gif

  1. <html lang="en">
  2. <head>
  3. <meta charset="UTF-8">
  4. <title>魔降风云变</title>
  5. </head>
  6. <body>
  7. <h1>出版社列表</h1>
  8. </body>
  9. </html>

publisher_list.html

1286512-20190613163442017-1596230556.png

这样就拿到页面了,但是还要展示出数据库中的数据。

渲染数据库的数据,将数据以表格形式显示出来:

  1. from app01 import models
  2. #展示出版社
  3. def publisher_list(request):
  4. # 从数据库中查询到出版社的信息
  5. all_publishers = models.Publisher.objects.all()
  6. return render(request, 'publisher_list.html', {
  7. 'all_publishers': all_publishers}) #publisher_list.html中使用的是字典中的键,键代替这个所有的对象
  8. #render方法也可以传{键值对},在html模板文件中使用键对传入的值进行操作。

HTML页面我们可以写死了,但是我们需要的是根据数据库的内容展示出来,用模板渲染出来。

在函数中传进来的是对象列表。每一个都是对象,是表中一行数据:

1286512-20190613170256340-546854485.png

每行数据库的内容显示在网页,使用pk,那么无论主键是啥名字,都可以用pk代替

1286512-20190613170707773-367088846.png

给表格加个边框:

1286512-20190613170908234-534884129.png

添加序号列:forloop.counter,从字典中每循环一次就计数一次,这样就让每行内容有个序号。而我们只需要将模板变量传进去,用固定语法操作。

1286512-20190613171130928-1294535091.png

2.写函数

from django.shortcuts import render
from app01 import models

# 展示出版社
def publisher_list(request):
  # 从数据库中查询到出版社的信息
  all_publishers = models.Publisher.objects.all()
  # 返回一个包含出版社信息的页面
  return render(request, ‘publisher_list.html’, {‘all_publishers’: all_publishers})

过程放在1里面了

3.写模板

  1. <table border="1">
  2. <thead>
  3. <tr>
  4. <th>序号</th>
  5. <th>ID</th>
  6. <th>名称</th>
  7. </tr>
  8. </thead>
  9. <tbody>
  10. {
  11. % for publisher in all_publishers %}
  12. <tr>
  13. <td>{
  14. { forloop.counter }}</td>
  15. <td>{
  16. { publisher.pk }}</td>
  17. <td>{
  18. { publisher.name }}</td>
  19. </tr>
  20. {
  21. % endfor %}
  22. </tbody>
  23. </table>

过程放在1里面了

3.1、新增

  1. obj = models.Publisher.objects.create(name=publisher_name)

新增功能的效果:出版社列表页面中一个按钮,点击跳转页面。这个页面中输入出版社的相关信息(出版社名称),有个按钮提交信息,后台要把输入的信息插入到数据库当中。插入之后浏览器需要再跳转到出版社列表页面。

这个按钮直接是个a标签就可以。也就是我在出版社列表中有个a标签,点击跳转页面add_publisher,里面要有form表单。

1286512-20190613172845340-183893669.png

1286512-20190613172921302-724442854.png

添加url,点击views跳转进入写函数:

1286512-20190613173054681-651272391.png

写出添加数据库记录的页面:这样在框中输入数据,后台将数据获取到并写入数据库中

1286512-20190613174733637-577606058.png

2处理的原理如下1处:

1286512-20190613175242317-1752420919.png

1286512-20190613175123653-1971571497.png

获取出版社的名称:是获取这个提交请求的name,获得post请求键值对中的值

1286512-20190613175828519-319098682.png

# 使用ORM将数据插入到数据库中,将获取到的要添加的出版社名称创建一个字段是输入名称的数据表记录。pid不用写,因为是自增

1286512-20190613180016012-80807182.png

1处的请求2处没有获取到,然后后面的name=None,这样前端3处跳转报错(1048, “Column ‘name’ cannot be null”)

1286512-20190613190932444-605122495.png

上面的报错的原因是1处get的名字与2处不一致,所有没有获取到post提交的值,那么1处的变量就是None。解决方法,将它们改为一致,我将模板文件的2处改为publisher_name。

下面我做的操作是在3处写入‘小马出版社’,点击提交之后,5处不变,重新进入模板文件的页面。可看函数,函数中无论GET或者POST请求都是返回的同样的页面。然后再看

4处数据库,函数拿到了我们提交的数据并在数据库中已经创建了这条记录。

1286512-20190613191647949-632071057.png

网页提交‘小马过河2出版社’,创建一条数据,返回的是这个类的对象,就是那个数据表的一条记录。可以通过创建一行数据时的返回值取出这行数据的各个字段的内容。

1286512-20190613193120156-1094726397.png

我们需要的是当我们从添加出版社的页面提交添加之后,那么页面跳转查看所有出版社的页面,这样能看到新添加的出版社。那么使用重定向:

看下图,在add_publisher页面中添加进一行数据后,直接跳转到publisher_list页面并显示新添加的一条记录‘小熊出版社’。

1286512-20190613194328552-1426366695.png

添加数据页面可以通过添加后进入展示所有数据的页面,但是展示表中所有记录的页面还没有进入添加数据的页面,那么在展示表中所有记录的页面添加一个a标签让它跳转到新增数据的页面即可,如下图

此处的a标签地址应写成路径,在url路由中能找到,这里实现了点击新增进入添加数据的页面,添加数据又能返回这里的展示页面。新增a标签的跳转实际上是点击之后又发送了一次get请求。

1286512-20190613195701289-1715945708.png

我现在添加一个重复的出版社名称,它会添加记录到数据库中,

1286512-20190613201026029-1146491968.png

出版社名字不应该重复的,下面就把这个字段设置成唯一键,然后执行数据迁移的那两条命令结果报错,原因是数据库中已经有重复的数据了‘小熊出版社’。

django.db.utils.IntegrityError: (1062, “Duplicate entry ‘小熊出版社’ for key ‘app01_publisher_name_36f04192_uniq’”)

1286512-20190613201839861-214622385.png

pycharm中将这条数据删除掉并提交

1286512-20190613202141321-1141237786.png

然后执行那两条数据迁移的命令,成功修改这个字段为唯一键:

1286512-20190613202448277-282069682.png

既然这个字段已经是唯一键了,那么我在页面添加数据库中已经有的这个字段内容,那么报错如下:

  1. (1062, "Duplicate entry '小熊出版社' for key 'app01_publisher_name_36f04192_uniq'")

1286512-20190613202645072-1256562505.png

数据库有约束,我应该在数据库插入之前,就进行判断有没有这个数据,而不是直接就往数据里面插入数据

这里添加了判断条件之后还是报错页面,原因是,我们应该在数据插入之前就判断是否存在相同的字段内容

1286512-20190613204413438-1655004027.png

1处插入数据前判断是否有相同的,有就传进error信息到,然后在返回的原网页后面渲染上错误提示信息(2处)。这样同名的数据插入网页会提示已存在的提示

1286512-20190613204552250-431928769.png

如果我不写内容直接点击提交

1286512-20190613204941597-415335357.png

出现了一条空数据,这显然不是我们想要的,所有我们需要在这个的函数上做判断,如果获取的值为空,那么返回这个页面,并在输入框后面渲染不能输入为空的错误提示

这里显示为已存在,刚刚我在里面插入了一个空的数据,现在将它删除掉

1286512-20190613210329818-1638220524.png

1286512-20190613210450529-1849654799.png

现在显示的是不能为空了,一开始error不是这个信息,到了不能为空这里,又被覆盖了一次。

1286512-20190613210632148-2141333854.png

看下面的代码,有三个render

1286512-20190613210848735-1621343453.png

我想要将三个render简化成一个:

1)我可以最后返回一个render,其它的只是赋值error变量。然后render的页面里渲染不同的error值。如果没有错误即默认error是空字符串就可以。

2)然后判断error信息是否非假(即非空),非假才执行创建数据记录的操作并重定向页面到查看所有出版社数据信息的页面

当设置了一个error是空字符串的时候,正常返回的页面是没有显示内容的。这样虽然函数的结构修改了,但是功能没有改变

1286512-20190613212317804-152819530.png

ContractedBlock.gif ExpandedBlockStart.gif

  1. def add_publisher(request):
  2. error=''
  3. #返回一个包含from表单的出版社页面
  4. if request.method=='POST':
  5. publish_name=request.POST.get('publisher_name')
  6. # 判断出版社名称是否有重复的
  7. if models.Publisher.objects.filter(name=publish_name):
  8. error='出版社名称已存在'
  9. #判断输入值是否为空
  10. if not publish_name:
  11. error="输入不能为空"
  12. if not error:
  13. obj=models.Publisher.objects.create(name=publish_name)
  14. #跳转到展示出版社的页面
  15. return redirect('/publisher_list/')
  16. return render(request,'add_publisher.html',{
  17. 'error':error})

add_publisher

但是还是有个问题,就是取出来的数据id是乱序的

1286512-20190613212225968-154883812.png

这是因为publiser_list这一页的get请求出来的数据没有排序,将从数据库中取出来的所有数据给个排序就解决了

1286512-20190613212838958-537599717.png

1286512-20190613213007593-1265184035.png

3.2、删除

  1. obj_list = models.Publisher.objects.filter(pk=pk)
  2. obj_list.delete()
  3. obj = models.Publisher.objects.get(pk=pk)
  4. obj.delete()

想要删除某一条记录,应该做什么样的操作呢?那么在名称列后面有个按钮或者a标签,点击它就删除掉这条记录,这样是可以的吧。

1286512-20190613214122172-815527342.png

那么在展示页中后面添加一列,使用a标签

1286512-20190613214507091-1686892738.png

现在应该是我点击一个删除,然后发送一个请求 ,并在后端数据库将这条数据删除,删除之后再跳转到这个页面

先设计删除url,创建删除函数,删除函数逻辑如下;

1286512-20190613215514004-214101065.png

如果我的函数中有一处存在错误,可能所有函数对应的网页都不能访问:检查元素加载失败

1286512-20190613220158269-1480255010.png

给删除a标签设置一个地址,已经实现点击删除访问这个路径了

1286512-20190613220439076-1853419452.png

但是点击删除的是哪条记录,我需要获取到才能在后台将这条记录删除掉。于是将它的跳转路径拼接一个这条记录的主键id

1286512-20190613220744428-1453083126.png

删除代码:

1286512-20190613224955771-1281804829.png

1286512-20190613224849370-2037250110.png

点击删除:

1286512-20190613224923433-570698356.png

这时候我是点击删除按钮删的,我也可能使用浏览器访问地址进行删除

1286512-20190613225234719-194883559.png

id=15的已删除:

1286512-20190613225256362-1936044574.png

如果自己拼接在浏览器地址栏访问请求不存在的记录:报错:Publisher matching query does not exist.

1286512-20190613225608318-216556694.png

那么我应该对这种情况做个判断,因为是get获取数据的,get不到就会显示错误,那么将get改为过滤

1286512-20190613225745368-2011258079.png

过滤出来可能多条记录,也可以对queryset 这个对象列表里的对象批量删除

1286512-20190613230253656-1969148925.png

ContractedBlock.gif ExpandedBlockStart.gif

  1. def del_publisher(request):
  2. # 获取要删除的数据
  3. pk = request.GET.get('id')
  4. obj_list = models.Publisher.objects.filter(pk=pk)
  5. if not obj_list:
  6. # 没有要删除的数据
  7. return HttpResponse('要删除的数据不存在')
  8. # 删除该数据
  9. # obj.delete()
  10. obj_list.delete()
  11. # 跳转到展示页面
  12. return redirect('/publisher_list/')

删除功能代码

3.3、编辑(修改数据)

  1. obj.name = publisher_name
  2. obj.save() # 保存数据到数据库中

想要进行编辑的话应该是什么样的过程。点击编辑a标签之后可以跳转到编辑页面,这个编辑页面包含了你要编辑的那条数据,直接在这上面进行修改,修改完了之后提交,后台修改了之后跳转回来到所有出版社展示页

创建url,创建函数,将编辑标签和删除标签写在同一列

1286512-20190613232048174-1001705256.png

1286512-20190613232137957-65005372.png

1286512-20190613232146698-1693115504.png

点击其中一个页面往这个地址发送请求了,并且根据id获取到了是哪条数据需要编辑

1286512-20190613232252536-1816960272.png

应该返回一个页面,这个页面中包含点击编辑的那条原始数据。编辑页面和添加页面差不多。

编辑的页面这样的话么有带上id=2这条数据的name

1286512-20190613233019676-1406920174.png

1286512-20190613232913787-1395751659.png

因为编辑按钮a标签跳转的时候带着对应数据的id,那么由此获得这条数据并将它的内容name默认填入到编辑的input标签里

  1. 通过点击编辑按钮传到请求里的id查出满足条件的数据库记录,并传到html模板文件中进行调用其中的值进行渲染。使得编辑框里显示要编辑的原数据内容

1286512-20190613234239947-776495572.png

如图,点击这个id的就显示出来要编辑的原数据。编辑的展示这样就没有问题

1286512-20190613234427592-220212627.png

下面点击提交,要进行以下的逻辑操作:

1286512-20190613234847326-938262999.png

要修改id=2的数据:由于发送POST请求之前,也要获取到obj对象,所有把POST请求处理放在后面

1286512-20190613235637351-433700251.png

1286512-20190613235837408-1981156481.png

现在需要将可能遇到的问题写上。传进错误信息进行渲染

1286512-20190614000521802-962418880.png

写这些功能先写正常的情况下,然后再考虑会出现的问题。

4、项目目录结构

1286512-20190614005419916-1438503223.png

ContractedBlock.gif ExpandedBlockStart.gif

  1. from django.shortcuts import render, redirect, HttpResponse
  2. from app01 import models
  3. # 展示出版社
  4. def publisher_list(request):
  5. # 从数据库中查询到出版社的信息
  6. all_publishers = models.Publisher.objects.all().order_by('pk')
  7. # 返回一个包含出版社信息的页面
  8. return render(request, 'publisher_list.html', {
  9. 'all_publishers': all_publishers})
  10. # 新增出版社
  11. def add_publisher(request):
  12. # 对请求方式进行判断
  13. if request.method == 'POST':
  14. # 处理POST请求
  15. # 获取到出版社的名称
  16. publisher_name = request.POST.get('publisher_name')
  17. # 判断出版社名称是否有重复的
  18. if models.Publisher.objects.filter(name=publisher_name):
  19. return render(request, 'add_publisher.html', {
  20. 'error': '出版社名称已存在'})
  21. # 判断输入的值是否为空
  22. if not publisher_name:
  23. return render(request, 'add_publisher.html', {
  24. 'error': '不能输入为空'})
  25. # 使用ORM将数据插入到数据库中
  26. obj = models.Publisher.objects.create(name=publisher_name)
  27. # 跳转到展示出版社的页面
  28. return redirect('/publisher_list/')
  29. # 返回一个包含form表单的页面
  30. return render(request, 'add_publisher.html')
  31. # 新增出版社
  32. def add_publisher(request):
  33. error = ''
  34. # 对请求方式进行判断
  35. if request.method == 'POST':
  36. # 处理POST请求
  37. # 获取到出版社的名称
  38. publisher_name = request.POST.get('publisher_name')
  39. # 判断出版社名称是否有重复的
  40. if models.Publisher.objects.filter(name=publisher_name):
  41. error = '出版社名称已存在'
  42. # 判断输入的值是否为空
  43. if not publisher_name:
  44. error = '不能输入为空'
  45. if not error:
  46. # 使用ORM将数据插入到数据库中
  47. obj = models.Publisher.objects.create(name=publisher_name)
  48. # 跳转到展示出版社的页面
  49. return redirect('/publisher_list/')
  50. # 返回一个包含form表单的页面
  51. return render(request, 'add_publisher.html', {
  52. 'error': error})
  53. # 删除出版社
  54. def del_publisher(request):
  55. # 获取要删除的数据
  56. pk = request.GET.get('id')
  57. obj_list = models.Publisher.objects.filter(pk=pk)
  58. if not obj_list:
  59. # 没有要删除的数据
  60. return HttpResponse('要删除的数据不存在')
  61. # 删除该数据
  62. # obj.delete()
  63. obj_list.delete()
  64. # 跳转到展示页面
  65. return redirect('/publisher_list/')
  66. # 编辑出版社
  67. def edit_publisher(request):
  68. error = ''
  69. # 查找要编辑的数据
  70. pk = request.GET.get('id') # url上携带的参数 不是GET请求提交参数
  71. obj_list = models.Publisher.objects.filter(pk=pk)
  72. if not obj_list:
  73. return HttpResponse('要编辑的数据不存在')
  74. obj = obj_list[0]
  75. if request.method == 'POST':
  76. # 处理POST请求
  77. # 获取新提交的出版的名称
  78. publisher_name = request.POST.get('publisher_name')
  79. if models.Publisher.objects.filter(name=publisher_name):
  80. # 新修改的名称已存在
  81. error = '新修改的名称已存在'
  82. if obj.name == publisher_name:
  83. error = '名称未修改'
  84. if not publisher_name:
  85. error = '名称不能为空'
  86. if not error:
  87. # 修改数据
  88. obj.name = publisher_name
  89. obj.save() # 保存数据到数据库中
  90. # 跳转到出版社的展示页面
  91. return redirect('/publisher_list/')
  92. # 返回一个包含原始数据的页面
  93. return render(request, 'edit_publisher.html', {
  94. 'obj': obj,'error':error})

参考代码views

转载于:https://www.cnblogs.com/machangwei-8/p/11016524.html

发表评论

表情:
评论列表 (有 0 条评论,271人围观)

还没有评论,来说两句吧...

相关阅读