gin49sz

导航

 

15.Ajax请求

浏览器向网站发送请求时:

  • GET
  • POST

特点:页面会刷新。

也可以基于Ajax向后台发送请求(偷偷发送请求)

  • 依赖jQuery

  • 编写ajax

    $.ajax({
        url:"发送的地址",
        type:"post",
        data:{
            n1:123,
            n2:456,
        } 
        success:function(res){
        console.log(res)
    	}
    })
    

15.1GET请求

<script type="text/javascript">
    function clickMe() {
        $.ajax({
            url:'/task/ajax/',
            type:"get",
            data:{
                n1:123,
                n2:456,
            }, 
            success:function (res) {
                console.log(res);
            }
        })
    }
</script>
def task_ajax(request):
    print(request.GET)
    return HttpResponse("成功了")

15.2POST请求

<script type="text/javascript">
    function clickMe() {
        $.ajax({
            url:'/task/ajax/',
            type:"post",
            data:{
                n1:123,
                n2:456,
            }, 
            success:function (res) {
                console.log(res);
            }
        })
    }
</script>
@csfr_exempt
def task_ajax(request):
    print(request.POST)
    return HttpResponse("成功了")

15.3使用jQuery绑定事件

{% extends "layout.html" %}

{% block title %}
任务管理
{% endblock %}
{% block css %}
<style>

</style>
{% endblock  %}
{% block content %}
    <div class="container">
        <h1>任务列表</h1>
        <h3>示例1</h3>
        <input type="button" class="btn btn-primary" value="点击" id="btn1">
    </div>
{% endblock  %}
{% block js %}
    <script type="text/javascript">
        $(function () {  
            // 页面框架加载完成之后代码自动执行
            bindBtn1Event();

        })


        //绑定在btn1上的事件
        function bindBtn1Event() {
            $("#btn1").click(function () {
                $.ajax({
                    url:'/task/ajax/',
                    type:'post',
                    data:{
                        n1:123,
                        n2:456,
                    },
                    success: function (res) {
                        console.log(res);
                    }
                });
            })
        }
    </script>
{% endblock  %}

15.4 ajax请求的返回值

一般不会返回页面,而是一个JSON格式

{% block content %}
<h3>示例1</h3>
<input type="button" class="btn btn-primary" value="点击" id="btn1">
{% endblock %}
{% block js %}
    <script type="text/javascript">
        $(function () {  
            // 页面框架加载完成之后代码自动执行
            bindBtn1Event();

        })
        //绑定在btn1上的事件
        function bindBtn1Event() {
            $("#btn1").click(function () {
                $.ajax({
                    url:'/task/ajax/',
                    type:'post',
                    data:{
                        n1:123,
                        n2:456,
                    },
                    dataType:"JSON",//通过逆序列化将字典变成JSON文件,之后可以通过.key获取值
                    success: function (res) {
                        console.log(res.status);
                        console.log(res.data);
                    }
                });
            })
        }
    </script>
{% endblock %}
# 用装饰器直接跳过csfr_token
@csrf_exempt
def task_ajax(request):
    """Ajax"""
    data_dict = {"status": True, "data": [11, 22, 33, 44]}
    # 对json格式进行dump生成字典,否则输出为object[JSON]
    json_string = json.dumps(data_dict)
    # return JsonResponse(data_dict)
    return HttpResponse(json_string)

含有input框的请求

<h3>示例2</h3>
<input type="text" id="txtUser" placeholder="姓名">
<input type="number" id="txtAge" placeholder="年龄">
<input type="submit" class="btn btn-primary" value="提交" id="btn2">
<script>
//绑定在btn2上的事件
function bindBtn2Event() {
    $("#btn2").click(function () {
        $.ajax({
            url:'/task/ajax/',
            type:'post',
            //获取input的值,提交到后台
            data:{
                n1:$("#txtUser").val(),
                n2:$("#txtAge").val(),
            },
            dataType:"JSON",//通过逆序列化将字典变成JSON文件,之后可以通过.key获取值
            success: function (res) {
                console.log(res.status);
                console.log(res.data);
            }
        });
    })
}
</script>

