[TOC]

之前项目使用flask框架进行二次开发,发现代码写的很烂,然后这时学到了django,想用django重写代码

一 Django去除模板url硬编码

一个项目中通常包含多个app,视图函数可能会重名,我们需要使用含有命名空间的urls
app/urls.py

app_name = 'app'

urlpatterns = [
    path('', views.index, name='index')
]

模板中:index.html

<li><a href="{% url 'app:index' %}" style="font-size:15px">备件管理</a></li>

二 模板继承问题

模板继承时,最好将script放在最前面,否则写JavaScript有的时候不注意位置会报错

三 Django分页

使用Django 第三方拓展:django-pure-pagination + bootstrap

https://github.com/jamespacileo/django-pure-pagination

https://www.jianshu.com/p/fd810de0960d

3.1 视图函数使用方法

  1. 安装
    pip install django-pure-pagination
    

  1. 它注册到 INSTALLED_APPS

    INSTALLED_APPS = [
    
     'pure_pagination',  # 分页
     # ...其他
    ]
    

  1. 在settings.py中进行分页配置

    PAGINATION_SETTINGS = {
     'PAGE_RANGE_DISPLAYED': 5,
     'MARGIN_PAGES_DISPLAYED': 2,
    
     'SHOW_FIRST_PAGE_WHEN_INVALID': True,
    }
    

    image.png


  1. views.py ```python from pure_pagination import Paginator,PageNotAnInteger

def index(request): inventories = Inventory.get_all()

# 对所有的inventories进行分页
try:
    page = request.GET.get('page', 1)
except PageNotAnInteger:
    page = 1

# 第二个参数代表每一页显示的个数
p = Paginator(inventories, 15,request=request)
page_obj = p.page(page)
return render(request, 'inventory/index.html', context={'page_obj': page_obj})
(1)`inventories = Inventory.get_all()`中get_all()方法是对数据查询的优化,在模型类中已经定义了:
```python
class Inventory(models.Model):
    """其他代码"""

    @classmethod
    def get_all(cls):
        return cls.objects.all()

也可以不在模型类中定义,直接在view中使用未优化前的方法:inventories = Inventory.objects.all()

(2)首先在get方法中,首先获取到所有inventories 的实例,然后是一个异常处理,如果没有给page赋值,默认为1,即首页;异常处理类似。
(3) 然后,调用Paginator接口获得一个实例:p = Paginator(inventories, 15,request=request),Paginator接口构造函数如下:

def __init__(self, object_list, per_page, orphans=0,
             allow_empty_first_page=True):
    self.object_list = object_list
    self._check_object_list_is_ordered()
    self.per_page = int(per_page)
    self.orphans = int(orphans)
    self.allow_empty_first_page = allow_empty_first_page

这里一般传递三个参数,分别是:所有inventories 的实例,每一页显示inventories 的数量,request
(4)当我们拿到这个分页控制器实例后,调用page方法,加上page参数(由前端URL传递下来的)即可得到分页实例page_obj , http://127.0.0.1:8000/inventory/?page=8 ,(此处的page=8传递给get方法里的page),即

page_obj = p.page(page)

(5)将返回的分实例返回给前端模板

return render(request, 'inventory/index.html', context={'page_obj': page_obj})

  1. urls.py ```python from inventory import views

app_name = ‘inventory’

urlpatterns = [ path(‘’, views.index, name=’index’) ]


---

6. 前端页面**index.html**显示的逻辑大致如下:

1)先判断有没有前一页,如果有,则显示“前一页”这个按钮链接,否则不显示;<br />2)一个for循环判断当前页,如果是当前页我们就改变他的显示样式(比如给按钮挂个灰色什么,这里是class="active"),否则就是普通样式;<br />3)最后判断有没有下一页,如果有,则显示“下一页”这个按钮链接,否则不显示<br />下面是前端模板一个例子,是需要替换**<li>**部分,根据结构填充即可
```html
            <nav aria-label="Page navigation">
                <ul class="pagination pull-right">
                    <!-- 上一页 -->
                    {% if page_obj.has_previous %}
                    <li class="long"><a href="?{{ page_obj.previous_page_number.querystring }}" aria-label="Previous"><span
                            aria-hidden="true">&laquo;</span></a></li>
                    {% endif %}

                    <!-- 遍历页数 -->
                    {% for page in page_obj.pages %}
                    {% if page %}
                        {% ifequal page page_obj.number %}
                            <li class="active"><a href="?{{ page.querystring }}">{{ page }}</a></li>
                        {% else %}
                            <li><a href="?{{ page.querystring }}">{{ page }}</a></li>
                        {% endifequal %}
                    {% else %}
                        <li class="none"><a href="">...</a></li>
                    {% endif %}
                    {% endfor %}

                    <!--有下一页-->
                    {% if page_obj.has_next %}
                    <li class="long"><a href="?{{ page_obj.next_page_number.querystring }}" aria-label="Next"><span
                            aria-hidden="true">&raquo;</span></a></li>
                    {% endif %}
                </ul>
            </nav>

