Django-(5)

本文详细介绍了Django ORM的使用,包括数据准备、模型定义、数据库迁移,以及各种查询关键字如filter、all、get等。还探讨了双下划线查询、查看SQL语句的方法。此外,文章讲解了外键字段的创建和操作,以及一对多、一对一和多对多关系的建立。最后,通过正反向概念和连表操作展示了如何进行跨表查询。
摘要由CSDN通过智能技术生成

内容概览

  • 表查询数据准备及测试环境搭建
  • ORM常见查询关键字
  • 双下划线的查询
  • 查看ORM底层SQL语句
  • ORM外键字段创建
  • 外键字段数据操作
  • 正反向概念
  • 跨表查询

表查询数据准备及测试环境搭建

  1. django切换为MySQL数据库

  2. 定义模型类

    class User(models.Model):
    	uid = models.AutoField(primary_key=True, verbose_name='编号')
    	name = models.CharField(max_lenght=32, verbose_name='姓名')
    	age = models.IntegerField(verbose_name='年龄')
    	join_time = models.DateField(auto_now_add=True)
    """
    auto_now:每次操作数据并保存都会自动更新为当前时间
    auto_now_add:在创建数据的时候保存当前时间,之后不会自动更改
    """
    
  3. 执行数据库迁移命令
    python manage.py makemigrations
    python manage.py migrate

  4. 模型层测试环境准备
    方式1:在任意空的py文件中或自带的测试文件中准备环境

    import os
    def main():
    	os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'day59.settings')
    	import django
    	django.setup()
    	"""在函数内编写测试代码"""
    
    if __name__ == '__main__':
    	main()
    

    方式2:pycharm提供测试环境
    使用python console命令行测试环境

ORM常见查询关键字

"""
先添加三条数据
models.User.objects.create(name='jason', age=18)
models.User.objects.create(name='kevin', age=24)
models.User.objects.create(name='oscar', age=36)
"""
1. fliter():筛选数据,返回值是Queryset
	print(models.User.objects.filter())  # <QuerySet [<User: User object (1)>, <User: User object (2)>, <User: User object (3)>]>
	print(models.User.objects.filter(name='jason'))  # <QuerySet [<User: User object (1)>]>
	"""
	括号内不写查询条件则返回所有查询到的数据
	括号内可以填写多个条件,使用逗号隔开,默认是and关系
	"""
2. all():查询所有数据,返回值是Queryset
	print(models.User.objects.all())  # <QuerySet [<User: User object (1)>, <User: User object (2)>, <User: User object (3)>]>
3. first():获取Queryset中第一个数据对象,如果为空则返回None
	print(models.User.objects.all().first())  # User object (1)
4. last():获取Queryset中最后一个数据对象,如果为空则返回None
	print(models.User.objects.all().last())  # User object (3)
5. get():根据条件获取具体的数据对象,如果对象不存在则报错,返回多个条件也会报错
	print(models.User.objects.get(pk=1))  # User object (1)
	print(models.User.objects.get(pk=10))  # User matching query does not exist.
	print(models.User.objects.get())  # get() returned more than one User -- it returned 3!