含有多个input框 - 使用form + name

<h3>示例3</h3>
<form id="form3">
    <input type="text" name="user" placeholder="姓名">
    <input type="text" name="age" placeholder="年龄">
    <input type="text" name="email" placeholder="邮件">
    <input type="text" name="more" placeholder="更多">
</form>
<input type="submit" class="btn btn-primary" value="提交" id="btn3">
<script>
//绑定在btn3上的事件
function bindBtn3Event() {
    $("#btn3").click(function () {
        $.ajax({
            url:'/task/ajax/',
            type:'post',
            //获取input的值,提交到后台
            data:$("#form3").serialize(),
            dataType:"JSON",//通过逆序列化将字典变成JSON文件,之后可以通过.key获取值
            success: function (res) {
                console.log(res.status);
                console.log(res.data);
            }
        });
    })
}
</script>

15.5通过Ajax添加数据

{% block content %}
    <div class="container">
        <div class="panel panel-default">
            <div class="panel-heading">表单</div>
            <div class="panel-body"> 
                <form id="formAdd" novalidate>
                    <div class="col-xs-6">
                        <div class="clearfix">
                            <div class="form-group" style="position:relative;">
                                <label>{{ form.title.label }}</label>
                                {{ form.title }}
                                <span class="error_msg" style="color:red;position:absolute;"></span>
                            </div>
                            <div class="form-group" style="position:relative;">
                                <label>{{ form.level.label }}</label>
                                {{ form.level }}
                                <span class="error_msg" style="color:red;position:absolute;"></span>
                            </div>
                            <div class="form-group" style="position:relative;">
                                <label>{{ form.user.label }}</label>
                                {{ form.user }}
                                <span class="error_msg" style="color:red;position:absolute;"></span>
                            </div>
                            <button id="btnAdd" type="button" class="btn btn-primary">提 交</button>
                        </div>
                    </div>
                    <div class="col-xs-6">
                        <div class="clearfix">
                            <div class="form-group" style="position:relative;">
                                <label>{{ form.detail.label }}</label>
                                {{ form.detail }}
                                <span class="error_msg" style="color:red;position:absolute;"></span>
                            </div>
                        </div>
                    </div>
                </form>
            </div>
        </div>
    </div>
{% endblock  %}
{% block js %}
    <script type="text/javascript">
        $(function () {  
            // 页面框架加载完成之后代码自动执行
            btnAddEvent()

        })

        //绑定在btnAdd上的事件
        function btnAddEvent() {
            $("#btnAdd").click(function () {
                $(".error_msg").empty();//先将错误信息置为空

                $.ajax({
                    url:'/task/add/',
                    type:'post',
                    data:$("#formAdd").serialize(),
                    dataType:"JSON",
                    success:function (res) {
                        if(res.status){
                            alert("添加成功")
                        }else{
                            $.each(res.error, function (name, data){
                                console.log(name, data);
                                $("#id_" + name).next().text(data[0])
                            })
                        }
                    }
                })
            })            
        }

        
    </script>
{% endblock  %}

views -> task.py

@csrf_exempt
def task_add(request):
    """添加任务"""
    print(request.POST)
    # <QueryDict: {'title': [''], 'level': ['1'], 'user': [''], 'detail': ['']}>

    # 1.用户发送过来的数据进行校验(ModelForm)
    form = TaskModelForm(data=request.POST)
    if form.is_valid():
        form.save()
        # 不能使用redirect跳转,因为ajax在发送时候不修改页面, 可以返回一个json给页面,然后页面根据对应的内容进行操作
        status_dict = {"status": True}
        return HttpResponse(json.dumps(status_dict))
    status_dict = {"status": False, "error": form.errors}
    return HttpResponse(json.dumps(status_dict, ensure_ascii=False))

utils -> modelform.py

class TaskModelForm(BootStrapModelForm):
    class Meta:
        model = models.Task
        fields = ["title", "level", "user", "detail"]
        widgets = {
            # "detail":forms.TextInput,     text框
            # "detail": forms.Textarea,     textarea框
        }

