暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Django:如何将「前端」表单中的数据传递给「后端」

Nephilim 2024-04-27
103

Tips:一些记录,一些笔记



2024/04/26

FRIDAY

Life is like a horse, you don't control it, it will control you.

人生像一匹马,你不驾驭它,它便驾驭你。





01

架构


前端:Bootstrap

后端:Django


02

前端


一、在页面上创建「form」

    <!-- 内容区域 -->
    <div class="modal-body">


    <form id="FormAddProject">
    {% csrf_token %}
    {% for field in form %}
    <div class="form-group">
    <label for="{{ field.id_for_label }}">
    {{ field.label }}
    </label>
    {{ field }}
    <span class="error-msg"></span>
    <br>
    </div>
    {% endfor %}
    </form>


    </div>


    二、定义「form」提交的按钮

      <!-- 底部区域 -->
      <div class="modal-footer">
      <button type="button"
      class="btn btn-secondary"
      data-bs-dismiss="modal"
      >
      取消
      </button>


      <button type="button"
      class="btn btn-primary"
      id="btnSubmitAddProject"
      >
      确定
      </button>
      </div>


      三、给「提交按钮」绑定点击事件(用Ajax实现)

        $(function () {
        btnSubmitAddProjectClick();
        })


        function btnSubmitAddProjectClick() {
        $('#btnSubmitAddProject').click(function () {


        // 清空所有的错误信息
        $('.error-msg').empty()


        $.ajax({
        url: "{% url 'project:index' %}",
        type: "POST",
        data: $('#FormAddProject').serialize(),
        dataType: "JSON",
        success: function (res) {
        console.log(res)
        if (res.status) {
        location.href = location.href
        // location.reload()
        } else {
        $.each(res.error, function (key, value) {
        $("#id_" + key).next().text(value[0]);
        })
        }
        }
        })
        })
        }


        03

        后端(Django)


        一、路由设置

        这里的配置,对应「前端」点击事件的AJAX中的「URL」部分的配置:

          url: "{% url 'project:index' %}",

          路由配置如下:

            #!/usr/bin/env python
            # -*- coding: UTF-8 -*-


            # ——————————————————
            # 脚本说明:
            # xxxxxxxxx
            # ——————————————————


            # ========================================
            # 开始
            # ))))))))) 模块包导入
            from django.urls import path, include


            from project.views.project.views import *


            # ))))))))) 类名
            app_name = "project"


            urlpatterns = [
            # 首页
                path('', index, name="index"),
            ]


            # ))))))))) 执行阶段


            # ))))))))) 结束


            # ========================================
            # 结束



            二、视图配置(index)

              from django.shortcuts import render, redirect
              from django.http import JsonResponse, HttpResponse


              from project.forms import *
              from project.models import *


              # Create your views here.
              def index(request):
              # return render(request, "project/index.html")


              # ===============================
              # 处理「GET」请求
              # ===============================


              if request.method == "GET":
              # ===============================
              # 项目列表
              # ===============================


              # 从数据库中查询两部分数据:
              # 创建的项目:星标 未星标
              # 参与的项目:星标 未星标


              # 将星标的项目全部获取并加载到一个列表中


              # 最终得到三个列表:星标 创建 参与


              # 最终得到的三个列表的「字典对象」
              project_dict = {
              'star': [],
              'created': [],
              'involved': [],
              }


              project_list_current_user = Project.objects.filter(
              project_creator = request.daily_info_management.account
              )
              for project in project_list_current_user:
              if project.project_star:
              project_dict['star'].append({
              'value': project,
              'type': 'created'
              })
              else:
              project_dict['created'].append(project)


              project_list_involved = ProjectMember.objects.filter(
              project_member = request.daily_info_management.account
              )
              for project_involved in project_list_involved:
              if project_involved.project_star:
              project_dict['star'].append({
              'value': project_involved.project,
              'type': 'involved'
              })
              else:
              project_dict['involved'].append(project_involved.project)


              # ===============================
              # 添加项目
              # ===============================


              formAddProject = addProjectModelForm(request)


              # ===============================
              # 返回阶段
              # ===============================


              return render(request, "project/index.html", {
              'form': formAddProject,
              'project_dict': project_dict,
              })


              # ===============================
              # 处理「POST」请求
              # ===============================


              # ===============================
              # 添加项目
              # ===============================


              formAddProject = addProjectModelForm(request,data=request.POST)
              if formAddProject.is_valid():
              # 验证通过:项目名、颜色、描述 + 创建者
              formAddProject.instance.project_creator = request.daily_info_management.account


              # 执行创建(保存)
              formAddProject.save()


              # ===============================
              # 返回阶段
              # ===============================


              return JsonResponse({
              "status": True
              })


              # ===============================
              # 返回阶段
              # ===============================


              return JsonResponse({
              "status": False,
              "error": formAddProject.errors
              })


              当发生「表单」的「提交事件」的时候,触发的是「request.POST」

              从视图的实现代码可以看到,首先会把「前端」过来的数据,丢给ModelForm进行校验与处理。


              三、ModelForm

                #!/usr/bin/env python
                # -*- coding: UTF-8 -*-


                # ——————————————————
                # 脚本说明:
                # xxxxxxxxx
                # ——————————————————


                # ========================================
                # 开始
                # ))))))))) 模块包导入
                from django import forms
                from django.core.exceptions import ValidationError


                from utils.Bootstrap.BootstrapForm import *


                from .models import *
                from .widgets import *


                # ))))))))) 类名


                class addProjectModelForm(BootstrapForm, forms.ModelForm):


                bootstrap_class_exclude = ['color']


                # project_desc = forms.CharField(
                # label="项目描述",
                # widget=forms.Textarea()
                # )


                def __init__(self, request, *args, **kwargs):
                super().__init__(*args,**kwargs)
                self.request = request


                class Meta:
                model = Project
                fields = [
                'project_name',
                'color',
                'project_desc',
                ]
                # 修改数据库中字段的默认展示方式
                widgets = {
                "project_desc": forms.Textarea(),
                # "color": forms.RadioSelect,
                "color": ColorRadioSelect(attrs={'class': 'color-radio'}),
                }


                def clean_project_name(self):
                """ 项目名称的校验 """


                project_name = self.cleaned_data['project_name']


                # 是否重名
                exists = Project.objects.filter(
                project_creator = self.request.daily_info_management.account,
                project_name = project_name
                ).first()
                if exists:
                raise ValidationError("已创建过同名项目,请更改项目名称后,重试")


                # 当前用户是否有额度创建项目
                project_already_created_count = Project.objects.filter(
                project_creator=self.request.daily_info_management.account
                ).count()


                # print("当前用户已创建的项目数量「%s」" % project_already_created_count)
                self.request.daily_info_management.account.project_num_created = project_already_created_count


                if self.request.daily_info_management.account.project_num_created >= self.request.daily_info_management.account_level.project_num:
                raise ValidationError("「可创建的项目数」已达到配额")


                # 如果验证没问题,则正常返回
                return project_name




                # ))))))))) 执行阶段


                # ))))))))) 结束


                # ========================================
                # 结束



                四、Bootstrap样式类

                  #!/usr/bin/env python
                  # -*- coding: UTF-8 -*-


                  # ——————————————————
                  # 脚本说明:
                  # xxxxxxxxx
                  # ——————————————————


                  # ========================================
                  # 开始
                  # ))))))))) 模块包导入


                  # ))))))))) 类名
                  class BootstrapForm(object):


                  # 哪些 class 不再应用 Bootstrap样式
                  bootstrap_class_exclude = []


                  def __init__(self, *args, **kwargs):
                  super().__init__(*args, **kwargs)


                  # 为表单元素添加 BootStrap 样式
                  for name, field in self.fields.items():


                  if name in self.bootstrap_class_exclude:
                  continue


                  field.widget.attrs['class'] = 'form-control'
                  field.widget.attrs['placeholder'] = '请输入%s' % (field.label,)


                  # ))))))))) 执行阶段


                  # ))))))))) 结束


                  # ========================================
                  # 结束



                  04

                  效果


                  当你完成了上述配置后,「前端」表单提交的数据便会传递给「后端」处理,并最终写入数据库。


                  来看看前端页面的效果:





                  END




                  温馨提示



                  如果你喜欢本文,请分享到朋友圈,想要获得更多信息,请关注我。


                  文章转载自Nephilim,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                  评论