Fork me on GitHub
随笔 - 234  文章 - 49 评论 - 0 阅读 - 13万
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

ORM是什么

ORM(Object-Relational Mapping,对象关系映射)是一种用于简化数据库操作的技术。它通过将数据库中的表映射为编程语言中的对象,使开发者能够以面向对象的方式操作数据库,而不需要直接编写复杂的SQL语句。

ORM 的工作原理:

ORM 框架将数据库中的每一个表映射为程序中的一个类,表中的每一行映射为类的一个实例(对象),表中的每一列则映射为对象的一个属性。这样,开发者可以通过操作对象来对数据库进行增删改查等操作,而不需要手动编写 SQL 语句。

ORM 的优点:

  1. 简化数据库操作:使用 ORM 可以让开发者更专注于业务逻辑,而不必花费大量时间编写和调试 SQL 语句。
  2. 可维护性和可读性:ORM 提供了更抽象和面向对象的编程方式,代码通常更加简洁和易于维护。
  3. 跨数据库支持:ORM 框架通常能够支持不同的数据库,只需要更改配置文件即可实现数据库切换,而不需要改动代码。
  4. 安全性:ORM 能有效防止 SQL 注入等常见的数据库安全问题。

常见的 ORM 框架:

  • Django ORM(Python):Django Web 框架自带的 ORM,用于与 MySQL、PostgreSQL、SQLite 等数据库交互。
  • SQLAlchemy(Python):一个功能强大的 Python ORM 库,支持多种数据库。
  • Hibernate(Java):一个广泛使用的 Java ORM 框架,通常与 Spring 框架一起使用。
  • Entity Framework(C#):微软为 .NET 开发的 ORM 框架,用于和 SQL Server、MySQL 等数据库交互。

创建 Django ORM 模型类

在 Django 中,ORM 模型类用于将数据库中的表映射为 Python 对象,每个模型类对应数据库中的一张表,类的属性对应表中的字段。

在 Django 中,模型类需要继承 django.db.models.Model 类,并且模型类的每个属性代表 table 的一个字段。

示例模型类

假设我们有一个应用场景要记录用户信息,可以创建一个 User 模型类:

from django.db import models

class User(models.Model):
    # 字段定义
    name = models.CharField(max_length=100)  # 字符串字段,对应数据库中的 VARCHAR
    email = models.EmailField()  # 邮箱字段,Django 提供的特殊类型
    age = models.IntegerField()  # 整数字段
    created_at = models.DateTimeField(auto_now_add=True)  # 自动设置为记录创建时间

    # 可选方法,用于表示对象的字符串形式
    def __str__(self):
        return self.name

在 Django 中,可以通过运行迁移命令将 models.py 中定义的模型类转换为数据库中的表。这个过程分为两步:创建迁移文件应用迁移到数据库

步骤 1:创建迁移文件

迁移文件是 Django 用于记录模型变更的文件。你可以通过以下命令创建迁移文件:
在项目目录下执行创建迁移文件命令python manage.py makemigrations

PS E:\devops> python manage.py makemigrations
Migrations for 'myapp':
  myapp\migrations\0001_initial.py
    - Create model User

该命令会根据 models.py 中的模型定义,生成一组迁移文件,这些文件会记录模型的创建或更新。生成的迁移文件会存储在应用程序的 migrations 文件夹中。

步骤 2:应用迁移到数据库

创建完迁移文件后,接下来需要将这些迁移应用到数据库中。你可以通过以下命令执行迁移操作,将模型类转换为数据库中的表:

在项目目录下执行迁移到数据库命令python manage.py migrate

PS E:\devops> python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, myapp, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying myapp.0001_initial... OK
  Applying sessions.0001_initial... OK

这个命令会读取所有的迁移文件,并在数据库中创建对应的表结构。

步骤 3:查看迁移的数据库表结构

每个迁移前的 [X] 表示该迁移已经被应用到数据库,说明你的数据库架构已经与这些迁移保持同步

PS E:\devops> python manage.py showmigrations
admin
 [X] 0001_initial
 [X] 0002_logentry_remove_auto_add
 [X] 0003_logentry_add_action_flag_choices
auth
 [X] 0001_initial
 [X] 0002_alter_permission_name_max_length
 [X] 0003_alter_user_email_max_length
 [X] 0004_alter_user_username_opts
 [X] 0005_alter_user_last_login_null
 [X] 0006_require_contenttypes_0002
 [X] 0007_alter_validators_add_error_messages
 [X] 0008_alter_user_username_max_length
 [X] 0009_alter_user_last_name_max_length
 [X] 0010_alter_group_name_max_length
 [X] 0011_update_proxy_permissions
 [X] 0012_alter_user_first_name_max_length
contenttypes
 [X] 0001_initial
 [X] 0002_remove_content_type_name
myapp
 [X] 0001_initial
sessions
 [X] 0001_initial

常见问题

  1. 数据库配置:确保你已经正确配置了数据库连接信息,在项目的 settings.py 文件中,DATABASES 配置应包含你的数据库信息。例如:
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',  # 或者使用 'postgresql', 'sqlite3', 'oracle' 等
        'NAME': 'your_db_name',
        'USER': 'your_db_user',
        'PASSWORD': 'your_db_password',
        'HOST': 'localhost',  # 例如,如果使用远程数据库,可以写上 IP
        'PORT': '3306',  # 对应的数据库端口
    }
}