16.知识点回顾

  • 创建Django项目
django-admin startproject xxx
  • 创建APP & 注册APP
python manage.py startapp yyy
INSTALLED_APP = {
    ...
    'app01.apps.App01Config'
}

不注册APP则无法创建models.py中的表到数据库中

  • 配置静态文件路径 & 模板的路径

  • 配置数据库相关的操作

    • 第三方模块(django3版本)

      pip install mysqlclient
      
    • 先去MySQL中创建一个数据库

    • 配置和数据库的连接 settings.py文件

    • 在app下的models.py中编写数据库文件(如果使用sqlite3数据库,直接从这一步开始即可)

    • 执行makemigrations和migrate

  • urls.py -> 路由 URL和函数的对应关系

  • views.py 视图函数 编写业务逻辑

  • templates目录, 编写HTML模板 模板语法、继承、

  • ModelForm & Form组件,在开发增删改查时候

    • 生成HTML标签(生成默认值)
    • 请求数据进行校验(钩子方法, 正则)
    • 保存到数据库(ModelForm)
    • 获取错误请信息(ErrorValidation 和 add_errors)
  • Cookie和Session,保存用户的登录信息

  • 中间件,基于中间件实现用户认证,基于:process_request

  • ORM操作

    mdoels.User.objects.filter(id="xxx")
    
  • 分页组件的应用

订单

  • 表结构

        class Order(models.Model):
            """订单"""
    
            oid = models.CharField(verbose_name="订单号", max_length=64)
            title = models.CharField(verbose_name="名称", max_length=32)
            price = models.IntegerField(verbose_name="价格")
    
            status_choices = (
                (1, "待支付"),
                (2, "已支付"),
            )
            status = models.SmallIntegerField(
                verbose_name="状态", choices=status_choices, default=1
            )
            admin = models.ForeignKey(
                verbose_name="管理员", to="Admin", on_delete=models.CASCADE
            )
    

想要去数据库中获取数据时:对象/字典

# 对象当前行的所有数据
row_object = models.Order.objects.filter(id=uid).first()
row_object.id
row_object.title
# 取某几列,字典类(因为json)
row_object = models.Order.objects.filter(id=uid).values("id","title").first()
# queryset = [obj, obj, obj]
queryset = models.Order.objects.all()

# queryset = [{"id":xx, "title":yy }, {}, {}]
queryset = models.Order.objects.all().values("id", "title")
#queryset = [(), (), ()]
queryset = models.Order.objects.all().values_list("id"m "title")

views -> order.py

from django.shortcuts import render
from django.views.decorators.csrf import csrf_exempt
from django.http import JsonResponse
from django import forms
import random
from datetime import datetime

from app01 import models
from app01.utils.bootstrap_form import BootStrapModelForm
from app01.utils.pagination import Pagination


class OrderModelForm(BootStrapModelForm):

    class Meta:
        model = models.Order
        # fields = "__all__"
        # 订单号由系统生成
        exclude = ["oid", "admin"]


def order_list(request):
    queryset = models.Order.objects.all().order_by("-id")
    page_object = Pagination(request, queryset)

    form = OrderModelForm()

    return render(
        request,
        "order_list.html",
        {
            "form": form,
            "queryset": page_object.page_queryset,
            "page_string": page_object.html(),
        },
    )


@csrf_exempt
def order_add(request):
    """新建订单(Ajax请求)"""
    form = OrderModelForm(data=request.POST)
    if form.is_valid():
        # 缺少oid
        # 生成一个以 年月日时分秒 + 随机生成值 构建的oid
        form.instance.oid = datetime.now().strftime("%Y%m%d%H%M%S") + str(
            random.randint(1000, 9999)
        )
        # 管理员 当外键为admin时候,实际上数据库中存储的是admin_id字段 为其添加当前系统的登录的管理员
        form.instance.admin_id = request.session["info"]["id"]
        form.save()
        # 等价于HttpResponse(json.dumps({"status":True}))
        return JsonResponse({"status": True})
    """console.log(res)
    {
        "status": false,
        "error": {
            "title": ["这个字段是必填项。"],
            "price": ["这个字段是必填项。"],
            "admin": ["这个字段是必填项。"],
        }
    }
    """
    return JsonResponse({"status": False, "error": form.errors})


