django小练习—小型图书管理系统

django小练习—小型图书管理系统

  1. 功能分析:
    1. 使用django内建的用户系统实现支持用户的注册和登录;
    2. 登录之后能显示数据库中的图书信息
    3. 支持分页功能
    4. 能够对已有的图书信息进行修改和删除
    5. 能够添加新的图书信息
    6. 能够将当前页的图书信息导出
  2. 开发
    1. 铺垫:

      1. 创建项目:cd到指定的文件夹,django-admin startproject bookManageSystem
      2. 创建应用:cd到项目文件夹,然后python manage.py startapp userpython manage.py startapp bookstore
      3. 创建数据库:mysql -uroot -p进入mysql,然后create database bookManageSystem default charset utf8
      4. settings基本配置:
        INSTALLED_APPS = [
            'django.contrib.admin',
            'django.contrib.auth',
            'django.contrib.contenttypes',
            'django.contrib.sessions',
            'django.contrib.messages',
            'django.contrib.staticfiles',
            'user',
            'bookstore'
        ]
        
        DATABASES = {
            'default': {
                'ENGINE': 'django.db.backends.mysql',
                'NAME': 'bookManageSystem',
                'USER': 'root',
                'PASSWORD': '你的数据库密码',
                'HOST': '127.0.0.1',
                'PORT': '3306'
            }
        }
        
        LANGUAGE_CODE = 'zh-Hans'
        
        TIME_ZONE = 'Asia/Shanghai'
        
    2. 用户app:

      1. 铺垫:

        1. 在user文件夹下手动创建templates文件夹,下面再创建一个user文件夹,用来存放html模板文件。

        2. 配置分布式路由: 在主路由文件中添加path('user/',include('user.urls')),,在应用文件夹user下面手动创建一个urls.py文件,结构和主路由文件一致。

        3. views.py文件中导入:

          from django.contrib.auth import authenticate,login,logout
          from django.contrib.auth.models import User
          from django.http import HttpResponse, HttpResponseRedirect
          from django.shortcuts import render
          

          urls.py文件中:

          from django.urls import path
          from . import views
          
      2. 网站首页(相当简约)

        1. 路由: 在应用文件夹user的urls.py中添加path('index',views.index_view),
        2. 视图函数:render了一个非常简单的页面。
          def index_view(request):
              return render(request,'user/index.html')
          
        3. 模板文件:极致的简约,没有任何修饰(hhh)
          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>首页</title>
          </head>
          <body>
          <h1>图书管理系统</h1>
          <p>
              <a href="/user/register">注册</a>  <a href="/user/login">登录</a>
          </p>
          </body>
          </html>
          
      3. 注册功能:

        1. 路由:在user下面的urls文件中添加path('register', views.register_view),

        2. 视图函数:

          def register_view(request):
              #注册
              #分get和post进行处理:点击注册时,是get请求,负责render一个页面,在注册界面提交信息时,是post请求,负责处理数据
              if request.method == 'GET':
                  return render(request,'user/register.html')
              elif request.method == 'POST':
                  username = request.POST['username']
                  password_1 = request.POST['password_1']
                  password_2 = request.POST['password_2']
                  if password_1 != password_2:
                      return HttpResponse('两次密码输入不一致')
                  #TODO 查询用户名是否已经注册
          
                  old_user = User.objects.filter(username=username)
                  if old_user:
                      return HttpResponse('用户名已注册')
          
          
                  #务必使用create_user创建用户
                  user = User.objects.create_user(username=username,password=password_1)
          
                  #如果需要注册后免登录
                  # login(request,user)
                  # return HttpResponseRedirect('/index')
          
                  return HttpResponseRedirect('/user/index')
          
        3. 模板文件:

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>注册</title>
          </head>
          <body>
          <form action="/user/register" method="post">
              {% csrf_token %}
              <p>
                  用户名:<input type="text" name="username">
              </p>
              <p>
                  密码:<input type="text" name="password_1">
              </p>
              <p>
                  确认密码:<input type="text" name="password_2">
              </p>
              <p>
                  <input type="submit" value="注册">
              </p>
          </form>
          </body>
          </html>
          
      4. 登录功能:

        1. 路由:path('login', views.login_view),

        2. 视图函数:

          def login_view(request):
              #登录
              if request.method == 'GET':
                  return render(request,'user/login.html')
              elif request.method == 'POST':
                  username = request.POST['username']
                  password = request.POST['password']
          
                  #校验用户信息
                  user = authenticate(username=username,password=password)
          
                  if not user:
                      return HttpResponse('用户名或密码错误')
                  else:
                      #校验成功
                      #记录会话状态
                      login(request,user)
                      return HttpResponseRedirect('/bookstore/all_book')
          
        3. 模板文件:

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>登录</title>
          </head>
          <body>
          <form action="/user/login" method="post">
              {% csrf_token %}
              <p>
                  用户名: <input type="text" name="username">
              </p>
              <p>
                  密码: <input type="password" name="password">
              </p>
              <p>
                  <input type="submit" value="登录">
              </p>
          
          </form>
          </body>
          </html>
          
      5. 退出功能:

        1. 路由:path('logout',views.logout_view)
        2. 视图函数:
          def logout_view(request):
              logout(request)
              return HttpResponseRedirect('/user/index')
          
    3. bookstore应用:

      1. 铺垫:

        1. 在user文件夹下手动创建templates文件夹,下面再创建一个user文件夹,用来存放html模板文件。

        2. 配置分布式路由: 在主路由文件中添加path('bookstore/',include('bookstore.urls')),在应用文件夹user下面手动创建一个urls.py文件,结构和主路由文件一致。

        3. views文件中引入:

          from django.shortcuts import render
          from django.core.paginator import Paginator
          from django.http import HttpResponse, HttpResponseRedirect
          import csv
          #引入模型类
          from .models import Book
          from django.contrib.auth.decorators import login_required
          

          urls文件中引入:

          from django.urls import path
          from . import views
          
      2. 创建模型类:

        1. 编写模型类: 在boostore这个应用文件夹下的models.py 文件夹中编写:

          from django.db import models
          
          # Create your models here.
          class Book(models.Model):
              #根据ORM的映射规则,一个类实际上就是一张表(表名=应用名_类名),类中的每个属性就对应着表中的一个字段
              title = models.CharField('书名',max_length=50,default='',unique=True)
              pub = models.CharField('出版社',max_length=100,default='')
              price = models.DecimalField('价格',max_digits=7,decimal_places=2)
              #任何关于表结构的修改,务必在对应模型类上修改
              market_price = models.DecimalField('零售价',max_digits=7,decimal_places=2,default=0.0)
              is_active = models.BooleanField('是否活跃',default=True)
              # 改变当前模型类对应的表的名字
              class Meta:
                  db_table = 'book'
              def __str__(self):
                  return '%s-%s-%s-%s'%(self.title,self.price,self.pub,self.market_price)
          
        2. 与数据库同步:python manage.py makemigrationspython manage.py migrate

        3. 创建数据:cd在项目文件夹下,使用python manage.py shell打开django shell,先导入模型类:from bookstore.models import Book,然后创建数据:Book.objects.create(title='Python',pub='清华大学出版社',price=30,market_price=35,is_active=True)

      3. 显示图书:

        1. 路由:在bookstore文件夹中的urls文件中添加path('all_book',views.all_book),
        2. 视图函数:
          @login_required
          def all_book(request):
              #在视图中要做的就是将书全查出来,然后发送给视图进行渲染
              #在这里用filter(is_active=True)进行筛选,就能巧妙实现删除了数据时候,该数据不再被显示的要求
              all_book = Book.objects.filter(is_active=True)
          
              # /bookstore/all_book?page=4
              # 拿到当前的页码,没有的话就默认是1
              page_num = request.GET.get('page', 1)
          
              # 初始化paginator
              # 第一个参数是总的数据,第二个参数是每页显示的条数
              paginator = Paginator(all_book, 2)
              # 初始化具体页码对应的page对象,管具体的每一页
              current_page = paginator.page(int(page_num))
          
              return render(request,'bookstore/all_book.html',locals()) #locals可以将函数内的局部变量以字典的形式传进render中。
          
        3. 模板文件:在bookstore/template下的bookstore文件夹中写:
          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>所有书籍</title>
          </head>
          <body>
          <p>
              <a href="/user/logout">退出</a>
          </p>
          <P>
              <a href="/bookstore/output_csv?page={{ current_page.number }}">导出本页数据</a>
          </P>
          <p>
              <a href="/bookstore/add_book">添加数据</a>
          </p>
          <table border="'1">
              <tr>
                  <th>id</th>
                  <th>title</th>
                  <th>pub</th>
                  <th>price</th>
                  <th>market_price</th>
                  <th>op</th>
              </tr>
              {% for book in current_page %}
                  <tr>
                      <td>{{ book.id }}</td>
                      <td>{{ book.title }}</td>
                      <td>{{ book.pub }}</td>
                      <td>{{ book.price }}</td>
                      <td>{{ book.market_price }}</td>
                      <td>
                          <a href="/bookstore/update_book/{{ book.id }}">更新</a>
                          {#点击a标签,发个get,拿到页面;然后修改数据,点击更新,就要给后台提交一些数据,这里就是POST#}
                          <a href="/bookstore/delete_book?book_id={{ book.id }}">删除</a>
                      </td>
                  </tr>
              {% endfor %}
          </table>
          
          {% if current_page.has_previous %}
              <a href="/bookstore/all_book?page={{ current_page.previous_page_number }}">上一页</a>
          {% else %}
              上一页
          {% endif %}
          
          {#当前页显示页码,非当前页显示a标签#}
          {% for page_num in paginator.page_range %}
              {% if page_num == current_page.number %}
                  {{ page_num }}
              {% else %}
                  <a href="/bookstore/all_book?page={{ page_num }}">{{ page_num }}</a>
              {% endif %}
          {% endfor %}
          
          
          {% if current_page.has_next %}
              <a href="/bookstore/all_book?page={{ current_page.next_page_number }}">下一页</a>
          {% else %}
              下一页
          {% endif %}
          
          </body>
          </html>
          
          {#T层通过视图作为桥梁,拿到m层的数据进行渲染,使用if for等关键字的时候是{%  %},记得在最后end,使用视图传过来的参数时{{  }}#}
          
      4. 修改图书:

        1. 路由:path('update_book/<int:book_id>',views.update_book),使用path转换器把要修改的图书的id传给视图函数。

        2. 视图函数:

          @login_required
          def update_book(request,book_id):
              # 书是通过path转换器过来,也就是路由中会带着,比如:bookstore/update_book/1,结尾就是id
              #先获取指定书的信息(get的时候得查书的信息,因为得给render的页面传过去用于显示,post的时候也得查,因为修改单个数据是一查二改三保存)
              try:
                  book = Book.objects.get(id = book_id,is_active=True)
              except Exception as e:
                  print('--update book error is %s'%(e))
                  return HttpResponse('--The book is not existed')
              # get拿页面,post处理数据
              if request.method == 'GET':
                  return render(request,'bookstore/update_book.html',locals()) #得把书的信息传进去,因为得显示。
              elif request.method == 'POST':
                  price = request.POST['price']
                  market_price = request.POST['market_price']
                  #改
                  book.price = price
                  book.market_price = market_price
                  #保存
                  book.save()
                  #跳转回all_book页面,形成一个闭环
                  return HttpResponseRedirect('/bookstore/all_book')
          
        3. 模板文件:

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>更改书籍</title>
          </head>
          <body>
          {#action是负责表单的这个数据具体要提交到哪里去,还提交给这个地址#}
          <form action="/bookstore/update_book/{{ book_id }}" method="post">
              {% csrf_token %}
              <p>
                  title <input type="text" value="{{ book.title }}" disabled="disabled">
              </p>
              <p>
                  pub <input type="text" value="{{ book.pub }}" disabled="disabled">
              </p>
              <p>
                  price <input type="text" name="price" value="{{ book.price }}">
              </p>
              <p>
                  market_price <input type="text" name="market_price" value="{{ book.market_price }}">
              </p>
              <p>
                  <input type="submit" value="更新">  <a href="/bookstore/all_book">返回</a>
              </p>
          </form>
          </body>
          </html>
          
      5. 删除图书功能:

        1. 路由: path('delete_book',views.delete_book),
        2. 视图函数:
          @login_required
          def delete_book(request):
              #通过获取查询字符串book_id拿到要删除的book的id,将其is_active改为False,然后302跳转至all_book.
              # 先做视图,再做页面,再绑定路由
          
              #拿到要删除的书的id
              book_id = request.GET.get('book_id')
              if not book_id:
                  return HttpResponse('---请求异常')
              # 查询要删的书的信息
              try:
                  book = Book.objects.get(id=book_id,is_active=True)
              except Exception as e:
                  print('---delete book get error %s'%(e))
                  return HttpResponse('--The book id is error')
              #将其is_active改成False
              book.is_active = False
              book.save() #因为伪删除相当于修改,所以一查二改三保存,要记得保存
              #302跳转至all_book
              return HttpResponseRedirect('/bookstore/all_book')
          
      6. 增加图书功能:

        1. 路由:path('add_book',views.add_book)
        2. 视图函数:
          @login_required
          def add_book(request):
              if request.method == 'GET':
                  return render(request,'bookstore/add_book.html')
              elif request.method == 'POST':
                  title = request.POST['title']
                  pub = request.POST['pub']
                  price = request.POST['price']
                  market_price = request.POST['market_price']
          
                  Book.objects.create(title=title,pub=pub,price=price,market_price=market_price,is_active=True)
          
                  return HttpResponseRedirect('/bookstore/all_book')
          
        3. 模板文件:
          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>添加书籍</title>
          </head>
          <body>
          <form action="/bookstore/add_book" method="post">
              {% csrf_token %}
              <p>
                  标题:<input type="text" name="title">
              </p>
              <p>
                  出版社:<input type="text" name="pub">
              </p>
              <p>
                  定价:<input type="text" name="price">
              </p>
              <p>
                  零售价:<input type="text" name="market_price">
              </p>
              <input type="submit" value="保存">
          </form>
          </body>
          </html>
          
      7. 导出数据功能:

        1. 路由: path('output_csv',views.output_csv),
        2. 视图函数:
          @login_required
          def output_csv(request):
          
              # 在这里用filter(is_active=True)进行筛选,就能巧妙实现删除了数据时候,该数据不再被显示的要求
              all_book = Book.objects.filter(is_active=True)
          
              # 拿到当前的页码,没有的话就默认是1
              page_num = request.GET.get('page', 1)
          
              # 初始化paginator
              # 第一个参数是总的数据,第二个参数是每页显示的条数
              paginator = Paginator(all_book, 2)
              # 初始化具体页码对应的page对象,管具体的每一页
              current_page = paginator.page(int(page_num))
          
              response = HttpResponse(content_type='text/csv')
              response['Content-Disposition'] = 'attachment;filename="myBookOnPage%s"'%(page_num)
          
              writer = csv.writer(response)
          
              writer.writerow(['id','title','pub','price','market_price'])
          
              for book in current_page:
                  writer.writerow([book.id,book.title,book.pub,book.price,book.market_price])
          
              return response
          
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值