6. values():查询指定的字段,结果是Queryset
	print(models.User.objects.all().values('name'))  # <QuerySet [{'name': 'jason'}, {'name': 'kevin'}, {'name': 'oscar'}]>
	print(models.User.objects.values('name')  # 也可以直接写values,结果与上边一样
7. values_list():查询指定的字段,结果是Queryset
	print(models.User.objects.all().values_list())  # <QuerySet [(1, 'jason', 18, datetime.date(2022, 9, 5)), (2, 'kevin', 24, datetime.date(2022, 9, 5)), (3, 'oscar', 36, datetime.date(2022, 9, 5))]>
8. order_by():指定字段排序,默认为升序,可以在字段前加负号改为降序,并且支持多个字段排序
	"""
	可在models.py的类中重写__str__方法,能够更清晰知道当前返回的对象
	def __str__(self):
        return f'{self.name}'
	"""
    print(models.User.objects.order_by('name'))  # <QuerySet [<User: jason>, <User: kevin>, <User: oscar>]>
    print(models.User.objects.order_by('-name'))  # <QuerySet [<User: oscar>, <User: kevin>, <User: jason>]>
9. count():统计orm查询后结果的个数
	print(models.User.objects.all().count())  # 3
10. distinct:针对重复的数据集进行去重,查询的结果必须是完全相同
    print(models.User.objects.all().distinct().count())  # 3
	print(models.User.objects.all().values('join_date').distinct().count())  # 1
11. exclude:筛选出不符合括号中条件的数据,结果是Queryset
	print(models.User.objects.exclude(name='oscar'))  # <QuerySet [<User: jason>, <User: kevin>]>
12. reverse():对排过序的结果集做翻转
    print(models.User.objects.all())  # <QuerySet [<User: jason>, <User: kevin>, <User: oscar>]>
    print(models.User.objects.all().reverse())  # <QuerySet [<User: jason>, <User: kevin>, <User: oscar>]>
    print(models.User.objects.all().order_by('name'))  # <QuerySet [<User: jason>, <User: kevin>, <User: oscar>]>
    print(models.User.objects.all().order_by('name').reverse())  # <QuerySet [<User: oscar>, <User: kevin>, <User: jason>]>
13. exists():判断查询结果集是否有数据,返回布尔值
	print(models.User.objects.filter(name='jason').exists())  # True
    print(models.User.objects.filter(name='xxx').exists())  # False
14. raw():自己编写SQL语句执行
	print(list(models.User.objects.raw('select * from app01_user')))  # [<User: jason>, <User: kevin>, <User: oscar>]
	
	"""也可以使用模块"""
	from django.db import connection
    cursor = connection.cursor()
    cursor.execute("insert into app01_user(name,age, join_date) VALUES ('jerry',12,'2022-9-20')")
    cursor.execute("update app01_user set name='tom' WHERE name='kevin'")
    cursor.execute("delete from app01_user where name='oscar'")
    cursor.execute("select * from app01_user")
    print(cursor.fetchone())
    print(cursor.fetchall())

双下划线的查询

1. 比较运算符
	1. 大于:字段大于指定数据
		print(models.User.objects.filter(age__gt=25))  # <QuerySet [<User: oscar>]>
	2. 小于:字段小于指定数据
		print(models.User.objects.filter(age__lt=25))  # <QuerySet [<User: jason>, <User: kevin>]>
	3. 大于等于:字段__gte
	4. 小于等于:字段__lte
2. 成员运算符
	字段__in:字段中是否有指定数据,指定数据值必须为可迭代对象
		print(models.User.objects.filter(age__in=(18,)))  # <QuerySet [<User: jason>]>
3. 范围查询
	字段__range:获取在某个范围之间的数据
	print(models.User.objects.filter(age__range=(20, 30)))  # <QuerySet [<User: kevin>]>
4. 模糊查询
	字段__contains:查询数据中包含指定值的,不忽略大小写
		print(models.User.objects.filter(name__contains='J'))  # <QuerySet []>
	字段__icontains:查询数据中包含指定值的,忽略大小写
		print(models.User.objects.filter(name__icontains='J'))  # <QuerySet [<User: jason>]>
5. 日期处理
	字段__year:获取日期数据中包含指定年份的数据
		print(models.User.objects.filter(join_date__year=2022))  # <QuerySet [<User: jason>, <User: kevin>, <User: oscar>]>
	字段__month:获取日期数据中包含指定月份的数据
		print(models.User.objects.filter(join_date__month=9))  # <QuerySet [<User: jason>, <User: kevin>, <User: oscar>]>
	字段__day:获取日期数据中包含指定天数的数据
		print(models.User.objects.filter(join_date__day=5))  # <QuerySet [<User: jason>, <User: kevin>, <User: oscar>]>

查看ORM底层SQL语句

  1. 如果是却如Queryset对象,那么可以直接使用.query查看SQL语句
  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',
	        },
	    }
	}

ORM外键字段创建

一对多
外键字段建在多的一方
会自动添加_id后缀
代码:models.ForeignKey()
多对多
外键字段创建多对多关系有三种方式
1. 直接在查询频率较高的表中填写字段即可,自动创建第三张关系表
2. 自己创建第三张关系表
3. 自己创建第三张关系表,但还是使用orm多对多字段做关联
代码:models.ManyToManyField()
一对一
外键字段建在查询频率较高的表中
会自动添加_id后缀
代码:OneToOneField()
ps:django1版本不需要添加on_delete参数

提前准备:

class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.IntegerField(verbose_name='单价')
    publish_time = models.DateField(auto_now_add=True)
    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
    authors = models.ManyToManyField(to='Author')

    def __str__(self):
        return f'书本:{self.title}'


class Publish(models.Model):
    name = models.CharField(max_length=32)
    email = models.EmailField()

    def __str__(self):
        return f'出版社:{self.name}'


class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    author_detail = models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE)

    def __str__(self):
        return f'作者:{self.name}'


class AuthorDetail(models.Model):
    phone = models.BigIntegerField()
    address = models.CharField(max_length=255)

    def __str__(self):
        return f'作者详情:{self.phone}'