def order_delete(request):
    """删除订单"""
    uid = request.GET.get("uid")
    exsits = models.Order.objects.filter(id=uid).exists()
    if exsits:
        models.Order.objects.filter(id=uid).delete()
        return JsonResponse({"status": True})
    return JsonResponse({"status": False, "error": "数据不存在,删除失败"})


def order_detail(request):
    """根据ID获取订单详细"""
    uid = request.GET.get("uid")
    row_dict = (
        models.Order.objects.filter(id=uid).values("title", "price", "status").first()
    )
    if not row_dict:
        return JsonResponse({"status": False, "error": "数据不存在,删除失败"})
    """方式一 字典

    result = {
        "status": True,
        "data": {
            "title": row_object.title,
            "price": row_object.price,
            "status": row_object.status,
        },
    }    
    """
    return JsonResponse({"status": True, "data": row_dict})

    # 从数据库中获取一个对象 row_object


@csrf_exempt
def order_edit(request):
    """编辑页面"""
    uid = request.GET.get("uid")
    row_object = models.Order.objects.filter(id=uid).first()
    if not row_object:
        # 编辑的内容不存在(编辑时已被删除)
        return JsonResponse({"status": False, "tips": "数据不存在,请重试"})
    form = OrderModelForm(data=request.POST, instance=row_object)
    if form.is_valid():
        form.save()
        return JsonResponse({"status": True})
    # 编辑的内容不符合规定
    return JsonResponse({"status": False, "error": form.errors})

templates ->order_list.py

{% extends "layout.html" %}

{% block title %}
订单管理
{% endblock %}
{% block css %}
<style>
  .unoccupied{
    background-color: red;
    color: #FFFFFF;
  }
</style>
{% endblock  %}
{% block 订单管理 %}class="active"{% endblock %}
{% block content %}
    <div class="container">
        <input type="button" value="新建订单1" class="btn btn-success" id="btnAdd">

        <input type="button" value="新建订单2" class="btn btn-success" data-toggle="modal" data-target="#myModal">

        <div class="panel panel-default" style="height:460px;margin-top:20px;">

          <div class="panel-heading">
              <h3 class="panel-title"><i class="fa fa-list-ul"></i> 订单列表</h3>
          </div>

          <table class="table table-hover table-bordered" style="padding:0 20px 0 20px;">
              <thead>
                  <tr>
                      <th>ID</th>
                      <th>订单号</th>
                      <th>名称</th>
                      <th>价格</th>
                      <th>状态</th>
                      <th>管理员</th>
                      <th>操作</th>
                  </tr>
              </thead>
              <tbody>
                  {% for item in queryset %}
                  <tr uid="{{ item.id }}">
                      <td>{{ item.id }}</td>
                      <td>{{ item.oid}}</td>
                      <td>{{ item.title}}</td>
                      <td>{{ item.price }}</td>
                      <td 
                      {% if item.status == 1 %}
                          class="unoccupied"
                      {% endif %}                     
                      >{{ item.get_status_display }}</td>
                      <td>{{ item.admin.username }}</td>                      
                      <td>
                          <input  uid={{ item.id }} type="button" class="btn btn-primary btn-xs btn-edit" value="编辑">
                          <span> </span>
                          <input  uid={{ item.id }} type="button" class="btn btn-danger btn-xs btn-delete" value="删除">
                      </td>
                  </tr>
                  {% endfor %}
              </tbody>
          </table>

      </div><!--panel-->

      <ul class="pagination">
          {{ page_string }}
      </ul>
    </div>