2.在应用中创建models.py:需要在settings.py文件中进行设置
应用是否添加到INSTALLED_APPS

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'myapp',  # 你的应用
]

3.修改模型后:如果你对模型进行了修改,例如增加字段或删除字段,需要重新执行:

python manage.py makemigrations
python manage.py migrate
python manage.py showmigrations

通过这些步骤,Django 会将 models.py 中的模型类自动转换为数据库中的表,简化数据库结构管理。

要数据库中检查

mysql> show create table myapp_user\G
*************************** 1. row ***************************
       Table: myapp_user
Create Table: CREATE TABLE `myapp_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(100) NOT NULL,
  `email` varchar(254) NOT NULL,
  `age` int(11) NOT NULL,
  `created_at` datetime(6) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

常用字段类型

Django 提供了丰富的字段类型来表示不同类型的数据。常用的字段类型有:

  1. CharField:用于存储短字符串,需指定 max_length 参数,表示最大字符数。
name = models.CharField(max_length=100)
  1. IntegerField:用于存储整数类型。
age = models.IntegerField()
  1. BooleanField:存储布尔值(TrueFalse)。
is_active = models.BooleanField(default=True)
  1. EmailField:用于存储电子邮件地址,会自动验证格式。
email = models.EmailField()
  1. DateFieldDateTimeField:用于存储日期和日期时间类型数据。
birthday = models.DateField()
created_at = models.DateTimeField(auto_now_add=True)
  1. ForeignKey:用于定义多对一的关系,表示当前模型和另一个模型之间的关系。
group = models.ForeignKey(Group, on_delete=models.CASCADE)
  1. ManyToManyField:用于定义多对多的关系。
tags = models.ManyToManyField(Tag)
  1. TextField:用于存储大段文本,类似于 SQL 的 TEXT 类型。
description = models.TextField()

元选项 (Meta Options)

Django 模型类可以通过 Meta 内部类来配置一些额外的选项,例如指定数据库表名、排序等:

class User(models.Model):
    name = models.CharField(max_length=100)
    email = models.EmailField()

    class Meta:
        # 指定表名
        db_table = 'user_table'
        # 默认排序方式
        ordering = ['-created_at']

简化操作orm

一般地都是编写views.py文件去操作models.py中的模型类,通过前端url访问,这种方式太过繁琐,此时仅通过操作orm对象修改数据库表数据

  1. 启用Django shell,在项目根目录下
python manage.py shell

就可以像在views.py文件中一样,导入模型类操作orm对象

  1. ipython 结合 Django shell,同样在根目录下,结合ipython的自动补全,好处多多(推荐使用)
python manage.py shell -i ipython
  1. 直接登录到mysql,查询表信息,此时已直接进入settings.py文件指定的数据库中,可直接执行sql语句
python manage.py dbshell

常见的模型操作

  1. 创建对象并保存到数据库
user = User(name="Alice", email="alice@example.com", age=25)
user.save()
  1. 查询对象
# 查询所有对象
users = User.objects.all()

# 根据条件查询对象
user = User.objects.get(id=1)
  1. 更新对象
user = User.objects.get(id=1)
user.age = 30
user.save()
  1. 删除对象
user = User.objects.get(id=1)
user.delete()

以下为在ipython中的操作

from myapp.models import models, User

user=User(name="Alice",email="alice@example.com",age=25)

user.save()

users = User.objects.all()

print(users)
#<QuerySet [<User: Alice>]>

user.age=30

user.save()

user.delete()
#(1, {'myapp.User': 1})

对应数据库中的数据变化

mysql> select * from myapp_user;
+----+-------+-------------------+-----+----------------------------+
| id | name  | email             | age | created_at                 |
+----+-------+-------------------+-----+----------------------------+
|  1 | Alice | alice@example.com |  25 | 2024-09-07 06:57:25.496603 |
+----+-------+-------------------+-----+----------------------------+
1 row in set (0.00 sec)

mysql> select * from myapp_user;
+----+-------+-------------------+-----+----------------------------+
| id | name  | email             | age | created_at                 |
+----+-------+-------------------+-----+----------------------------+
|  1 | Alice | alice@example.com |  30 | 2024-09-07 06:57:25.496603 |
+----+-------+-------------------+-----+----------------------------+
1 row in set (0.00 sec)

mysql> select * from myapp_user;
Empty set (0.00 sec)

模型操作

新增数据

save()方法

最常见的方式是实例化一个模型对象,然后使用 .save() 方法将该对象保存到数据库。

# 1. 创建一个 User 对象
user = User(name="John Doe", email="john@example.com", age=25)

# 2. 保存对象到数据库
user.save()
create()方法

使用 create() 方法直接创建并保存数据

# 使用 create() 方法直接创建并保存数据
user = User.objects.create(name="Alice", email="alice@example.com", age=30)
批量插入数据

bulk_create() 可以一次性插入多个对象,性能比逐个保存要更好

# 创建多个 User 对象的列表
users = [
    User(name="Bob", email="bob@example.com", age=22),
    User(name="Charlie", email="charlie@example.com", age=28),
    User(name="Daisy", email="daisy@example.com", age=35),
]

# 批量插入数据到数据库中
User.objects.bulk_create(users)

get_or_create方法

如果你希望在插入数据前先检查是否存在该条记录,可以使用 get_or_create() 方法。它会先尝试从数据库中查找匹配的对象,如果没有找到,则创建新对象并保存。

user, created = User.objects.get_or_create(
    name="John Doe",
    email="john@example.com",
    defaults={'age': 25}
)

if created:
    print("新用户已创建")
else:
    print("用户已存在")

update_or_create方法

如果你希望先检查记录是否存在,如果存在则更新记录,否则创建新记录,可以使用 update_or_create() 方法

user, created = User.objects.update_or_create(
    email="john@example.com",
    defaults={'name': "John Doe", 'age': 26}
)

if created:
    print("新用户已创建")
else:
    print("用户信息已更新")

查询数据

方法 1:all()

all() 方法用于查询表中的所有记录。

# 查询所有用户
users = User.objects.all()

all() 返回的是一个 QuerySet,即一组查询结果。

方法 2:filter()

filter() 方法用于根据条件过滤查询结果,返回所有匹配条件的对象。

# 查询年龄大于 25 的用户
users = User.objects.filter(age__gt=25)

# 查询名字为 "John Doe" 的用户
users = User.objects.filter(name="John Doe")

filter() 支持链式调用,可以组合多个条件。

方法 3:get()

get() 方法用于根据条件获取单个对象。如果查询的条件返回多个结果或没有结果,它会抛出异常。

# 查询 email 为 'john@example.com' 的用户
try:
    user = User.objects.get(email="john@example.com")
except User.DoesNotExist:
    print("用户不存在")
except User.MultipleObjectsReturned:
    print("查询返回了多个用户")

get() 通常用于唯一性查询,确保条件返回的是单个结果。

方法 4:exclude()

exclude() 方法用于排除符合条件的记录,它的作用与 filter() 相反。

# 查询年龄不是 25 的用户
users = User.objects.exclude(age=25)

exclude() 返回不符合条件的对象集合。

方法 5:order_by()

order_by() 方法用于对查询结果进行排序。默认是升序,前面加上 - 表示降序。

# 按年龄升序排序
users = User.objects.order_by('age')

# 按创建时间降序排序
users = User.objects.order_by('-created_at')

方法 6:values()values_list()

values() 方法用于返回指定字段的字典,而不是整个对象;values_list() 则返回一个包含字段值的元组。

# 只获取用户的名字和邮箱,返回字典
users = User.objects.values('name', 'email')

# 只获取用户的名字和邮箱,返回元组
users = User.objects.values_list('name', 'email')

方法 7:count()

count() 方法用于返回查询结果的数量。

# 查询年龄大于 25 的用户数量
count = User.objects.filter(age__gt=25).count()

方法 8:first()last()

first()last() 方法分别返回查询结果的第一个和最后一个对象。

# 获取第一个用户
first_user = User.objects.first()

# 获取最后一个用户
last_user = User.objects.last()

方法 9:exists()

exists() 方法用于检查是否有满足条件的对象,返回布尔值。

# 检查是否有年龄大于 25 的用户
user_exists = User.objects.filter(age__gt=25).exists()

方法 10:aggregate()annotate()

aggregate() 方法用于执行聚合函数,如 COUNTSUMAVG 等;annotate() 则用于在查询结果中附加聚合数据。

from django.db.models import Count, Avg

# 计算所有用户的平均年龄
average_age = User.objects.aggregate(Avg('age'))

# 每个年龄有多少用户
age_count = User.objects.values('age').annotate(count=Count('id'))

方法 11:distinct()

distinct() 方法用于去除查询结果中的重复记录。

# 查询所有不同的用户年龄
distinct_ages = User.objects.values('age').distinct()

这些方法用于优化查询外键和多对多关系的字段,减少数据库查询次数。

# 假设 User 有一个外键 `group`,使用 select_related 进行外键的优化查询
users = User.objects.select_related('group').all()

# 假设 User 有一个多对多字段 `tags`,使用 prefetch_related 进行优化查询
users = User.objects.prefetch_related('tags').all()

修改数据

1.通过模型实例进行修改

修改数据最常见的方式是先查询出需要修改的对象,对其属性进行更改,然后调用 .save() 方法保存到数据库中。

# 1. 查询出需要修改的对象
user = User.objects.get(id=1)

# 2. 修改属性
user.name = "New Name"
user.age = 30

# 3. 保存修改
user.save()

说明:

  • 查询对象:使用 get()filter() 查询需要修改的对象。
  • 修改属性:通过直接赋值修改模型对象的属性值。
  • 保存数据:调用 .save() 方法将修改保存到数据库中。Django 会自动生成 UPDATE 语句
2.批量更新(update() 方法)

如果需要一次性修改多个对象的某个字段,可以使用 update() 方法。该方法会生成一个 UPDATE SQL 语句,直接修改满足条件的所有对象。

# 批量修改年龄大于 25 岁的用户,将他们的年龄设置为 26
User.objects.filter(age__gt=25).update(age=26)

说明:

  • update() 方法会直接在数据库中执行,不会逐个加载对象到内存中,因此效率更高。
  • 该方法只适用于批量更新,并且只能更新对象的某些字段,无法调用 save() 来触发模型实例的额外逻辑(如 save() 方法中的自定义逻辑)。
3.更新或创建(update_or_create() 方法)

如果你想实现“如果对象存在则更新,不存在则创建”的逻辑,update_or_create() 方法非常适合。

# 如果用户邮箱为 'john@example.com' 的记录存在,则更新名字;否则创建新用户
user, created = User.objects.update_or_create(
    email='john@example.com',
    defaults={'name': 'John Doe', 'age': 26}
)

if created:
    print("新用户已创建")
else:
    print("用户信息已更新")
说明:
  • update_or_create() 方法会先查询是否有符合条件的对象,如果存在,则更新它;如果不存在,则创建新的对象。
注意事项:
  1. .save() 方法:当你通过实例进行修改时,必须手动调用 .save() 方法才能将修改保存到数据库。
  2. update() 方法:该方法适用于批量修改操作,但它不会调用模型的 save() 方法,也不会触发 pre_savepost_save 信号。
  3. 事务控制:如果在修改数据时涉及多个步骤,建议使用 Django 的事务机制来确保数据一致性。

删除数据

1.删除单条数据
# 获取一条数据
record = User.objects.get(id=1)

# 删除这条数据
record.delete()
2.删除多条数据

你可以通过filter()方法筛选出符合条件的多条数据,然后使用delete()方法一次性删除它们。

# 筛选出满足条件的多条数据
records = User.objects.filter(status='inactive')
# 删除这些数据
records.delete()

注意delete()方法会直接从数据库中删除数据,删除后无法恢复,请谨慎操作。

3.批量删除

你可以通过filter()方法筛选出符合条件的多条数据,然后使用delete()方法一次性删除它们。

# 分批删除,避免大量数据删除时的性能问题
batch_size = 100
qs = User.objects.filter(status='inactive')

while qs.exists():
    qs[:batch_size].delete()

注意delete()方法会直接从数据库中删除数据,删除后无法恢复,请谨慎操作。

4.使用事务删除数据

如果你希望在删除数据时使用事务,可以通过Django的transaction模块来确保数据一致性。

from django.db import transaction
from myapp.models import User

# 使用事务确保一致性
with transaction.atomic():
    User.objects.filter(status='inactive').delete()
posted on   anyux  阅读(75)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示