Django之ORM操作


目录
  • 双下划线查询
    • 数据准备
    • 具体操作
  • orm创建外键关系
  • 外键字段的增删改查
  • 正反向的概念
    • 正向
    • 反向
  • 多表查询
    • 基于对象的跨表查询
    • 基于双下划线的跨表查询
    • 双下线查询扩展
  • 如何查看SQL语句
    • 方式1:句点符加query查看
    • 方式2:配置文件固定配置

双下划线查询

数据准备

class Staff(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    salary = models.DecimalField(max_digits=8, decimal_places=2)
    recruit_time = models.DateField(auto_now=True)

    def __str__(self):
        return "%s-对象" % self.name
models.Staff.objects.create(name='linda', age=22, salary=25000.00)
models.Staff.objects.create(name='rose', age=24, salary=15000.00)
models.Staff.objects.create(name='frank', age=32, salary=35000.00)
models.Staff.objects.create(name='laurence', age=24, salary=25000.00)
models.Staff.objects.create(name='steve', age=42, salary=15000.00)
models.Staff.objects.create(name='july', age=32, salary=35000.00)
models.Staff.objects.create(name='sam', age=27, salary=42000.00)
models.Staff.objects.create(name='tom', age=33, salary=28000.00)
models.Staff.objects.create(name='Simon', age=43, salary=45000.00)

具体操作

# 一、查询年龄小于等于27的员工
staff_obj = models.Staff.objects.filter(age__lte=27)
print(staff_obj)
	"""
    __gt         大于
    __lt         小于
    __gte        大于等于
    __lte        小于等于
    """
# 二、查询年龄是24、32、42的员工
staff_obj = models.Staff.objects.filter(age__in=[14, 32, 42])
print(staff_obj
	"""
    __in         成员运算
    """
# 三、查询年龄在25到30之间的员工
 staff_obj = models.Staff.objects.filter(age__range=[25, 30])
 print(staff_obj)
	"""
    __range      范围查询
    """
# 四、查询姓名中包含字母s的员工
 staff_obj = models.Staff.objects.filter(name__contains='s')
 print(staff_obj)  # , , ]>
 staff_obj = models.Staff.objects.filter(name__icontains='s')
 print(staff_obj)  # , , , ]>
	"""
    __contains      区分大小写
    __icontains     忽略大小写
    """
# 五、查询姓名中首字母为j的员工
      staff_obj = models.Staff.objects.filter(name__startswith='j')
      print(staff_obj)  # ]>
# 六、查询姓名中尾字母为e的员工
      staff_obj = models.Staff.objects.filter(name__endswith='e')
      print(staff_obj)  # 
# 七、查询姓名中s开头m结尾的员工
      staff_obj = models.Staff.objects.filter(name__regex='^s.*m$')
      print(staff_obj)  # ]>
# 八、查询招聘月份是5月的员工
      staff_obj = models.Staff.objects.filter(recruit_time__month=5)
      print(staff_obj)  # , , ]>
# 九、查询招聘年份是2020年的员工
      staff_obj = models.Staff.objects.filter(recruit_time__year=2020)
      print(staff_obj)  # , , ]>

orm创建外键关系

class Staff(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    salary = models.DecimalField(max_digits=8, decimal_places=2)
    recruit_time = models.DateField(auto_now=True)

    def __str__(self):
        return "%s-对象" % self.name


# 图书表
class Book(models.Model):
    book_title = models.CharField(max_length=64, verbose_name='图书名')
    book_price = models.DecimalField(max_digits=6, decimal_places=2, verbose_name='图书价格')
    publish_time = models.DateField(auto_now=True, verbose_name='出版日期')
    publish = models.ForeignKey(to='Press')
    authors = models.ManyToManyField(to='Author')

    def __str__(self):
        return "%s-图书对象" % self.book_title


# 出版社表
class Press(models.Model):
    press_name = models.CharField(max_length=64, verbose_name='出版社名称')
    press_addr = models.CharField(max_length=64, verbose_name='出版社地址')

    def __str__(self):
        return "%s-出版社对象" % self.press_name


# 作者表
class Author(models.Model):
    author_name = models.CharField(max_length=64, verbose_name='作者姓名')
    author_age = models.IntegerField(verbose_name='作者年龄')
    author_details = models.OneToOneField(to='AuthorDetail')

    def __str__(self):
        return "%s-作者对象" % self.author_name


# 作者详情表
class AuthorDetail(models.Model):
    author_addr = models.CharField(max_length=64, verbose_name='作者地址')
    author_phone = models.BigIntegerField(verbose_name='作者联系方式')

    def __str__(self):
        return "%s-作者详情对象" % self.author_addr

外键字段的增删改查

# 一对多、一对一外键字段操作
  增
    models.Book.objects.create(book_title='初中地理', book_price=29, publish_id=1)
    publish_obj = models.Press.objects.filter(pk=3).first()
    models.Book.objects.create(book_title='初中生物', book_price=36, publish=publish_obj)
  改
    res = models.Book.objects.filter(pk=5).update(publish_id=1)
    print(res)
    publish_obj = models.Press.objects.filter(pk=2).first()
    res = models.Book.objects.filter(pk=6).update(publish_id=publish_obj)
    print(res)
 
# 多对多字段操作
  一、第三张关系表创建数据
    book_obj = models.Book.objects.filter(pk=2).first()
    book_obj.authors.add(3, 4)
    book_obj = models.Book.objects.filter(pk=3).first()
    author_obj = models.Author.objects.filter(pk=5).first()
    book_obj.authors.add(author_obj)
	注意:括号内可以放主键值也可以放数据对象,并且都支持多个
  二、第三张关系表修改数据
    book_obj = models.Book.objects.filter(pk=2).first()
    book_obj.authors.set([5])
    注意:括号内必须是一个可迭代对象,元素同样支持主键值或者数据对象
  三、第三张关系表删除数据
    book_obj = models.Book.objects.filter(pk=2).first()
    book_obj.authors.remove(5)
    注意:括号内可以放主键值也可以放数据对象并且都支持多个
  四、第三张关系表清空指定数据
    book_obj = models.Book.objects.filter(pk=3).first()
    book_obj.authors.clear()
    注意:括号内无需传值,直接清空当前表在第三张关系表中的绑定记录

正反向的概念

核心在于当前数据对象是否含有外键字段:有则是正向,没有则是反向

正向

eg:
由书籍查询出版社,外键字段在书籍表中,那么书查出版社就是'正向'
由书籍查询作者,外键字段在书籍表中,那么书查作者就是'正向'
由作者查询作者详情,外键字段在作者表中,那么也是'正向'

反向

eg:
由出版社查询书籍 外键字段不在出版社表 那么出版社查书就是'反向'

多表查询

基于对象的跨表查询

基于对象的跨表查询本质就是子查询即分步操作即可

# 查询初中生物书籍对应的出版社
# book_obj = models.Book.objects.filter(book_title='初中生物').first()
# res = book_obj.publish
# print(res)  # 西南师范大学出版社-出版社对象

# 查询小学英语对应的作者
# book_obj = models.Book.objects.filter(book_title='小学英语').first()
# res = book_obj.authors.all()
# print(res)  # , ]>

# 查询作者david的详情信息
# author_obj = models.Author.objects.filter(author_name='david').first()
# res = author_obj.author_details
# print(res)  # 北京-作者详情对象

# 查询四川大学出版社出版的书籍
# publish_obj = models.Press.objects.filter(press_name='四川大学出版社').first()
# res = publish_obj.book_set.all()
# print(res)  # , , ]>

# 查询朱巍编写的书籍
# author_obj = models.Author.objects.filter(author_name='朱巍').first()
# res = author_obj.book_set.all()
# print(res)  # , ]>

# 查询地址在杭州的作者
# author_detail_obj = models.AuthorDetail.objects.filter(author_addr='杭州').first()
# res = author_detail_obj.author
# print(res)  # 李华-作者对象

基于双下划线的跨表查询

基于双下划线的跨表查询本质就是联表操作

# 查询科学世界书籍对应的出版社名称
# res = models.Press.objects.filter(book__book_title='科学世界')
# print(res)  # ]>
# res = models.Press.objects.filter(book__book_title='科学世界').values('press_name')
# print(res)  # 

# 查询地理探索对应的作者姓名和年龄
# res = models.Author.objects.filter(book__book_title='地理探索').values('author_name', 'author_age')
# print(res)  # 

# 查询作者david的联系方式和地址
# res = models.AuthorDetail.objects.filter(author__author_name='david').values('author_phone', 'author_addr')
# print(res)  # 

# 查询西南师范大学出版社出版的书籍名称和价格
# res = models.Book.objects.filter(publish__press_name='西南师范大学出版社').values('book_title', 'book_price')
# print(res)  # 

# 查询王涛编写的书籍名称和日期
# res = models.Book.objects.filter(authors__author_name='王涛').values('book_title', 'publish_time')
# print(res)  # 

# 查询地址在北京的作者的姓名和年龄
# res = models.Author.objects.filter(author_details__author_addr='北京').values('author_name', 'author_age')
# print(res)  # 

双下线查询扩展

基于双下划线的跨表查询的结果也可以是完整的数据对象

# 查询科学世界书籍对应的出版社名称
# res = models.Press.objects.filter(book__book_title='科学世界').first()
# print(res)  # 四川大学出版社-出版社对象

# 查询地理探索对应的作者姓名和年龄
# res = models.Author.objects.filter(book__book_title='地理探索').values('author_name', 'author_age')
# print(res)  # 

# 查询作者david的联系方式和地址
# res = models.AuthorDetail.objects.filter(author__author_name='david').values('author_phone', 'author_addr')
# print(res)  # 

# 查询西南师范大学出版社出版的书籍名称和价格
res = models.Book.objects.filter(publish__press_name='西南师范大学出版社').values('book_title', 'book_price')
print(res)  # 

# 查询王涛编写的书籍名称和日期
# res = models.Book.objects.filter(authors__author_name='王涛').values('book_title', 'publish_time')
# print(res)  # 

# 查询地址在北京的作者的姓名和年龄
# res = models.Author.objects.filter(author_details__author_addr='北京').values('author_name', 'author_age')
# print(res)  # 

# 连续跨表操作
# 查询小学英语对应的作者的地址
res = models.AuthorDetail.objects.filter(author__book__book_title='小学英语').values('author_addr')
print(res)  # 

# 获取多张表里面的字段数据
# 查询初中数学对应的作者的地址和出版社名称
res = models.AuthorDetail.objects.filter(author__book__book_title='初中数学').values('author_addr', 'author__book__publish__press_name')
print(res)  # 

如何查看SQL语句

方式1:句点符加query查看

如果结果集对象是queryset可以点query查看

方式2:配置文件固定配置

只要执行了orm操作都会打印内部SQL语句

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level': 'DEBUG',
        },
    }
}