Django模型ORM操作

Django模型之ORM操作

ORM介绍

  • 什么是ORM
    ORM 全拼Object-Relation Mapping.

    中文意为 对象-关系映射.

    在MVC/MVT设计模式中的Model模块中都包括ORM

  • ORM优势

    • 只需要面向对象编程, 不需要面向数据库编写代码.

      对数据库的操作都转化成对类属性和方法的操作.
      不用编写各种数据库的sql语句.

    • 实现了数据模型与数据库的解耦, 屏蔽了不同数据库操作上的差异.

      不在关注用的是mysql、oracle…等.
      通过简单的配置就可以轻松更换数据库, 而不需要修改代码.

  • ORM劣势
    相比较直接使用SQL语句操作数据库,有性能损失.
    根据对象的操作转换成SQL语句,根据查询的结果转化成对象, 在映射过程中有性能损失.

  • ORM和数据库关系:
    在Django中model是你数据的单一、明确的信息来源。它包含了你存储的数据的重要字段和行为。通常,一个模型(model)映射到一个数据库表.

    基本情况:

    每个模型都是一个Python类,它是django.db.models.Model的子类。

    模型的每个属性都代表一个数据库字段。

ORM操作

模型创建
from django.db import models


class BaseModel(models.Model):
    """
    基础类
    """
    create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    update_time = models.DateTimeField(auto_now=True, verbose_name="修改时间")
    is_delete = models.BooleanField(default=False, verbose_name="删除标志")
    creator = models.CharField(max_length=64, verbose_name="创建人", null=True, blank=True)
    operator = models.CharField(max_length=64, verbose_name="维护人", null=True, blank=True)

    class Meta:
        abstract = True
        
        
class Cate(BaseModel):
    """
    设备分类
        服务器、网络设备
    """

    cate_name = models.CharField(max_length=64, verbose_name="分类名称", db_index=True, unique=True)
    parent_id = models.ForeignKey('self', on_delete=models.SET_NULL, verbose_name="上级ID", null=True, blank=True)

    class Meta:
        db_table = "tb_cate"
        verbose_name = "分类名称"
        verbose_name_plural = verbose_name


class Vendor(BaseModel):
    """
    设备厂商
    """
    vendor = models.CharField(max_length=64, verbose_name="设备厂商", db_index=True, unique=True)

    class Meta:
        db_table = "tb_vendor"
        verbose_name = "设备厂商"
        verbose_name_plural = verbose_name


class EquipmentInfo(BaseModel):
    """
    设备信息表
    """
    inst_name = models.CharField(max_length=128, verbose_name="设备名称", db_index=True)
    server_ip = models.CharField(max_length=64, verbose_name="管理IP", unique=True)
    cate = models.ForeignKey(Cate, on_delete=models.CASCADE, verbose_name="所属分类")
    vendor = models.ForeignKey(Vendor, on_delete=models.CASCADE, verbose_name="所属厂商")
    detail = models.CharField(max_length=512, verbose_name="详情描述", null=True, blank=True)

    class Meta:
        db_table = "tb_equip"
        verbose_name = "设备信息"
        verbose_name_plural = verbose_name


class AccountInfo(BaseModel):
    """
    设备的账号信息
    """
    LEVEL_CHOICE = (
        (0, "超级用户"),
        (1, "运维账户"),
        (2, "普通账户")
    )
    equip = models.ForeignKey(EquipmentInfo, on_delete=models.CASCADE, verbose_name="关联的设备")

    account = models.CharField(max_length=128, verbose_name="账号信息")
    password = models.CharField(max_length=512, verbose_name="密码")

    level = models.IntegerField(default=2, verbose_name="账户级别")

    class Meta:
        db_table = "tb_account"
        verbose_name = "设备账户"
        verbose_name_plural = verbose_name

数据迁移命令

python manage.py makemigrations # 生成迁移文件

python manage.py migrate # 执行迁移文件生成数据库表

数据创建
1、实例化方式创建数据
cate = Cate()
cate.cate_name = "交换机"
cate.save()

print(cate) --> Cate object (1)

2、使用ORM中的create方法创建数据
# create 添加数据
cate_obj = Cate.objects.create(cate_name="路由器")

print(cate_obj) --> Cate object (2)