<!-- 新建/编辑订单对话框 -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
    <div class="modal-dialog" role="document">
        <div class="modal-content">
            <div class="modal-header">
              <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
              <h4 class="modal-title" id="myModalLabel"></h4>
            </div>

            <div class="modal-body">

                <form id="formAdd" novalidate>

                    {% for field in form %}
                    <div class="form-group">
                        <label>{{ field.label }}</label>
                        {{ field }}
                        <spanv class="error_msg" style="color:red;">{{ field.errors.0 }}</span>
                    </div>
                    {% endfor %}
              </form>

              </div>
              
              <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
                <button type="button" class="btn btn-primary" id="BtnSave">保存</button>
              </div>
        </div>
    </div>
</div>

<!-- 删除订单对话框 -->
<div class="modal fade" id="deleteModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
    <div class="modal-dialog" role="document">
      <div class="alert alert-danger alert-dismissible fade in" role="alert">
        <h4>确认删除?</h4>
        <p style="margin:10px;">删除后所有关联的相关数据都会被删除</p>
        <p style="text-align:right;">
          <button id="btn-confrim-delete" type="button" class="btn btn-danger">确认</button>
          <!-- data-dismiss="modal" 取消对话框 -->
          <button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
        </p>
      </div>
    </div>
</div>

{% endblock  %}
{% block js %}
<script type="text/javascript">
  var DELETE_ID ;
  var EIDT_ID ;
    $(function () {
        bindBtnAddEvent();
        bindBtnSaveEvent();
        bindBtnDeleteEvent();
        bindBtnConfirmDeleteEvent();
        bindBtnEditEvent();
    })

    function bindBtnAddEvent() {
        $("#btnAdd").click(function () {
          //将正在编辑的ID设置为空
          EIDT_ID = undefined;
          //清空由Edit留下的数据 $()[0]是对应的DOM
          $("#formAdd")[0].reset()
          //清除所有错误信息
          $(".error_msg").empty();          
          //点击按钮,显示对话框
          $("#myModal").modal('show');
          //修改对话框标题
          $("#myModalLabel").text("新建")            
        })
    }
    function bindBtnSaveEvent() {
        $("#BtnSave").click(function () {
          //清除所有错误信息
          $(".error_msg").empty(); 

          //根据EDIT_ID来确认当前保存的是新建数据还是编辑数据
          if(EIDT_ID){
            //编辑
            doEdit();
          }else{
            //添加
            doAdd();
          }
        });
    }
    function bindBtnDeleteEvent() {
      $(".btn-delete").click(function () {
        //显示删除对话框
        $("#deleteModal").modal('show');

        //获取当前行的id并赋值给全局变量
        DELETE_ID = $(this).attr("uid")

      })
    }
    function bindBtnConfirmDeleteEvent() {
      $("#btn-confrim-delete").click(function () {
        //点击确认删除按钮
        $.ajax({
          url:"/order/delete/", // => /order/delete/?uid=13
          type:"GET",
          data:{
            uid:DELETE_ID,
          },
          dataType:"JSON",
          success:function (res) {
            if(res.status){
              //alert("删除成功")
              //隐藏删除对话框
              $("#deleteModal").modal('hide');
              // //删除该行数据 通过js删除
              // $("tr[uid="+ DELETE_ID + "]").remove()

              //刷新页面
              location.reload()

              

              
            }else{
              alert(res.error)
            }
          }

        })
      });
    }
    function bindBtnEditEvent() {
      $(".btn-edit").click(function () {
        //当前id
        var currentId = $(this).attr("uid");
        EIDT_ID = currentId;
        console.log(EIDT_ID)


        //修改对话框标题
        $("#myModalLabel").text("编辑");

        //发送ajax去后端获取当前行的相关数据
        $.ajax({
          url:"/order/detail/",
          type:"get",
          data:{
            uid:currentId,
          },
          dataType:"JSON",
          success: function (res) {
            if(res.status){
              // 点击显示模态对话框
              $("#myModal").modal("show");  
              
              //console.log(res);
              //将数据默认赋值到对话框的标签中
              $.each(res.data, function (name, value) {
                $("#id_"+name).val(value);
              })
            }else{
              alert(res.error);
            }
          }
        })


      });
    }
    function doAdd(){
      $.ajax({
        url:"/order/add/",
        type:"post",
        data:$("#formAdd").serialize(),
        dataType:"JSON", //将从页面获取到的数据转化为JSON格式
        success:function (res){
          if(res.status){
            alert("创建成功");
            //清空表单 jQuery对象[0] - 找到对应的DOM对象 .reset 使用DOM对象的reset置空功能
            $("#formAdd")[0].reset();
            //关闭对话框
            $("#myModal").modal("hide");
            //重新加载页面
            location.reload()
          }else{
            //console.log(res.error)
            //将错误信息显示在对话框中
            $.each(res.error, function (name, errorList) {
              //拼接id id_title
              $("#id_" + name).next().text(errorList[0]);
            })
          }
        }
      })
    }
    function doEdit(){
      $.ajax({
        url:"/order/edit/?uid="+EIDT_ID,
        type:"post",
        data:$("#formAdd").serialize(),
        dataType:"JSON", //将从页面获取到的数据转化为JSON格式
        success:function (res){
          if(res.status){
            alert("创建成功");
            //清空表单 jQuery对象[0] - 找到对应的DOM对象 .reset 使用DOM对象的reset置空功能 等价于.val("")置空
            $("#formAdd")[0].reset();
            //关闭对话框
            $("#myModal").modal("hide");
            //重新加载页面
            location.reload()

          }else{
            //编辑的数据不存在
            if(res.tips){
              alert(res.tips)
            }else{


            }
            //console.log(res.error)
            //将错误信息显示在对话框中
            $.each(res.error, function (name, errorList) {
              //拼接id id_title
              $("#id_" + name).next().text(errorList[0]);
            })
          }
        }
      })
    }

