04 Django模型基础

1. models字段类型

概述

django根据属性的类型确定以下信息

  • 当前选择的数据库支持字段的类型
  • 渲染管理表单时使用的默认html控件
  • 在管理站点最低限度的验证

django会为表增加自动增长的主键列,每个模型只能有一个主键列,如果使用选项设置某属性为主键列后则django不会再生成默认的主键列

属性命名限制

  • 遵循标识符规则

  • 由于django的查询方式,不允许使用连续的下划线定义属性时,

    需要字段类型,字段类型被定义在diango.db.models.fields目录下,为了方便使用被导入到django.db.models中

使用方式

  • 导入from django.db import models
  • 通过models.Field创建字段类型的对象,赋值给属性

逻辑删除和物理删除

对于重要数据都做逻辑删除,不做物理删除,实现方法是定义is_delete属性,类型为BooleanField,默认值为False
is_delete = models.BooleanField(default=False)

常用字段类型

  • AutoField: 一个根据实际ID自动增长的IntegerField,通常不指定,如果不指定,主键字段id将自动添加到模型中

  • CharField(max_length=字符长度)

    • 字符串,默认的表单样式是 Input
  • TextField
    大文本字段,一般超过4000使用,默认的表单控件是Textarea

  • IntegerField

    • 整数
  • DecimalField(max_digits=None,decimal_places=None)

    • 使用python的Decimal实例表示的十进制浮点数
    • 参数说明
      • DecimalField.max_digits -> 位数总数
      • DecimalField.decimal_places -> 小数点后的数字位数
  • FloatField: 用Python的float实例来表示的浮点数

  • BooleanField

    • True/False 字段,此字段的默认表单控制是CheckboxInput
  • DateField([auto_now=False,auto_now_add=False])

    • 使用Python的datetime.date实例表示的日期参数说明
    • 参数说明
      • DateField.auto_now
        每次保存对象时,自动设置该字段为当前时间,用于**“最后一次修改”**的时间戳,它总是使用当前日期,默认为false
      • DateField.auto_now_add
        当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用创建时的日期,默认为false
      • 注意:auto_now_add,auto_now,and_default 这些设置是相互排斥的他们之间的任何组合将会发生错误的结果
  • TimeField: 使用Python的datetime.time实例表示的时间,参数同DateField

  • DateTimeField: 使用Python的datetime.datetime实例表示的日期和时间,参数同DateField

  • FileField

    • 一个上传文件的字段
  • ImageField:

    • 继承了FileField的所有属性和方法,但对上传的对象进行校验,确保它是个有效的image
    • 需要安装Pillow: “pip install Pillow”

2. 常用字段参数

# 常用字段选项(通过字段选项,可以实现对字段的约束)
	1. null=True
		数据库中字段是否可以为空
	2. blank=True
		django的 Admin 中添加数据时是否可允许空值

	一般null=True & blank=True 搭配着用,出现null=True就用上blank=True
    
	3. primary_key = True
    	主键,对AutoField设置主键后,就会代替原来的自增id4. auto_now和auto_now_add
        auto_now 自动创建 --- 无论添加或修改,都是当前操作的时间
        auto_now_add 自动创建 --- 永远是创建时的时间
        
    5. choices (后台admin下拉菜单)
        USER_TYPE_LIST =(
        (1'超级用户'),
        (2'普通用户'), 
        )
		user_type = models.IntegerField(choices=USER_TYPE_LIST,default=1,,verbose_name='用户类型')
        
    6. max_length 最大长度
	7. default 	  默认值
	8. verbose_name		Admin(后台显示的名称)中字段的显示名称
	9. name|db_column	数据库中的字段名称
	10. unique=True		不允许重复
	11. db_index = True	数据库索引,例如:如果你想通过name查询的更快的话,给他设置为索引即可
    12.	editable=True 	在Admin里是否可编辑,不可编辑则不显示
	13. 设置表名
	class Meta:
		db_table ='person'

在创建模型迁移之时,经常会遇到以下问题,这是以为原先数据库中已经有数据,这时创建新的数据字段,原先的记录不知道填充什么内容进新增字段(假设不是所有新增字段都有默认值)

模型在admin后台默认的html控件 --> 渲染管理表单时使用的默认html控件
在这里插入图片描述