3、bulk_create批量创建数据
# 批量添加数据 bulk_create
cate_list = [Cate(cate_name=item) for item in ["防火墙", "负载均衡"]]
Cate.objects.bulk_create(cate_list)
4、 bulk_create批量创建数据并去重
cate_list = [Cate(cate_name=item) for item in ["防火墙", "负载均衡"]]
    Cate.objects.bulk_create(cate_list, ignore_conflicts=True)

ignore_conflicts 对数据进行去重操作,对应的字段需要设置成unique=True

5、添加一对多外键
# 添加外键关联
equip = EquipmentInfo.objects.create(
    inst_name="互联网区交换换机6881-M1",
    server_ip="106.129.11.100",
    cate_id=1,
    vendor_id=1,
    detail="互联网区交换机6881"
)

print(equip) --> EquipmentInfo object (1)

6、以对象的形式添加外键
# 以对象的形式添加外键
cate_obj = Cate.objects.get(pk=1)
vendor_obj = Vendor.objects.get(pk=1)
equip = EquipmentInfo.objects.create(
    inst_name="互联网区交换换机6881-M2",
    server_ip="106.129.11.101",
    cate=cate_obj,
    vendor=vendor_obj,
    detail="互联网区交换机6881-M2"
)

print(equip) --> EquipmentInfo object (2)

注意: 这种添加方式,多了两次查询,会有一定的性能消耗

数据修改
1、按属性字段进行修改
# 按属性进行修改
vendor_obj = Vendor.objects.get(pk=2)
vendor_obj.vendor = "思科"
vendor_obj.save()

print(f"修改前厂商名称: {vendor_obj.vendor}") --> 修改前厂商名称: 华为1

print(f"修改后厂商名称: {vendor_obj.vendor}") --> 修改后厂商名称: 思科

2、使用update进行修改
# update方式修改
vendor_obj = Vendor.objects.filter(pk=2).update(vendor="山石")

print(vendor_obj) --> 1

注意: update修改时,要使用filter过滤指定的数据,否则会全部修改

3、批量修改数据 bulk_update

数据删除
1、delete()删除数据
# 查找要删除的数据对象
vendor_obj = Vendor.objects.filter(pk=2).first()
vendor_obj.delete()
数据查询操作【重要】
1、查询所有数据 all()
# 1. 查询所有的分类
cate_queryset = Cate.objects.all()

# 查询结果
# <QuerySet [<Cate: 交换机>, <Cate: 路由器>, <Cate: 防火墙>, <Cate: 负载均衡>]>
2、使用filter()方法查询数据

filter方法可以根据条件进行过滤自己想要的数据

# 1. 不跟查询条件,查询所有数据
cate_queryset = Cate.objects.filter()
# 查询结果 <QuerySet [<Cate: 交换机>, <Cate: 路由器>, <Cate: 防火墙>, <Cate: 负载均衡>]>

# 2. 过滤名称为 “交换机” 的数据
cate_queryset = Cate.objects.filter(cate_name='交换机')
# 查询结果  <QuerySet [<Cate: 交换机>]>

# 3. 查询名称包含“思科”的设备信息
inst_queryset = EquipmentInfo.objects.filter(inst_name__contains='思科')
print(inst_queryset)
# 查询结果  <QuerySet [<EquipmentInfo: 互联网区路由器思科3945-M1>, <EquipmentInfo: 互联网区路由器思科3945-M2>]>

# 注意: contains 和 icontains的区别  icontains是忽略大小写