</script>
{% endblock  %}

17.其他知识点

1.图表

  • highchart
  • echarts(推荐)

柱状图

views -> chart.py

def chart_bar(request):
    """构造柱状图数据"""
    # 数据可以去数据库中获取
    legend = ["销量", "业绩"]
    series_list = [
        {"name": "销量", "type": "bar", "data": [5, 20, 36, 10, 10, 20]},
        {"name": "业绩", "type": "bar", "data": [6, 24, 44, 50, 10, 60]},
    ]
    x_axis = ["1月", "2月", "3月", "4月", "5月", "6月"]
    result = {
        "status": True,
        "data": {
            "legend": legend,
            "series_list": series_list,
            "x_axis": x_axis,
        },
    }
    return JsonResponse(result)

templates -> chart_list.html

<div class="col-sm-4">

    <div class="panel panel-default">
        <div class="panel-heading">
            <h3 class="panel-title">饼状图</h3>
        </div>
        <div class="panel-body">
            <div id="m3" style="width:100%;height:400px;"></div>
        </div>

    </div><!--panel-->

</div>

...

<script src="{% static 'js/echarts.js' %}"></script>
<script type="text/javascript">
    $(function () {
      InitBar();
    })

    /*初始化柱状图*/
    function InitBar() {
      // 基于准备好的dom,初始化echarts实例
      var myChart = echarts.init(document.getElementById('m2'));

      // 指定图表的配置项和数据
      var option = {
        title: {
          text: 'ECharts 入门示例',
          textAlign:"auto",
          left:"center",
        },
        tooltip: {},
        legend: { //后台获取
          bottom:0,
        },
        xAxis: {
          data: [] //后台获取
        },
        yAxis: {},
        series: [] //后台获取
      };
      $.ajax({
        url:"/chart/bar/",
        type:"get",
        dataType:"JSON",
        success:function(res){
          //将后台返回的数据更新到option中
          if(res.status){
            option.legend.data = res.data.legend;
            option.xAxis.data = res.data.x_axis;
            option.series = res.data.series_list;
            // 使用刚指定的配置项和数据显示图表。
            myChart.setOption(option);            
          }//res.status

        },//success:function(res)

      })//$.ajax
        
    }//function InitBar()