3.迁移怎么回滚

完成迁移之后,会在应用文件夹App/migrations文件夹下创建迁移文件,并且在数据库表django_migrations中创建对应记录

想要回滚,可以删除对应的迁移python文件以及对应数据库记录
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4. models基本操作

一般的数据库操作流程:

  1. 创建数据库,设计表结构和字段
  2. 连接Mysql数据库,并编写数据访问层代码
  3. 业务逻辑层去调用数据访问层执行数据库操作

Django通过Model操作数据库,不管你数据库的类型是MySql或者Sqlite,Django自动帮你生成相应数据库类型的SQL语句,所以不需要关注SQL语句和类型,对数据的操作Django帮我们自动完成。

只要会写Model就可以了。django使用对象关系映射(Object Relational Mapping,简称ORM)框架去操控数据库。ORM(Object Relational Mapping)对象关系映射,是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。

在Django模型中可以使用内部类Meta为模型提供选项,具体请见文档

增删改查

ORM

  • 模型 <=> 表
  • 类结构 -> 表结构
  • 对象 -> 表的一条数据
  • 类属性 -> 表的字段

模型基本操作

  1. 增: (假设模型是Author)

    1. 创建对象实例,然后调用save方法
    obj = Author()
    obj.first_name = "zhang"
    obj.last_name = 'san'
    obj.save()
    
    1. 创建对象并初始化,在调用save方法
    obj = Author(first_name = "zhang",last_name = 'san')
    obj.save()
    
    1. 使用create方法
    Author.objects.create(first_name = "zhang",last_name = 'san')
    
    1. 使用get_or_create方法,可以防止重复
    Author.objects.get_or_create(first_name = "zhang",last_name = 'san')
    

在这里插入图片描述

注意: 添加失败是因为PersonModel模型中name属性设置的是unique

# 增加数据
def add_person(request):
    # # 方式1
    # try:
    #     p = PersonModel(name='张三', age=20)
    #     p.save()
    # except Exception as e:
    #     print(e)
    #     return HttpResponse('添加失败')

    # return HttpResponse('添加成功')

    # 方式2
    # PersonModel.objects.create(name='李四', age=25)
    # return HttpResponse('添加成功')

    # 方式3
    ret = PersonModel.objects.get_or_create(name='李四', age=25)
    print("ret",ret)
    # ret:(<PersonModel:PersonModelobject(2)>,True)
    # 如果是第一次创建: 则是True,如果已经存在则是False
    return HttpResponse('添加成功')
  1. 删:

    1. 获取单个对象并调用Queryset的delete()方法
    p = PersonModel.objects.first() # 获取第一个数据
    p.delete()
    p = PersonModel.objects.get(name="李四")   # 根据对应的id获取数据
    p.delete()
    

    注意: objects不能直接调用delete()方法

    1. 使用模型过滤filter(),再对过滤结果进行删除
    # 使用过滤器
    PersonModel.objects.filter(age__gt = 15).delete()   # 删除年龄大于15的数据        
    
  2. :

    1. 直接使用对象.属性修改
    # 获取数据
    p = PersonModel.objects.first()
    p.age = 25
    p.save()
    
    # 修改多条数据
    p_list = PersonModel.objects.all()
    
    for p in p_list:
    	p.age = 25
       	p.save()
    
    1. 修改多条数据
    PersonModel.objects.all().update(age=25)  # 修改所有数据
    

    save()更新时,会对所有字段进行更新操作,如果想要只更新某个字段,减少数据库操作,可以这么做:

    obj.first_name = "zhang"
    obj.save(update_fields = ['first_name'])
    
  3. 查:

对查询集可使用的函数

  • get():获取单条数据 Author.objects.get(id=123)

    • 如果没有找到符合条件的对象,会引发模型类.DoesNotExist异常
    • 如果找到多个,会引发模型类.MultipleObjectsReturned异常
  • first():返回査询集(Queryset)中的第一个对象

  • last():返回查询集中的最后一个对象

  • count():返回当前查询集中的对象个数

  • exists():判断查询集中是否有数据,如果有数据返回True没有反之

  • all()获取全部数据: Author.objects.all()

  • values():获取指定列的值,可以传多个参数! 返回包含字典的列表(保存了字段名和对应的值) —>

    Author.objects.all().values(‘password’)

  • values_list():获取指定列的值,可以传多个参数! 返回包含元组列表(只保存值) —>

    Author.objects.all().values_list(‘password’)

  • filter()