# 4. 查询id 在列表内的数据
inst_queryset = EquipmentInfo.objects.filter(id__in=[1, 2])
print(inst_queryset)
# 查询结果 <QuerySet [<EquipmentInfo: 互联网区交换换机6881-M1>, <EquipmentInfo: 互联网区交换换机6881-M2>]>
3、 exclude(**kwargs) 查询条件之外的数据
cate_queryset = Cate.objects.exclude(cate_name='负载均衡')
print(cate_queryset)
# <QuerySet [<Cate: 交换机>, <Cate: 路由器>, <Cate: 防火墙>]>
4、 values()函数,返回一个特殊的QuerySet,运行后得到的并不是model的实例化对象,而是一个可迭代的字典序列
cate_queryset = Cate.objects.filter(pk=1).values('id', 'is_delete', 'cate_name', 'creator')
print(cate_queryset)
# 查询结果  <QuerySet [{'id': 1, 'is_delete': False, 'cate_name': '交换机', 'creator': None}]>
5、values_list() 按指定的字段返回可迭代的元组集合
cate_queryset = Cate.objects.filter(id__in=[1, 2]).values_list('id', 'cate_name', 'parent_id')
print(cate_queryset)
# 查询结果 <QuerySet [(1, '交换机', None), (2, '路由器', None)]>
6、 order_by() 对查询结果集进行排序
cate_queryset = Cate.objects.filter().order_by('-id')
print(cate_queryset)
# <QuerySet [<Cate: 负载均衡>, <Cate: 防火墙>, <Cate: 路由器>, <Cate: 交换机>]>
7、 count() 统计当前查询集的对象个数
cate_queryset = Cate.objects.filter()
print(cate_queryset.count())
# 查询结果  4
8、 first() 获取当前查询集的第一条数据
cate_queryset = Cate.objects.filter()
print(cate_queryset.first())
# 查询结果 交换机
9、 last() 获取当前查询集的最后一条数据
cate_queryset = Cate.objects.filter()
print(cate_queryset.last())
# 查询结果 负载均衡
10、 exists() 判断当前查询集是否存在
cate_queryset = Cate.objects.filter(id=1)
print(cate_queryset.exists())
# 查询结果 True
外键相关操作
外键查询操作
1. 一对多外键关联查询
# 查询分类下的设备信息
cate_queryset = Cate.objects.filter(id=1).first()
inst_queryset = cate_queryset.equipmentinfo_set.all()
print(inst_queryset)
# 查询结果 <QuerySet [<EquipmentInfo: 互联网区交换换机6881-M1>, <EquipmentInfo: 互联网区交换换机6881-M2>]>
2. 根据设备查询分类信息的名称
# 根据设备查询分类信息的名称
inst_obj = EquipmentInfo.objects.filter(pk=1).first()
cate_name = inst_obj.cate.cate_name
print(cate_name)
# 查询结果  交换机
外键修改操作
1. 使用外键对象进行修改
cate_obj = Cate.objects.filter(pk=2).first()
inst_obj = EquipmentInfo.objects.filter(pk=1).first()
print(f"修改前:{inst_obj.cate}")  # 修改前: 交换机
inst_obj.cate = cate_obj
inst_obj.save()
print(f"修改后: {inst_obj.cate}")  # 修改后: 路由器
2. 使用外键ID进行修改
inst_obj = EquipmentInfo.objects.filter(pk=1).first()
print(f"修改前: {inst_obj.cate.pk}")  # 修改前:2
inst_obj.cate_id = 1
inst_obj.save()
print(f"修改后: {inst_obj.cate.pk}")  # 修改后:1
3. 使用update方法进行修改
inst_queryset = EquipmentInfo.objects.filter(pk=2)
inst_queryset.update(cate_id=2)
print(inst_queryset)  
# 查询结果 <QuerySet [<EquipmentInfo: 互联网区交换换机6881-M2>]>

注意:update进行修改时是批量修改,所以使用update修改的时候,要结合过滤条件进行修改,否则会把所有数据修改。

查询优化
1. select_related() 基于连表查询,一对一/多外键
  • 对于一对一字段(OneToOneField)和外键字段(ForeignKey),可以使用select_related来对QuerySet进行优化。
  • select_related 返回一个QuerySet,当执行它的查询时,它沿着外键关系查询关联的对象的数据。 表之间进行join连表操作,一次性获取关联的数据。
inst_queryset = EquipmentInfo.objects.filter().select_related('cate')
print(inst_queryset)
# 查询结果: <QuerySet [<EquipmentInfo: 互联网区交换换机6881-M1>, <EquipmentInfo: 互联网区交换换机6881-M2>]>
2.prefetch_related()

多表连表操作时速度会慢,使用其执行多次SQL查询在Python代码中实现连表操作。分别在多表中查询到结果,然后重组。

cate_inst_queryset = Cate.objects.prefetch_related('equipmentinfo_set').filter(is_delete=False)
print(cate_inst_queryset)
# 查询结果: <QuerySet [<Cate: 交换机>, <Cate: 路由器>, <Cate: 防火墙>, <Cate: 负载均衡>]>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值