(1) 用到了bootstrap分页样式:https://v3.bootcss.com/components/#pagination
(2) Page常用属性和方法:

has_next:是否还有下一页。
has_previous:是否还有上一页。
next_page_number:下一页的页码。
previous_page_number:上一页的页码。
number:当前页。

最终样式:
image.png

3.2 类视图(官方推荐姿势)使用方法

views.py


from pure_pagination.mixins import PaginationMixin
from django.views.generic import ListView

class IndexView(PaginationMixin,ListView):
    # 模型
    model = Inventory
    # 模板
    template_name = 'inventory/index.html'
    # 一个多少条数据
    paginate_by = 15

当我们使用了类视图后,Django会自动的生成3个上下文对象:

  • paginator: 这是一个Paginator的实例,就是普通视图里面的paginator对象
  • page_obj: 这是一个Page的实例
  • is_paginated: 这是一个布尔值,表示是否已经分页

如果不加PaginationMixin。前端页面的页数不显示


urls.py

from inventory import views

urlpatterns = [
    path('', views.IndexView.as_view(), name='index')
]

其他的都不变

四 分页之跳转页面

在第三章的基础上,增加跳转页面的功能
image.png

  1. index.html新增代码
    <li style="font-size: 15px">跳至<input type="text" size="1" id="pageNum">页
     <button type="button" class="btn btn-default btn-sm" id="skipPage">
          <span class="glyphicon glyphicon-share-alt" aria-hidden="true"></span>
    </button>
    </li>
    
    上面使用了bootstrap

  1. js代码 ```javascript

    (1)使用jQuery为**id**是**skipPage**的**button**按钮绑定事件<br />(2)`page_obj.paginator.num_pages`是总页数<br />(3)_Location_._assign_() 方法会触发窗口加载并显示指定的URL的内容。<br />(4)`location.assign("{% url 'inventory:index' %}?page=" + pageNum)`:js方法来控制向后端发送GET请求,链接末尾加上pageNum,发送给后端,后端代码同第三章:
    ```python
    def index(request):
        inventories = Inventory.get_all()
        try:
            page = request.GET.get('page', 1)
        except PageNotAnInteger:
            page = 1
        p = Paginator(inventories, 15,request=request)
        page_obj = p.page(page)
        return render(request, 'inventory/index.html', context={'page_obj': page_obj})
    

    五 使用pure_pagination进行分页关键字查询

    image.png
    需求:在表单中输入查询关键字以及选择查询字段,将查询的数据返回,并可以进行分页
    此部分需要结合第三、四、十一章,使用了bootstrap表单验证功能

    1. 前端form表单

       <!--查询一栏-->
       <form action="{% url 'inventory:index'  %}" method="get">
           <div class="row" style="margin-left: auto;margin-right: 20px">
               <div class="panel panel-primary">
                   <div class="panel-heading">
                       <h3 class="panel-title">条件查询</h3>
                   </div>
                   <div class="panel-body">
                       <div style="display:inline-block;">
                           <div style="float:left;padding:6px;">
                               <span>关键字:</span>
                           </div>
                           <div style="float:left;">
                               <div class="form-group">
                                   <input id="keyword" name="keyword" class="form-control" style="width:200px;"
                                          placeholder="请输入关键字"/>
                               </div>
                           </div>
                           <div style="float:left;padding:6px;">
                               <span>查询字段:</span>
                           </div>
                           <div style="float:left;">
                               <div class="form-group">
                                   <select id="queryField" name="queryField" class="form-control" style="width:200px;">
                                       <option value="">请选择</option>
                                       <option value="m_name">物料名称</option>
                                       <option value="m_number">物料号</option>
                                       <option value="type">规格型号</option>
                                       <option value="person">责任人</option>
                                       <option value="parts_classlification">备件分类</option>
                                   </select>
                               </div>
                           </div>
      
                           <div style="float:left;margin-left:20px;">
                               <div class="form-group">
                                   <button type="submit" id="query" class="btn btn-primary">查询</button>
      
                               </div>
                           </div>
                       </div>
                   </div>
               </div>
           </div>
       </form>
      

      使用bootstrap的表单验证功能,具体请看十一章(https://www.yuque.com/u1046159/lp12n4/pn8619#bXfaP
      form表单将含有name属性的元通过get方法传递给后台函数index

    2. index.py

      def index(request):
       try:
           page = request.GET.get('page', 1)
      
       except PageNotAnInteger:
           page = 1
      
       keyword = request.GET.get('keyword')
       query_field = request.GET.get(('queryField'))
       if keyword and query_field is not None:
           inventories = Inventory.get_all().filter(**{query_field + '__contains': keyword})
       else:
           inventories = Inventory.get_all()
       p = Paginator(inventories, 15, request=request)
      
       page_obj = p.page(page)
      
       return render(request, 'inventory/index.html', context={'page_obj': page_obj})
      

      分页代码和第三章分页代码相似,只是添加了处理逻辑:如果获取的前端查询参数不为空(说明用于点击了查询功能,那么这时候返回查询的结果,即对数据库数据进行过滤【如果用户点击查询,传递给后端的参数一定不为空,因为使用了bootstrap进行了表单验证,一定不为空才让点击】);如果后台获取到的查询参数为空,那么说明用户没有使用查询功能,返回数据库所有数据

    查询代码

        if keyword and query_field is not None:
            inventories = Inventory.get_all().filter(**{query_field + '__contains': keyword})
    
    • get_all()方法是对模型查询的优化,定义在模型类中: ```python class Inventory(models.Model): “””库存类”””

    @classmethod
    def get_all(cls):
        return cls.objects.all()
    
    
    - 不使用get_all()方法,可以使用:
    ```python
    inventories = Inventory.objects.all().filter(**{query_field + '__contains': keyword})
    

    没有使用查询功能

        else:
            inventories = Inventory.get_all()
    

    六 使用JavaScript触发bootstrap的模态框

    https://segmentfault.com/a/1190000040463838

    需求:为一个按钮绑定事件,点击后bootstrap弹窗提示
    html页面

    <button id="skipPage>点击</button>
    
    
    <div class="modal" id="mymodal">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <button type="button" class="close" data-dismiss="modal"><span
                            aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
                    <h4 class="modal-title">提示</h4>
                </div>
                <div class="modal-body">
                    <p>请输入正确的页码!</p>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-default" data-dismiss="modal">确认</button>
                </div>
            </div>
        </div>
    </div>
    
    • <div class="modal-body">里面可以放一些提示信息,如放警示框
      <div class="modal-body">
      <div class="alert alert-danger" role="alert"><p>请输入正确的页码!</p></div>
      </div>
      

    JavaScript

    <script type="text/javascript">
      $(function () {
      $("#skipPage").click(function () {
          $("#mymodal").modal()
        }
      })
    
    })
    </script>
    

    image.png

    七 jQuery获取点击元素的父元素id

    html

    <ul class="nav navbar-nav">
      <li id="t1"><a href="">备件管理</a></li>
      <li id="t2"><a href="">库存汇总</a></li>
      <li id="t3"><a href="">入库管理</a></li>
      <li id="t4"><a href="">出库管理</a></li>
    </ul>
    

    jquery

    <script>
      $(function () {
                  $(document).click(function (e) {
                      var li_id = $(e.target).parent().attr('id')
                      alert(li_id)
    
                  })
              })
    
    </script>
    

    八 Django 使用外部JS文件导致模板变量和{% url %}失效的问题

    https://blog.csdn.net/qq_41475058/article/details/103435763
    解决方法:能不用模板变量就尽量不用,例如有些只能从页面上获取就直接用jquery从页面上获取吧,如下第一张图。例如ajax里面的url这种,可以直接使用路径/restartdo/,如果真的想使用url变量的话(怕资源更改麻烦),可以在html中将url的值定义为一个变量,然后在JS文件中将ajax中的url设为这个变量。入下第二三张图。大概就这样吧,目前没发现更好的方法,JS能不用模板变量就尽量不用吧。

    九 Django模糊查询(字段名为变量)

    参考:https://blog.csdn.net/w710537643/article/details/108520484

    需求:前端使用ajax将查询参数传递给django后台,现在想要实现模糊查询,查询某个数据库字段等于查询参数,原SQL语句样例:
    image.png

    SELECT * FROM "inventory" where type LIKE '%16A%'
    
    • type 是数据库字段名,16A 是关键字

    Django模糊查询代码:

    keyword = query_data['keyword']
    queryField = query_data['queryField']
    page_obj = Inventory.objects.filter(**{queryField + '__contains':keyword})
    
    • 即字段名和关键字都是变量

    Django视图函数完整代码:

    def index(request):
    
        if request.method == 'POST':
            # 接收ajax传递过来的数据,是字典格式
            query_data = request.POST
            keyword = query_data['keyword']
            queryField = query_data['queryField']
            page_obj = Inventory.objects.filter(**{queryField + '__contains':keyword})
    

    之前使用flask查询代码:

        condition = {field: q}
        if field == "m_name":
            condition = Inventory.m_name.like('%%%s%%' % q)
        elif field == "m_number":
            # condition = Inventory.m_number.like('%%%s%%' % q)
            search = "%{}%".format(q)
            condition = Inventory.m_number.like(search)
        elif field == "person":
            condition = Inventory.person.like('%%%s%%' % q)
        elif field == "parts_classlification":
            condition = Inventory.parts_classlification.like('%%%s%%' % q)
        elif field == "type":
            condition = Inventory.type.like('%%%s%%' % q)
        else:
            condition = Inventory.id
    

    发现改造后,简洁许多

    10 django+ajax使用

    和前端交互全部使用JSON,如何将数据库查询结果转换成JSON格式 https://blog.csdn.net/EverXerxes/article/details/84316645

    前端

    function edit(obj){
      var $td= $(obj).parents('tr').children('td');
      var m_number = $td.eq(1).text();
      console.log(m_number);
      data = {
        'm_number':m_number
      };
      $.ajax({
        type:'GET',
        url:"{% url 'inventory:edit' %}",
        data:data,
        dataType:'json',
        success:function (data){
          console.log(data)
        },
        error:function () {alert('数据返回错误!')}
      })
    
    }
    

    django后端

    方法一:(django自带的serializers序列化model)(推荐使用此方法)

    def edit(request):
        # ajax传值
        m_number = request.GET.get('m_number')
        inventory= Inventory.objects.filter(m_number=m_number)
        json_data = serializers.serialize('json', inventory)
        return HttpResponse(inventory, content_type="application/json")
    

    返回的数据格式:

    [
        {
            "model": "inventory.inventory",
            "pk": 1,
            "fields": {
                "type": "KNB32CM55",
                "m_number": "Pow-001",
                "m_name": "插接箱",
                "m_cate": "电气",
                "kuwei": "0902C1",
                "quantity": 3,
                "limit": 16,
                "life_time": 0,
                "batch_number": 0,
                "price": 500,
                "total_price": 2500,
                "supply_period": 45,
                "scarp": "",
                "parts_classlification": "Spare parts",
                "person": "Yao Sheng",
                "comments": "301、302洁净室"
            }
        }
    ]
    

    想要的数据在fields字段里面,有点难受的是,每条数据对象包含 fields,model,pk三个对象,分别代表字段、模型、主键,我更想要一个只包含所有字段的字典对象。虽然也可以处理,但还是省点性能,交给前端解析吧。

    ajax使用
    m_number = data[0]['fields']['m_number']

    $.ajax({
      type:'GET',
      url:"{% url 'inventory:edit' %}",
      data:data,
      dataType:'json',
      async: false,
      success:function (data) {
        m_number = data[0]['fields']['m_number']
        console.log(m_number)
      },
      error:function () {alert('数据返回错误!')}
    })
    

    方法二:(model_to_dict方法)

    def edit(request):
        # 获取前端传过来的值
        m_number = request.GET.get('m_number')
        inventory= Inventory.objects.filter(m_number=m_number).first()        # 返回单个对象
        # 将对象转化为字典
        inventory = model_to_dict(inventory)
    
        return HttpResponse(json.dumps(inventory), content_type="application/json")
    
    • Inventory.objects.filter(m_number=m_number).first():返回单个对象
    • model_to_dict(inventory):对象转化为字典

    返回的数据格式:

    {
        "id": 1,
        "type": "KNB32CM55",
        "m_number": "Pow-001",
        "m_name": "插接箱",
        "m_cate": "电气",
        "kuwei": "0902C1",
        "quantity": 3,
        "limit": 16,
        "life_time": 0,
        "batch_number": 0,
        "price": 500,
        "total_price": 2500,
        "supply_period": 45,
        "scarp": "",
        "parts_classlification": "Spare parts",
        "person": "Yao Sheng",
        "comments": "301、302洁净室"
    }
    

    ajax使用
    m_number = data['m_number']

    $.ajax({
      type:'GET',
      url:"{% url 'inventory:edit' %}",
      data:data,
      dataType:'json',
      async: false,
      success:function (data) {
        m_number = data['m_number']
        console.log(m_number)
      },
      error:function () {alert('数据返回错误!')}
    })
    

    11 bootstrap表单

    11.1 表单验证bootstrapValidator

    https://www.jianshu.com/p/756b225d480d https://www.cnblogs.com/huangcong/p/5335376.html

    1. 首先导入包 ```html
    
    2. 如果想对某一个字段添加验证规则,需要<div class="form-group"></div>包裹,input标签必须有name值,此值为验证匹配的字段。其实就是要符合bootstrap表单结构
    ```html
     <form action="" method="get">
         <div class="form-group">
           <input id="keyword" name="keyword" class="form-control" style="width:200px;"
                  placeholder="请输入关键字"/>
         </div>
    
         <div class="form-group">
           <select id="queryField" name="queryField" class="form-control" style="width:200px;">
             <option value="">请选择</option>
             <option value="m_name">物料名称</option>
             <option value="m_number">物料号</option>
             <option value="type">规格型号</option>
             <option value="person">责任人</option>
             <option value="parts_classlification">备件分类</option>
           </select>
         </div>
    
         <div class="form-group">
           <button type="submit" id="query" class="btn btn-primary">查询</button>
         </div>
    </form>
    
    1. JavaScript

    notEmpty 验证字段不为空

    <script>
          $(function () {
            $('form').bootstrapValidator({
                feedbackIcons: {
                    valid: 'glyphicon glyphicon-ok',
                    invalid: 'glyphicon glyphicon-remove',
                    validating: 'glyphicon glyphicon-refresh'
                },
                fields: {
                    keyword: {
                        validators: {
                            notEmpty: {
                                message: '请输入要查询的关键字'
                            }
                        }
                    },
                    queryField: {
                        validators: {
                            notEmpty: {
                                message: '请选择要查询的字段'
                            }
                        }
                    }
                }
            });
        });
    </script>
    

    image.png


    11.2 表单重置

    需求:点击重置按钮,恢复模态框中表单未修改前的数据(向模态框中form表单传值请看第13章:https://www.yuque.com/u1046159/lp12n4/pn8619#vFUuD


    11.3 模态框关闭后,销毁表单验证

    模态框里面嵌套表单,表单验证后,关闭模态框,再次打开模态框,之前的表单验证规则还在

    首次打开模态框,表单验证
    image.png
    此时关闭模态框,再次打开模态框,验证规则还在
    image.png
    解决办法:https://blog.csdn.net/weixin_40886648/article/details/83379069

    //去除模态框之前的表单验证
    $('#modifymodal').on('hide.bs.modal', function () {
      $('#modifyForm').bootstrapValidator('resetForm');
    });
    

    完整案例:

    
    // 弹出模态框
    $("#modifymodal").modal();
    
    
    //去除模态框之前的表单验证
    $('#modifymodal').on('hide.bs.modal', function () {
      $('#modifyForm').bootstrapValidator('resetForm');
    });
    
    
    
    //表单验证
    $(function () {
            $('#modifyForm').bootstrapValidator({
                message: "this is not valid field",
                feedbackIcons: {
                    valid: 'glyphicon glyphicon-ok',
                    invalid: 'glyphicon glyphicon-remove',
                    validating: 'glyphicon glyphicon-refresh'
                },
                fields: {
                    quantity: {
                        validators: {
                            notEmpty: {
                                message: '库存数量不能为空'
                            },
                            digits: {
                                message: '库存数量必须为整数'
                            }
                        }
                    },
                    limit: {
                        validators:{
                            notEmpty: {
                                message: '库存数量不能为空'
                            },
                            digits: {
                                message: '库存数量必须为整数'
                            }
                        }
                    }
                }
            })
        });
    

    image.png

    12 bootstrap table api使用

    1. 引用文件

      <link rel="stylesheet" href="https://unpkg.com/bootstrap-table@1.15.3/dist/bootstrap-table.min.css">
      <script src="https://unpkg.com/bootstrap-table@1.15.3/dist/bootstrap-table.min.js"></script>
      <script src="https://unpkg.com/bootstrap-table@1.15.3/dist/locale/bootstrap-table-zh-CN.min.js"></script>
      
    2. 页面定义table

      <table id="inventoryTable"></table>
      
    3. jQuery

       $("#inventoryTable").bootstrapTable({
           search: true, //获得一个搜索框
           striped: true, //开启斑马线
           showColumns: true, //获得一个能选择显示某些列的按钮
           showRefresh: true, //获得一个刷新数据按钮
       });
      

      image.png

      13 获取表格当前行数据+向bootstrap模态框传值

      需求:点击表格操作按钮,获取当前行数据,传入bootstrap的模态框中,弹出模态框(并进行表单验证),修改数据后,将数据传递给django后台
      image.png

    4. 表格 ```html

      {% for inventory in page_obj.object_list %} {% endfor %}
      id 物料号 物料名称 规格型号 物料分类 库位 库存数量 最低库存数量
      {{ inventory.id }} {{ inventory.m_number }} {{ inventory.m_name }} {{ inventory.type }} {{ inventory.m_cate }} {{ inventory.kuwei }} {{ inventory.quantity }} {{ inventory.limit }}
    表格中数据是从Django后台返回的
    
    2. 模态框代码
    ```html
    <!--修改按钮弹出框-->
    <div class="modal" id="modifymodal">
        <div class="modal-dialog modal-dialog-centered modal-dialog-scrollable">
            <div class="modal-content">
                <div class="modal-header">
                    <button type="button" class="close" data-dismiss="modal"><span
                            aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
                    <h4 class="modal-title">备件信息修改</h4>
                </div>
                <form action="" method="get" class="form-horizontal">
                    <div class="modal-body">
                        <!--id-->
                        <div class="form-group">
                            <label class="col-sm-2 control-label">id</label>
                            <div class="col-sm-10">
                                <input type="text" class="form-control" id="id" disabled value="">
                            </div>
                        </div>
                        <!--物料号-->
                        <div class="form-group">
                            <label class="col-sm-2 control-label">物料号</label>
                            <div class="col-sm-10">
                                <input type="text" class="form-control" id="m_number" value="" disabled>
                            </div>
                        </div>
    
                          <!--其他字段-->
                  </div>
                </form>
    
                <div class="modal-footer">
                    <button type="button" class="btn btn-default" data-dismiss="modal">确认</button>
                </div>
            </div>
        </div>
    </div>
    

    方法一:jQuery获取

    $(document).on('click','#modify',function () {
    
            // 获取表格当前行数据
            $("#inventoryTable tbody").on("click", "tr", function () {
                var data = new Array();
                var td = $(this).find("td");
                for (var i = 0; i < td.length - 1; i++) {
                    data.push(td.eq(i).text());
                }
                console.log(data);
                // 向模态框中插值
                $("#id").val(data[0]);
                $("#m_number").val(data[1]);
                $("#m_name").val(data[2]);
                $("#type").val(data[3]);
                $("#m_cate").val(data[4]);
                $("#kuwei").val(data[5]);
                $("#quantity").val(data[6]);
                $("#limit").val(data[7]);
                $("#parts_classlification").val(data[8]);
                $("#person").val(data[9]);
                $("#comments").val(data[10]);
    
            });
            // 弹出模态框
            $("#modifymodal").modal();
    
        });
    
    • td.length-1:取出操作列中的修改、出库申请文字,只获取前面内容

    这种情况下,如果希望有个表单重置按钮,时不能恢复未修改前的数据的!

    获取到的数据
    image.png
    效果图:
    image.png

    使用这种方法,发现一个bug,页面刷新后,首次点击,模态框中是没有数据的,只有再次点击,模态框才有数据

    首次点击
    image.png
    再次点击
    image.png

    暂时没有找到解决方法,使用原生js可解决这个问题!

    <button id="modify" type="button" class="btn btn-primary btn-sm" onclick="modify()">修改</button>
    
        // 修改功能
        function modify(){
            // 获取表格当前行数据
            $("#inventoryTable tbody").on("click", "tr", function () {
                var data = new Array();
                var td = $(this).find("td");
                for (var i = 0; i < td.length - 1; i++) {
                    data.push(td.eq(i).text());
                }
                console.log(data);
                // 向模态框中插值
                $("#id").val(data[0]);
                $("#m_number").val(data[1]);
                $("#m_name").val(data[2]);
                $("#type").val(data[3]);
                $("#m_cate").val(data[4]);
                $("#kuwei").val(data[5]);
                $("#quantity").val(data[6]);
                $("#limit").val(data[7]);
                $("#parts_classlification").val(data[8]);
                $("#person").val(data[9]);
                $("#comments").val(data[10]);
    
            });
            // 弹出模态框
            $("#modifymodal").modal();
        }
    

    方法二 :ajax

    table

    <table>
                <thead>
                <tr>
    
                    <th scope="col">备件类型</th>
                    <th scope="col">物料责任人</th>
                    <th scope="col">备注</th>
                    <th scope="col">操作</th>
                </tr>
                </thead>
                <tbody>
                {% for inventory in page_obj.object_list %}
                <tr>
                    <td>{{ inventory.parts_classlification }}</td>
                    <td>{{ inventory.person }}</td>
                    <td>{{ inventory.comments }}</td>
                    <td>
                        <button id="modify" type="button" class="btn btn-primary btn-sm" onclick="edit(this)">修改</button>
                        <button id="apply" type="button" class="btn btn-primary btn-sm" style="margin-left: 3px">出库申请
                        </button>
                    </td>
    
                </tr>
                {% endfor %}
                </tbody>
            </table>
    
    • 给修改按钮绑定点击事件:onclick="edit(this)",获取当前表格关键字,ajax将值传给后端,django后端查询后,返回给ajax,然后使用jQuery为=赋值

    ajax

        // 修改功能
        function edit(obj){
            var $td= $(obj).parents('tr').children('td');
            var m_number = $td.eq(1).text();
            console.log(m_number);
            data = {
                'm_number':m_number
            };
            $.ajax({
                type:'GET',
                url:"{% url 'inventory:edit' %}",
                data:data,
                dataType:'json',
                 async: false,
                success:function (data) {
    
                    $("#id").val(data['id']);
                    $("#m_number").val(data['m_number']);
                    $("#m_name").val(data['m_name']);
                    $("#type").val(data['type']);
                    $("#m_cate").val(data['m_cate']);
                    $("#kuwei").val(data['kuwei']);
                    $("#quantity").val(data['quantity']);
                    $("#limit").val(data['limit']);
                    $("#parts_classlification").val(data['parts_classlification']);
                    $("#person").val(data['person']);
                    $("#comments").val(data['comments']);
    
                },
                error:function () {alert('数据返回错误!')}
            });
            // 弹出模态框
            $("#modifymodal").modal();
    
    
        }
    

    14 django更新数据库数据

    需求:前端form表单将修改后的数据,使用post方法传递给后端,django后端接收前端的请求参数,在数据库查询该行数据,更改数据

    14.1 方法一

    使用以下方法

    inventory = Inventory.objects.get(id=id)
    
    inventory.m_name = m_name
    # ...
    
    inventory.save()
    

    注意: 对于form表单, 将{% csrf_token %} 添加到您创建的每个使用 POST 提交数据的 Django 模板中。这将减少恶意用户劫持表单的可能性。

    <form action="{% url 'inventory:edit' %}" method="post" >
      {% csrf_token %}
    </form>
    

    id = request.POST.get('id')

    def edit(request):
        if request.method == 'POST':
            id = request.POST.get('id')
            # ...
    

    还有一种方法 :id = request.POST['id']

    重要: 虽然您也可以通过请求直接访问表单数据(例如request.POST[‘renewal_date’] 或 request.GET[‘renewal_date’](如果使用 GET 请求),但不建议这样做。清理后的数据是无害的、验证过的、并转换为 Python 友好类型。

    当使用第二种方法时,如果表单字段设置了disabled(input控件被忽略,没有提交内容到后台),会报错:
    https://blog.csdn.net/xiaotuwai8/article/details/110958441

    <input type="text" class="form-control" id="id" name="id" disabled value="">
    

    报错:

    django.utils.datastructures.MultiValueDictKeyError: 'id'
    

    更新数据库数据

    def edit(request):
        if request.method == 'POST':
            id = request.POST.get('id')
            m_name = request.POST.get('m_name')
            # 其他
    
    
            inventory = Inventory.objects.get(id=id)
    
            inventory.m_name = m_name
            # ...
    
            inventory.save()
    
            return redirect('inventory:index')
    
    • 修改先要查找,然后再修改
    • 一定要使用.save()方法,否则数据不会保存到数据库,修改不成功

      14.2 方法二

      使用: ```python m_number = request.POST.get(‘m_number’)

    Inventory.objects.filter(m_number=m_number).update( m_name=m_name, type=type, m_cate=m_cate, kuwei=kuwei, quantity=quantity, limit=limit, parts_classlification=parts_classlification, person=person, comments=comments )

    
    - **update**只能结合**filter**一起用
    - `m_number=m_number`:前面是数据库字段,后面是赋值的变量名(即要更改的数据)
    
    方法一适合更新一条数据,也只能更新一条数据,当只有一条数据更新时推荐使用此方法<br />方法二适合更新一批数据,类似于mysql语句update user set username='nick' where id = 1
    
    <a name="qV1gq"></a>
    # 15 jQuery给表格每一行按钮绑定点击事件不生效
    表格
    ```html
            <table>
                <thead>
                    <tr>
                        <th scope="col">物料号</th>
                          //其他
                    </tr>
                </thead>
                <tbody>
                {% for inventory in page_obj.object_list %}
                <tr>
                    <td>{{ inventory.m_number }}</td>
                      //其他
                    <td>
                        <button id="modify" type="button" class="btn btn-primary btn-sm">修改</button>
                    </td>
    
                </tr>
                {% endfor %}
                </tbody>
            </table>
    

    为修改按钮绑定点击事件,只有表格第一行的修改按钮点击有反应,其他行修改按钮点击没反应,也没报错,下面是jQuery代码:
    image.png

    $('#modify').click(function () {
      alert('test')
    })
    

    解决方法:使用on

    $(document).on('click','#modify',function () {
      alert('test')
    })
    
    • on方法的第一个参数为click,第二个是按钮id,第三个是function

    原因:https://www.cnblogs.com/leiting/p/9323539.html

    16 django中外键ForeignKey

    https://zhuanlan.zhihu.com/p/25393972

    有两张表,一张用户表,一张角色表,用户表中字段role_id是角色表中的主键role_id

    模型类

    class User(models.Model):
        """用户"""
        domain_name = models.CharField(max_length=125)
        real_name = models.CharField(max_length=125)
        department = models.CharField(max_length=125)
        email = models.CharField(max_length=125)
        role_id = models.ForeignKey('Role',on_delete=models.CASCADE)
        status = models.IntegerField()
        first_login = models.IntegerField()
    
    
    
    class Role(models.Model):
        '''角色'''
        role_id = models.AutoField(primary_key=True)
        name = models.CharField(max_length=125)
        description = models.CharField(max_length=125)
        status = models.IntegerField()
    

    ForeignKey ( othermodel, on_delete, _options _)**

    • 有两个必选参数,第一个参数为关联的表格(主表)在默认的情况下,外键储存的是主表的主键(Primary key),上述案例user表中role_id会自动关联role表中主键role_id;第二个参数:CASCADE,当主表的字段被删除时,和他有关的子表字段也会被删除

    image.png

    数据库迁移后,两张表结构
    user表
    image.png
    role表
    image.png

    17 django会话(session)

    https://www.liujiangblog.com/course/django/168 https://docs.djangoproject.com/zh-hans/3.2/topics/http/sessions/

    需求:用户登录时获取当前用户名,从数据库中查询用户名对应的信息,存入session中

    # 首页
    def index(request):
    
        user = User.objects.filter(domain_name='zxy').first()
        user = model_to_dict(user)
        request.session['domain_name'] = 'zxy'
        request.session['role_id'] = user['role_id']
        request.session['status'] = user['status']
        request.session['first_login'] = user['first_login']
    
    • 为了方便测试,设置了一个假的用户名 zxy

    当会话中间件启用后,传递给视图request参数的HttpRequest对象将包含一个session属性,这个属性的值是一个类似字典的对象。你可以在视图的任何地方读写request.session属性

    • request.session['domain_name'] = 'zxy : 设置值
    • request.session['domain_name']:取值