查询集可以被链式调用,Author.objects.filter(name="seven").filter(age=18)

进阶操作
# 获取个数
Author.objects.filter(name="seven").count()

# 获取id大于1的值
Author.objects.filter(id__gt=1)	# SELET * FROM Author WHERE id > 1
# 获取id大于或等于1的值
Author.objects.filter(id__gte=1)	# SELET * FROM Author WHERE id >= 1
# 获取id小于10的值
Author.objects.filter(id__lt=10)	# SELET * FROM Author WHERE id < 10
# 获取id小于或等于10的值
Author.objects.filter(id__lte=10)	# SELET * FROM Author WHERE id >= 1

# 获取id大于1且小于10的值
Author.objects.filter(id__lt=10,id__gt=1)	# SELET * FROM Author WHERE id > 1 AND id < 10
# 获取id在11,22,33的数据
Author.objects.filter(id__in=[11,22,33])	# SELET * FROM Author WHERE id IN (11,22,33)

# 获取id`不在`11,22,33的数据
Author.objects.exclude(id__in=[11,22,33])	# SELET * FROM Author WHERE id NOT IN (11,22,33)

# 获取name包含"ven"的数据 (和数据库中like语法相似)
Author.objects.filter(name__contains="ven")	# SELET * FROM Author WHERE name LIKE '%ven%'

# icontains()大小写不敏感
Author.objects.filter(name__icontains="ven")

Author.objects.filter(name_regex="^ven")	# 正则匹配
Author.objects.filter(name_iregex="^ven")	# 正则匹配,忽略大小写
Author.objects.filter(age_range=[10,20])   	# 范围bettwen and

# startswith,istartswith,endswith,iendswith:
# 以什么开始,以什么结束,和上面一样带i的是大小写不敏感的, 其实不带i的也忽略大小写

Author.objects.filter(name='seven').order_by('id','age')	# asc升序, 多个属性->id相同时,按照age来排序
Author.objects.filter(name='seven').order_by('-id')	# desc降序

Author.objects.all()[18:20] # 切片,取所有数据的18条到20条,分页的时候用的到
# 下标从0开始,不能为负数,可以实现分页

# 手动分页
page 页码 
per_page 每页数量 = 51(page=1): 0-4 =>[0:5]2(page=2): 5-9 =>[5:10]3(page=3): 10-14 =>[10:15]4(page=4): 15-19 =>[15:20]

每一页数据范围:[(page-1) * per_page : page * per_page]

# 聚合
使用aggregate()函数返回聚合函数的值
- Avg:平均值
- Count:数量
- Max:最大
- Min:最小
- Sum:求和
from django.db.models import Count,Min,Max,Sum
Author.objects.aggregate(Max('age'))

5. views.py

from django.http import HttpResponse
from django.shortcuts import render
from django.db.models import Avg, Max, Min, Sum
# Create your views here.

from App.models import *


# 增加数据
def add_person(request):
    # # 方式1
    # try:
    #     p = PersonModel(name='张三', age=20)
    #     p.save()
    # except Exception as e:
    #     print(e)
    #     return HttpResponse('添加失败')

    for i in range(10):
        p = PersonModel(name='张三'+str(i), age=20+i)
        p.save()

    # return HttpResponse('添加成功')

    # 方式2
    # PersonModel.objects.create(name='李四', age=25)
    # return HttpResponse('添加成功')

    # 方式3
    # ret = PersonModel.objects.get_or_create(name='李四', age=26)
    # print("ret",ret)
    # ret:(<PersonModel:PersonModelobject(5)>,True)
    # 如果是第一次创建: 则是True,如果已经存在则是False
    return HttpResponse('添加成功')


# 删除数据
def del_person(request):
    try:
        # p = PersonModel.objects.first() # 获取第一个数据
        # p = PersonModel.objects.get(name="李四")   # 根据对应的id获取数据
        # p.delete()
        # 使用过滤器
        PersonModel.objects.filter(age__gt = 15).delete()   # 删除年龄大于15的数据
        
    except Exception as e:
        print(e)
        return HttpResponse('删除失败')
    
    return HttpResponse('删除成功')