</script>

2.关于文件的上传

2.1基本操作

<div class="container">
    <form method="post" enctype="multipart/form-data"><!--表单中一定要有enctype属性,否则不会上传文件-->
        {% csrf_token %}
        <input type="text" name="username">
        <input type="file" name="avatar">
        <input type="submit" value="提交">
    </form>
</div>
def upload_list(request):
    """上传文件"""
    if request.method == "GET":
        return render(request, "upload_list.html")
    # <QueryDict: {'username': ['朱一凡'], 'avatar': ['推荐-划分区域.png']}> 仅上传了文件的字符名而非文件
    # print(request.POST)  # 请求体中的数据(不包含文件)
    # print(request.FILES)  # 请求体中的文件
    file_object = request.FILES.get("avatar")  # 文件对象
    print(file_object.name)  # 文件名 推荐-划分区域.png

    # 将上传的文件写入一张图片中
    # 将图片分块上传,然后分块写入到a1.png中,也可以将文件名设置为file_object.name
    f = open("a1.png", mode="wb")
    for chunk in file_object:
        f.write(chunk)
    f.close

    return HttpResponse("提交成功")

案例:批量上传数据

<div class="panel-heading">
    <h3 class="panel-title"><i class="fa fa-list-ul"></i> 批量上传</h3>
</div>
<div class="panel-body">
    <form action="/depart/multi/" enctype="multipart/form-data" method="post">
        {% csrf_token %}
        <div class="form-group">
          <input type="file" name="exc">
        </div>
        <button type="submit" class="btn btn-info btn-sm">上传</button>
    </form>
</div>
def depart_multi(request):
    """批量上传(Excel文件)"""
    from openpyxl import load_workbook

    # 获取用户上传的文件对象
    file_object = request.FILES.get("exc")

    # 对象传递给openpyxl, 由openpyxl读取文件的内容
    wb = load_workbook(file_object)
    # 读取第一个sheet
    sheet = wb.worksheets[0]
    # cell = sheet.cell(1, 1)
    # 循环获取每一行的数据
    for row in sheet.iter_rows(min_row=2):
        # 获取每一行的第一个数据,即部门名称
        text = row[0].value
        # 判断该部门是否存在
        exists = models.Department.objects.filter(title=text).exists()
        if not exists:
            models.Department.objects.create(title=text)
        else:
            return HttpResponse("上传失败,有重复名称的部门")

    return redirect("/depart/list/")

案例:混合数据上传

提交页面时:用户输入数据 + 文件 (进行校验 不能为空,格式错误等)

  • Form生成HTML标签:type=file
  • 可以做表单的验证
  • form.cleaned_data获取 数据 + 文件对象
{% extends "layout.html" %}
{%load static%}

{% block title %}
{{ title_templ }}
{% endblock %}
{% block Form上传 %}class="active"{% endblock  %}
{% block content %}
    <div class="container">
        <div class="panel panel-default">
            <div class="panel-heading">
            <h3 class="panel-title">{{ panel_title_templ}}</h3>
            </div>

            <div class="panel-body">
                <form method="post" enctype="multipart/form-data" novalidate>
                    {% csrf_token %}
                    
                    {% for field in form %}
                    <div class="form-group">
                        <label>{{ field.label }}</label>
                        {{ field }}
                        <span style="color:red;">{{ field.errors.0 }}</span>
                    </div>
                    {% endfor %}
                    
                    <button type="submit" class="btn btn-primary"><i class="fa fa-save" aria-hidden="true"></i> 保 存</button>
                    <a href="{{cancel_url}}" class="btn btn-danger" ><i class="fa fa-close" aria-hidden="true"></i> 取 消</a>
                </form>
            </div>
            
        </div>
    </div>
{% endblock  %}

from django import forms


class UpForm(BootStrapForm):
    bootstrap_exclude = ["img"]
    name = forms.CharField(label="姓名")
    age = forms.IntegerField(label="年龄")
    img = forms.FileField(label="头像")