外键字段数据操作

一对多与一对一:
	方式1:直接使用实际字段名添加关联数据值
		models.Book.objects.create(title='Python', price='998', publish_id=1)
	方式2:先获取需要关联的对象,再用虚拟字段名添加关联数据值
		publish_obj = models.Publish.objects.filter(pk=1).first()
	    models.Book.objects.create(title='java', price=888, publish=publish_obj)
多对多:
	需要先获取一个对象
	models.book_obj = models.Book.objects.filter(pk=1).first()
	add():添加数据,可以填写数据值也可以填写数据对象,支持填写多个,使用逗号隔开
	    book_obj.authors.add(1)
	    book_obj.authors.add(2,3)
		author_obj = models.Author.objects.filter(pk=2).first()
	    book_obj.authors.add(author_obj)
	remove():删除数据,可以填写数据值也可以填写数据对象,支持填写多个,使用逗号隔开
		book_obj.authors.remove(1)
	    author_obj1 = models.Author.objects.filter(pk=2).first()
	    author_obj2 = models.Author.objects.filter(pk=3).first()
	    book_obj.authors.remove(author_obj1, author_obj2)
	set():修改数据,括号内必须填写可迭代对象(实际上是先删除后添加)
		book_obj.authors.set([2, 3])
	clear():清空指定数据,括号内不用填写参数
		book_obj.authors.clear()

正反向概念

正反向的关键就在于外键字段在哪里
正向查询:通过书籍查询出版社,外键字段在书籍表中
反向查询:通过出版社查询书籍,外键字段不在出版社表中

跨表查询

ORM跨表查询口诀:正向查询按外键字段,反向查询按表名小写

基于对象(子查询)
"""正向跨表查询"""
# 1.查询主键为1的书籍对应的出版社(一对多)
# 1.1.先根据条件查询数据对象(先查书籍对象)
book_obj = models.Book.objects.filter(pk=1).first()
# 1.2.以对象为基准 思考正反向概念(书查出版社 外键字段在书表中 所以是正向查询)
print(book_obj.publish)

# 2.查询主键为3的书籍对应的作者(多对多)
book_obj = models.Book.objects.filter(pk=1).first()
print(book_obj.authors)  # app01.Author.None
print(book_obj.authors.all())  # 在查询结果有多条时需要使用all

# 3.查询jason的作者详情(一对一)
author_obj = models.Author.objects.filter(name='jason').first()
print(author_obj.author_detail)


"""反向跨表查询"""
# 4.查询南方出版社出版的书籍
publish_obj = models.Publish.objects.filter(name='南方出版社').first()
print(publish_obj.book)  # 报错,还需要添加_set后缀
print(publish_obj.book_set)  # app01.Book.None
print(publish_obj.book_set.all())  # 有多个结果还是需要使用all

# 5.查询jason写过的书
author_obj = models.Author.objects.filter(name='jason').first()
print(author_obj.book_set.all())

# 6.查询电话是110的作者
uthor_detail_obj = models.AuthorDetail.objects.filter(phone=110).first()
print(author_detail_obj.author)  # 针对只有单个数据不需要加_set后缀与all
基于双下划线(连表操作)
"""正向跨表查询"""
# 1.查询主键为1的书籍对应的出版社名称及书名
res = models.Book.objects.filter(pk=1).values('publish__name', 'title')
print(res)  # 正向依然是用外键字段,查哪个字段就双下划线加字段名即可

# 2.查询主键为3的书籍对应的作者姓名及书名
res = models.Book.objects.filter(pk=3).values('authors__name', 'title')
print(res)

# 3.查询jason的作者的电话号码和地址
res = models.Author.objects.filter(name='jason').values('author_detail__phone', 'author_detail__address')
print(res)

"""反向跨表查询"""
# 4.查询南方出版社出版的书籍名称和价格
res = models.Publish.objects.filter(name='南方出版社').values('book__title', 'book_price')
print(res)  # 反向也依然使用表名小写

# 5.查询jason写过的书的名称和日期
res = models.Author.objects.filter(name='jason').values('book__title', 'book__publish_time')
print(res)

# 6.查询电话是110的作者姓名和年龄
res = models.AuthorDetail.objects.filter(phone=111).values('author__name', 'author__age')
print(res)


# 7.查询主键为1的书籍对应的作者电话号码(三张表)
res = models.Book.objects.filter(pk=1).values('authors__author_detail__phone')
print(res)
"""先从第一张表通过外键字段名进入第二张表,再直接从第二张表的外键字段名查询到第三张表的数据"""
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值