# 修改数据
def update_person(request):
    try:
        # 获取数据
        # p = PersonModel.objects.first()
        # p.age = 25
        # p.save()

        # 修改多条数据
        p_list = PersonModel.objects.all()
        # PersonModel.objects.all().update(age=25)  # 修改所有数据
        for p in p_list:
            p.age = 25
            p.save()
    except Exception as e:
        print(e)
        return HttpResponse('修改失败')
    
    return HttpResponse('修改成功')

        
def get_person(response):
    # get() 方法获取单个数据
    # p = PersonModel.objects.get(id=1)

    # p = PersonModel.objects.get(pk=18)    # primary key等于18
    # p = PersonModel.objects.get(age=100)  # 找不到对应的数据时会报错,找到多条数据时也会报错   
    # print(p,type(p))    # <PersonModel: PersonModelobject(1)> <class 'App.models.PersonModel'>
    # print(p.name,p.age)

    # all() 方法返回所有数据
    p_list = PersonModel.objects.all()
    print(p_list,type(p_list))  #  <PersonModel: PersonModel object (25)>]> <class 'django.db.models.query.QuerySet'> 查询集,可以遍历

    # first() 方法获取第一个数据
    # p = PersonModel.objects.first()

    # last() 方法获取最后一个数据   
    # p = PersonModel.objects.last()

    # exists() 方法判断数据是否存在
    # if PersonModel.objects.filter(name='张三').exists():
    #     print('存在')
    # else:
    #     print('不存在')

    # values() 方法返回指定字段的数据
    # p_list = PersonModel.objects.values('name','age')   #返回包含字典的列表
    p_list = PersonModel.objects.values_list('name','age')   # 返回包含元组列表
    print(p_list,type(p_list))

    # filter() 方法过滤数据,返回一个```查询集````,参数为空时返回所有数据
    # p_list = PersonModel.objects.filter(age__gt=15)   # 年龄大于15的数据
    # p_list = PersonModel.objects.filter(name__contains='三')   # 名字包含'三'的数据
    # p_list = PersonModel.objects.filter(name__startswith='张')   # 名字以'张'开头的数据

    # exclude() 方法排除数据,返回一个```查询集````,参数为空时返回所有数据
    # p_list = PersonModel.objects.exclude(age__gt=15)   # 年龄不大于15的数据

    # order_by() 方法排序数据,返回一个```查询集````,参数为空时返回所有数据
    # p_list = PersonModel.objects.order_by('age')   # 按年龄排序
    # p_list = PersonModel.objects.order_by('-age')   # 按年龄倒序排序

    # contains() 方法查找字符串是否在指定字段中,返回一个```查询集````,参数为空时返回所有数据
    p_list = PersonModel.objects.filter(name__contains='三')   # 名字包含'三'的数据
    print(p_list,type(p_list))

    # regex() 方法查找正则表达式是否匹配指定字段,返回一个```查询集````,参数为空时返回所有数据
    # p_list = PersonModel.objects.filter(name__regex=r'^张')   # 名字以'张'开头的数据

    # 聚合函数
    # count() 方法计算数据条数
    # count = PersonModel.objects.count()
    # print(count)

    # max() 方法获取最大值
    # max_age = PersonModel.objects.all().aggregate(Max('age'))
    # print(max_age)

    # min() 方法获取最小值
    # min_age = PersonModel.objects.all().aggregate(Min('age'))
    # print(min_age)

    # sum() 方法求和
    # total_age = PersonModel.objects.all().aggregate(Sum('age'))
    # print(total_age)

    # avg() 方法求平均值
    result = PersonModel.objects.all().aggregate(Avg('age'))
    print(result)

    return HttpResponse('获取成功')


# 分页数据
def paginate(request,page=1):
    # 页码: page
    # 每页显示条数: per_page
    per_page = 10
    # 数据范围的计算公式 -> (页码-1)*每页显示条数 ~ 页码*每页显示条数

    all = PersonModel.objects.all()
    start = (page-1) * per_page
    end = page * per_page
    p_list = all[start:end]
    return render(request,"page_list.html",{'p_list':p_list})