import os
from app01 import models


def upload_form(request):
    context = {"title_templ": "Form上传", "panel_title_templ": "Form上传"}
    if request.method == "GET":
        form = UpForm()
        return render(request, "upload_form.html", {**context, "form": form})
    # 进行表单验证要分别对数据和files进行验证
    form = UpForm(data=request.POST, files=request.FILES)
    if form.is_valid():
        # print(form.cleaned_data)
        # {'name': 'wupeiqi', 'age': 12, 'img': <InMemoryUploadedFile: a1.png (image/png)>}
        # 读取字段的数据然后分别对每个字段进行处理
        img_object = form.cleaned_data.get("img")
        # file_path = "app01/static/img/{}".format(img_object.name) project6-Django\System_Manage_User\app01\static
        # 数据库上传的地址,是在网页端通过与服务器地址拼接可以直接访问的
        db_file_path = os.path.join(
            "static",
            "img",
            img_object.name,
        )
        # 实际上文件的地址,即在存储图片时候的地址
        file_path = os.path.join(
            "project6-Django", "System_Manage_User", "app01", db_file_path
        )
        f = open(file_path, mode="wb")
        for chunk in img_object.chunks():
            f.write(chunk)
        f.close()

        # 将图片路径写入数据库
        models.Boss.objects.create(
            name=form.cleaned_data["name"],
            age=form.cleaned_data["age"],
            img=db_file_path,
        )

        return HttpResponse("上传成功")
    return render(request, "upload_form.html", {**context, "form": form})

2.2 启用media

在urls.py中进行配置

from django.urls import path, re_path
from django.views.static import serve
from django.conf import settings
urlpatterns = [
	re_path(r"^media/(?P<path>.*)$", serve, {"document_root":settings.MEDIA_ROOT}, name="media"),
]

在settings.py中进行配置

import os

MEDIA_ROOT = os.path.join(BASE_DIR, "media")
MEDIA_URL = "/media/"

之后就可以直接通过/media/图片.png访问图片

案例:混合数据上传(Form)

def upload_form(request):
    context = {"title_templ": "Form上传", "panel_title_templ": "Form上传"}
    if request.method == "GET":
        form = UpForm()
        return render(request, "upload_form.html", {**context, "form": form})
    # 进行表单验证要分别对数据和files进行验证
    form = UpForm(data=request.POST, files=request.FILES)
    if form.is_valid():
        from django.conf import settings

        # media_path = os.path.join(settings.MEDIA_ROOT, img_object.name) 绝对路径
        media_path = os.path.join("media", img_object.name)
        # 实际上文件的地址,即在存储图片时候的地址
        file_path = os.path.join("project6-Django", "System_Manage_User", media_path)
        f = open(file_path, mode="wb")
        for chunk in img_object.chunks():
            f.write(chunk)
        f.close()

        # 将图片路径写入数据库
        models.Boss.objects.create(
            name=form.cleaned_data["name"],
            age=form.cleaned_data["age"],
            img=media_path,
        )

        return HttpResponse("上传成功")
    return render(request, "upload_form.html", {**context, "form": form})

2.3modelform

models.py

class City(models.Model):
    """城市"""

    name = models.CharField(verbose_name="名称", max_length=32)
    count = models.IntegerField(verbose_name="人口")
    # 本质上数据库中也是CharField,但是在保存时候
    img = models.FileField(
        verbose_name="LOGO", max_length=128, upload_to="city/"
    )  # 自动放到media下的city目录中

小结

  • 自己动手写

    file_object = request.FILES.get("exc")
    
  • Form组件(表单验证)

    request.POST
    file_object = request.FILES.get("exc")
    
    具体文件操作需要手动
    
  • ModelForm(表单验证 + 自动保存数据库 + 自动保存文件)

    - Media文件夹
    - Models.py定义类文件要
    img = models.FileField(verbose_name="", max_length=128, upload_to="fileAddress/")
    
posted on 2024-02-16 13:24  树深时见鹿nnn  阅读(8)  评论(0编辑  收藏  举报