# 自动分页器
def auto_paginate(request):
    # 自动分页器
    from django.core.paginator import Paginator
    # 实例化分页器
    paginator = Paginator(PersonModel.objects.all(), 10)
    page = 1
    persons = paginator.page(page) # 获取第page页的数据
    paginator.page_range   # 页码范围,可以遍历

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/939450.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【数据集】厨房明火数据集2916张YOLO+VOC格式

数据集格式&#xff1a;VOC格式YOLO格式 压缩包内含&#xff1a;3个文件夹&#xff0c;分别存储图片、xml、txt文件 JPEGImages文件夹中jpg图片总计&#xff1a;2916 Annotations文件夹中xml文件总计&#xff1a;2916 labels文件夹中txt文件总计&#xff1a;2916 标签种类数&am…

JavaScript的一些注意事项!

JavaScript的一些注意事项&#xff01; 1. JavaScript 数据类型2. JavaScript 事件3. JavaScript 字符串4. JavaScript 正则表达式5. JavsScript this 关键字6. JavaScript let 和 const7. JavaScript 异步编程8. JavaScript Promise9. JavaScript 代码规范10. JavaScript 函数…

图(dfs与bfs)算法2

进度&#xff1a;15/100 原题1&#xff1a; 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 &#xff08;力扣的图&#xff09; 原题2&#xff1a; 给定二叉树的根节点 root &#xff0c;返回所有左叶子之和。 原题3&#xff1a; 给…

【NLP 16、实践 ③ 找出特定字符在字符串中的位置】

看着父亲苍老的白发和渐渐老态的面容 希望时间再慢一些 —— 24.12.19 一、定义模型 1.初始化模型 ① 初始化父类 super(TorchModel, self).__init__()&#xff1a; 调用父类 nn.Module 的初始化方法&#xff0c;确保模型能够正确初始化。 ② 创建嵌入层 self.embedding n…

lightRAG 论文阅读笔记

论文原文 https://arxiv.org/pdf/2410.05779v1 这里我先说一下自己的感受&#xff0c;这篇论文整体看下来&#xff0c;没有太多惊艳的地方。核心就是利用知识图谱&#xff0c;通过模型对文档抽取实体和关系。 然后基于此来构建查询。核心问题还是在解决知识之间的连接问题。 论…

基于JAVA+SpringBoot+Vue的反欺诈平台

基于JAVASpringBootVue的反欺诈平台 前言 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN[新星计划]导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末附源码下载链接&#x1f345; 哈喽兄弟…

Gartner发布2025年网络安全主要趋势:实现转型和嵌入弹性两大主题下的9个趋势

持续不断的技术和业务中断考验着安全计划和团队绩效的极限。安全和风险管理领导者必须实现业务价值&#xff0c;并加倍努力增强组织、个人和团队的韧性&#xff0c;以证明安全计划在 2025 年的有效性。 机会 面对不断变化的技术以及企业希望利用这些技术获得战略利益的愿望&…

基于Spring Boot的新能源汽车个性化推荐系统

一、系统背景与意义 随着新能源汽车市场的快速发展&#xff0c;消费者对新能源汽车的需求日益多样化。为了满足消费者的个性化需求&#xff0c;提高购车体验&#xff0c;开发一个基于Spring Boot的新能源汽车个性化推荐系统显得尤为重要。该系统能够根据用户的偏好、历史行为等…

YOLOV8 原理和实现全解析(合适新人)

YOLOV8 原理和实现全解析 0 简介1 YOLOv8 概述2 模型结构设计3 Loss 计算4 训练数据增强5 训练策略6 模型推理过程7 特征图可视化总结 0 简介 图 1&#xff1a;YOLOv8-P5 模型结构 以上结构图由 RangeKinggithub 绘制。 YOLOv8 是 Ultralytics 公司在 2023 年 1月 10 号开源的…

【WRF教程第四期】WRF 初始化概述:以4.5版本为例

WRF 初始化&#xff08;WRF Initialization&#xff09; Building Initialization Programs编译方式 理想案例初始化&#xff08;Initialization for Idealized Cases&#xff09;理想化案例的输入可用的理想化案例 现实案例初始化&#xff08;Initialization for Real Data Ca…

vmcore-dmesg交叉编译(arm64平台)

kexec工具&#xff1a;能够将第二内核&#xff08;捕获内核&#xff09;装载到指定内存运行。 vmcore-dmesg工具&#xff1a;用于提取vmcore的dmesg信息。 1、源码下载地址&#xff1a; Index of /pub/linux/utils/kernel/kexec/ 2、交叉编译&#xff1a; 采用aarch64-lin…

计算机网络-L2TP VPN基础概念与原理

一、概述 前面学习了GRE和IPSec VPN&#xff0c;今天继续学习另外一个也很常见的VPN类型-L2TP VPN。 L2TP&#xff08;Layer 2 Tunneling Protocol&#xff09; 协议结合了L2F协议和PPTP协议的优点&#xff0c;是IETF有关二层隧道协议的工业标准。L2TP是虚拟私有拨号网VPDN&…

OpenCV学习——图像融合

import cv2 as cv import cv2 as cvbg cv.imread("test_images/background.jpg", cv.IMREAD_COLOR) fg cv.imread("test_images/forground.png", cv.IMREAD_COLOR)# 打印图片尺寸 print(bg.shape) print(fg.shape)resize_size (1200, 800)bg cv.resize…

ChatGPT重大更新:新增实时搜索和高级语音

12月17日消息&#xff0c;据报道&#xff0c;OpenAI开启了第八天技术分享直播&#xff0c;对ChatGPT搜索功能进行了大量更新。 此次ChatGPT新增的功能亮点纷呈。其中&#xff0c;实时搜索功能尤为引人注目。OpenAI对搜索算法进行了深度优化&#xff0c;使得用户提出问题后&…

30. Three.js案例-绘制并渲染圆弧

30. Three.js案例-绘制并渲染圆弧 实现效果 知识点 WebGLRenderer WebGLRenderer 是 Three.js 中用于渲染 3D 场景的核心类。它利用 WebGL 技术在浏览器中渲染 3D 图形。 构造器 new THREE.WebGLRenderer(parameters) 参数类型描述parametersObject可选参数对象&#xff…

YOLO8 改进 009:引入 ASFF 对 YOLOv8 检测头进行优化(适用于小目标检测任务)

论文题目&#xff1a;Learning Spatial Fusion for Single-Shot Object Detection 论文地址&#xff1a;Paper - ASFF 官方源码&#xff1a;GitHub - GOATmessi8/ASFF 简 介 多尺度特征融合是解决多尺度目标检测问题的关键技术&#xff0c;其中 FPN&#xff08;特征金字塔网络…

【数据集】生菜病害检测数据集530张6类YOLO+VOC格式

数据集格式&#xff1a;VOC格式YOLO格式 压缩包内含&#xff1a;3个文件夹&#xff0c;分别存储图片、xml、txt文件 JPEGImages文件夹中jpg图片总计&#xff1a;530 Annotations文件夹中xml文件总计&#xff1a;530 labels文件夹中txt文件总计&#xff1a;530 标签种类数&#…

设计模式2

23中设计模式分类 创建型模式&#xff1a;对象实例化的模式&#xff0c;创建型模式用于解耦对象的实例化过程。&#xff08;对象的创建和对象的使用分离&#xff09; 5种&#xff1a;单例模式、工厂模式、抽象工厂模式、原型模式、建造者模式 结构型模式&#xff1a;把类或对…

CSS边框的样式

边框阴影 让元素更有立体感 img {box-shadow: 2px 10px 5px 20px #ff0000;border-radius: 44px;}语法&#xff1a;box-shadow&#xff1a;值1 值2 值3 值4 值5 值1&#xff1a;水平阴影的位置值2&#xff1a;垂直阴影的位置值3&#xff1a;模糊距离值4&#xff1a;阴影的尺寸…

Spring篇--xml方式整合第三方框架

Spring xml方式整合第三方框架 xml整合第三方框架有两种整合方案&#xff1a; ​ 不需要自定义名空间&#xff0c;不需要使用Spring的配置文件配置第三方框架本身内容&#xff0c;例如&#xff1a;MyBatis&#xff1b; ​ 需要引入第三方框架命名空间&#xff0c;需要使用…