Django orm

Django链接MySQL

"""django默认使用自带的sqlite3"""
1.配置文件修改配置
	DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': '库名',  # 一定要事先创建好才能指定
        'HOST':'127.0.0.1',
        'PORT':3306,	# MySQL默认端口号3306
        'USER':'用户名',
        'PASSWORD':'密码',
        'CHARSET':'utf8'
    }
}
    
2.在项目文件夹或者应用文件夹内的__init__.py文件中书写固定的代码
	import pymysql
	pymysql.install_as_MySQLdb()

Django orm

orm:对象关系映射
    orm目的就是为了能够让不懂SQL语句的人通过python面向对象的知识点也能够轻松自如的操作数据库
    缺陷:sql封装死了,有时候查询速度很慢
		类				 >>>		 表
		对象				>>>			表里面的数据
		对象点属性		  >>>		  字段对应的值
        
1.我们的模型类需要写在应用下的models.py文件中
	class User(models.Model):
        # id int primary key auto_increment
        id = models.AutoField(primary_key=True)
        # name varchar(32)
        name = models.CharField(max_length=32)  # CharField必须要加max_length参数
        # age int
        age = models.IntegerField()
****************************************************************************
2.数据库迁移命令
	1.将数据库修改操作先记录到小本本上(对应应用下的migrations文件夹)
    	python3 manage.py makemigrations
    2.真正的执行数据库迁移操作
   		python3 manage.py migrate   
    # 只要动了models.py中跟数据库相关的代码就必须重新执行上述两条命令
****************************************************************************
3.针对主键字段
	class User1(models.Model):
        # 如果你不指定主键 那么orm会自动帮你创建一个名为id的主键字段
        # 如果你想让主键字段名不叫id 叫uid、sid、pid等则需要自己手动指定
        username = models.CharField(max_length=32)

orm数据库同步命令

"""
数据库里面已经有一些表,我们如何通过django orm操作?
	1.照着数据库表字段自己在models.py
		数据需要自己二次同步
	2.django提供的反向同步
"""
1.先执行数据库迁移命令 完成链接
	python manage.py makemigrations
2.查看代码
	python manage.py inspectdb

orm字段的增删改

# 增
pwd = models.IntegerField('密码',null=True)  # 该字段可以为空
is_delete = models.IntegerField(default=0)  # 默认值

# 改
直接改代码然后执行数据库迁移命令即可

# 删
注释掉代码然后执行数据库迁移命令即可

orm常用和非常用字段

常用
AutoField		# 自增列,如果没有的话,默认会生成一个名称为 id 的列。
				# 如果要显式的自定义一个自增列,必须设置primary_key=True
IntegerField	# 整形
FloatField		# 浮点类型
CharField		# 字符串字段
DateField		# 日期类型
	auto_now=True		# 保存时自动设置该字段为现在日期,最后修改日期
    auto_now_add=True	# 当该对象第一次被创建是自动设置该字段为现在日期,创建日期。
DateTimeField	# 日期时间类型
	auto_now=True		# 保存时自动设置该字段为现在日期,最后修改日期
    auto_now_add=True	# 当该对象第一次被创建是自动设置该字段为现在日期,创建日期。

非常用
BooleanField	# 布尔类型
TextField		# 大文本
FileField		# 文件
	upload_to=''	# 上传文件的本地文件系统路径
EmailField		# 带有检查Email合法性的CharField
GenericIPAddressField  # 带有检查IP地址合法性的CharField
URLField		# 带有URL合法性校验的CharField

orm字段参数

null		# 是否可以为空
primary_key	# 主键,对AutoField设置主键后,就会代替原来的自增 id 列
unique		# 是否唯一
db_index	# 是否给该字段建索引
default		# 默认值为
max_length	# 字段长度
choices
	-在model表模型定义的时候给某个字段指定choice
    sex_choice=((1,'男'),(2,'女'),(0,'未知'))
    sex =models.IntegerField(default=1,choices=sex_choice)
    -在使用的时候,直接取出中文
    	对象.get_sex_display()
        
了解
    verbose_name        Admin中显示的字段名称
    blank               Admin中是否允许用户输入为空
    editable            Admin中是否可以编辑
    help_text           Admin中该字段的提示信息
    choices             Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作

orm数据的增删改查

# 1.查询数据
# select * from user where name=username;
user_obj = models.User.objects.filter(name=username).first()

# 2.添加数据
# insert into user(name,pwd) values(username,password);
models.User.objects.create(name=username,pwd=password)

# 3.查询所有的数据
# select * from user;
models.User.objects.all()  # [obj1,obj2,obj3,obj4]

# 4.修改数据
方法一:
    models.User.objects.filter(id=edit_id).update(name=username,pwd=password)
方法二:
    edit_obj.name = username
    edit_obj.pwd = password
    edit_obj.save()

# 5.删除数据
models.User.objects.filter(id=delete_id).delete()

orm创建外键关系

# ORM针对外键字段的创建位置
	一对多
		推荐建在多的一方
	一对一
		建在任何一方都可以,但是推荐建在查询频率较高的表中
	多对多
		1.自己建表
		2.建在任何一方都可以,但是推荐建在查询频率较高的表中
        
class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8,decimal_places=2)  # 总共8位 小数占2位
    # 出版社外键
    publish = models.ForeignKey(to='Publish')  # 默认就是主键
    """自动在外键字段后面加_id后缀"""
    # 作者外键
    authors = models.ManyToManyField(to='Author')  # 自动帮你创建书籍和作者的第三张表
    """虚拟字段不会在表中实例化出来  而是告诉ORM创建第三张关系表"""

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

class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    author_detail = models.OneToOneField(to='AuthorDetail')
    """自动在外键字段后面加_id后缀"""

class AuthorDetail(models.Model):
    phone = models.BigIntegerField()
    addr = models.CharField(max_length=128)

ForeignKey参数

to						# 对那张表
to_field				# 对表中的某个字段
related_name			# 反向操作时,使用的字段名,用于代替原反向查询时的’表名_set’
related_query_name		# 反向查询操作时,使用的连接前缀,用于替换表名
on_delete				#当删除关联表中的数据时,当前表与其关联的行的行为。
    models.CASCADE		# 删除关联数据,与之关联也删除
    models.DO_NOTHING	# 删除关联数据,什么都不做
    models.PROTECT		# 删除关联数据,引发错误ProtectedError
    models.SET_NULL		# 删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空)
    models.SET_DEFAULT	# 删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)
    models.SET			# 删除关联数据,
        a. 与之关联的值设置为指定值,设置:models.SET(值)
        b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)
db_constraint
	True:建立外键,默认是True
	False:不建立外键
    外键是否建立:
        -好处:不会出现脏数据
        -坏处:插入的时候,效率低
        -企业中:通常不建立,程序员控制

ManyToManyField字段参数

db_table			# 指定第三张表的名字
to					# 关联的表
related_name		# 反向操作时,使用的字段名,用于代替原反向查询时的’表名_set’
related_query_name  # 反向查询操作时,使用的连接前缀,用于替换表名

through				# 手动创建第三张表,指定通过哪个表
through_fields		# 关联字段是什么

手动创建第三张表

多对多关系建立的三种方式
	第一种:自动创建(常用:第三张表没有其他字段)
    第二种:手动创建第三张表(比较常用:第三张表有多余字段)
    第三种:完全手动写第三张表
    
# 第一种:
    class Book(models.Model):
        title = models.CharField(max_length=32, verbose_name="书名")

    # 通过ORM自带的ManyToManyField自动创建第三张表
    class Author(models.Model):
        name = models.CharField(max_length=32, verbose_name="作者姓名")
        books = models.ManyToManyField(to="Book", related_name="authors")
        
# 第二种
    class Book1(models.Model):
        title = models.CharField(max_length=32, verbose_name="书名")

    # 自己创建第三张表,并通过ManyToManyField指定关联
    class Author1(models.Model):
        name = models.CharField(max_length=32, verbose_name="作者姓名")
        books = models.ManyToManyField(
            to="Book1", through="Author2Book", through_fields=("author", "book")
        )
        # through_fields 元组的第一个值是ManyToManyField所在的表去中间表通过那个字段,就写在第一个位置

    class Author2Book(models.Model):
        author = models.ForeignKey(to="Author1")
        book = models.ForeignKey(to="Book1")
        
# 第三种
    class Book1(models.Model):
        title = models.CharField(max_length=32, verbose_name="书名")

    class Author1(models.Model):
        name = models.CharField(max_length=32, verbose_name="作者姓名")

    # 自己创建第三张表,分别通过外键关联书和作者
    class Author2Book1(models.Model):
        author = models.ForeignKey(to="Author")
        book = models.ForeignKey(to="Book")

多对多操作的api

book.authors.add()				# 添加关系
book_obj.authors.remove()		# 将某个特定的对象从被关联对象集合中去除。
book_obj.authors.clear()      	# 清空被关联对象集合
book_obj.authors.set()        	# 先清空再设置

Meta元信息

# 在每一个模型类中都可以写
class Meta: #元信息
    db_table='mypublish'  #表名
    index_together=('name','city')  # 多个字段联合索引
    unique_together=('name','city') # 联合唯一
    ordering=('nid', ) # 默认以哪个字段排序

原生sql

res = models.Author.objects.raw('select * from app01_book where nid>1')
for book in res:
    print(book.price)

# 执行原生sql,跟对象类型无关了,查出什么字段,可以直接使用该字段

orm单表查询关键字

QuerySet对象方法
	query  # 查看orm内部对应的SQL语句
    
# 增
    res = models.Books.objects.create(title='西游记',price=687.90)
    print(res.title)
    '''create返回值就是当前被创建的数据对象'''
    
# 查
    res = models.Books.objects.all()
    print(res.query)
    res = models.Books.objects.filter()
    print(res.query)
    res = models.Books.objects.filter(title='jason')
    print(res)
    """filter括号内可以放多个参数 默认是and关系  推荐使用  条件不符合不会报错"""
    
    res1 = models.Books.objects.get(title='jason')
    print(res1)
    """get括号内可以放多个参数 默认是and关系  不推荐使用  条件不符合直接报错"""
    
# 改
    res = models.Books.objects.filter(pk=1).update(price=666.66)
    print(res)  # 返回值是受影响的行数

    book_obj = models.Books.objects.filter(pk=2).first()
    book_obj.price = 999.66
    book_obj.save()  # 效率低(所有字段重新写一遍)
    """pk能够自动查找到当前表的主键字段 我们不需要查看当前表主键字段名"""
    
# 删
    models.Books.objects.filter(pk=1).delete()

.first()  # 取第一个数据对象
    res = models.Books.objects.all().first()
    res1 = models.Books.objects.all()[0]
    res2 = models.Books.objects.all()[0:2]
    print(res,res1,res2)
    """QuerySet对象还支持切片操作 但是只能填正数"""
    
.last()  # 取最后一个数据对象
    res = models.Books.objects.all().last()
    print(res)
    
.values()  # 获取数据指定字段的值
    res = models.Books.objects.all().values('title','publish_time')
    res1 = models.Books.objects.values('title','publish_time')
    print(res,res1)
    """all()加不加都表示所有数据  values获取的结果 类似于列表套字典"""
    
.values_list()  # 获取数据指定字段的值
    res = models.Books.objects.values_list('title', 'publish_time')
    print(res)
    """values_list获取的结果 类似于列表套元组"""
    
.order_by()  # 排序
    res = models.Books.objects.order_by('price')  # 默认是升序
    print(res)
    res1 = models.Books.objects.order_by('-price')  # 减号降序
    print(res1)
    
.count()  # 计数
    res = models.Books.objects.count()  # 统计数据条数
    print(res)
    
.distinct()  # 去重
    res = models.Books.objects.all().distinct()
    res1 = models.Books.objects.values('title').distinct()
    print(res1)
    """去重的前提是数据必须是一模一样  一定不能忽略主键"""
    
.exclude()  # 排除什么什么在外  取反操作
    res = models.Books.objects.exclude(title='西游记')
    print(res.query)
    
.reverse()	# 反转
    res = models.Books.objects.all()
    res1 = models.Books.objects.reverse()
    res2 = models.Books.objects.order_by('price').reverse()
    print(res)
    print(res1)
    print(res2)
    """reverse需要先排序之后才能反转"""
    
.exists()  判断是否有数据 返回布尔值
    res = models.Books.objects.all().exists()
    print(res)

神奇的双下划綫查询(范围查询)

__gt	# 大于
	查询价格大于700的书籍
    models.Books.objects.filter(price__gt=700)
    
__lt	# 小于
	查询价格小于700的书籍
    models.Books.objects.filter(price__lt=700)
    
__gte、__lte		# 大于等于、小于等于
	价格大于等于700 小于等于700
    models.Books.objects.filter(price__gte=700)
    models.Books.objects.filter(price__lte=700)
    
__in	# 在这之中
	查询价格要么是40 要么是50 要么是60
    models.Books.objects.filter(price__in=[40,50,60])
    
__range		# 在什么之间
	查询价格在500到800之间的
    models.Books.objects.filter(price__range=(500,800))
    
__contains	# 包含
	查询书名中包含字母s的书
    models.Books.objects.filter(title__contains='s')  # 区分大小写
    models.Books.objects.filter(title__icontains='s')  # 区分大小写
    
__year、__month	# 筛选年、月
	查询出版日期是2021年3月的书
    models.Books.objects.filter(publish_time__year=2021,publish_time__month=3)

跨表查询理论

正向
	外键字段在谁那儿,谁查另外的人就是正向
反向
	没有外键字段
# 就是判断你是否有关联的外键字段

"""
正向查询按外键字段
反向查询按表名小写加_set
"""

基于对象的跨表查询

# 子查询
"""
1.先查询出一个对象
2.基于对象点正反向字段
"""

查询神雕侠侣对应的作者
book_obj = models.Book.objects.filter(title='神雕侠侣').first()
res = book_obj.authors.all()

查询东方出版社出版过的书籍
author_obj = models.Author.objects.filter(name='jason').first()
res = author_obj.book_set.all()

基于双下划线的跨表查询

查询神雕侠侣对应的作者名字
res = models.Book.objects.filter(title='神雕侠侣').values('authors__name')
res = models.Author.objects.filter(book__title='神雕侠侣').values('name','age')

聚合查询

from django.db.models import Sum,Avg,Max,Min,Count
1 聚合函数,sum,max,min,count,avg
2 把聚合结果字段重命名
res=models.Book.objects.all().aggregate(aaa=Sum('price'))

F查询

F 查询:取出某个字段对应的值
from django.db.models import F

查询评论数大于阅读数的书籍
res=models.Book.objects.filter(commit_num__gt=F('read_num'))
print(res)

把所有图书价格+1
res=models.Book.objects.all().update(price=F('price')+1)
print(res) # 影响额行数

Q查询

Q 查询:构造出 与&、或|、非~

查询名字叫红楼梦并且者价格大于100的书
models.Book.objects.filter(name='红楼梦'&price__gt=100)

查询名字叫红楼梦或者价格大于100的书
models.Book.objects.filter(Q(name='红楼梦')|Q(price__gt=100))

查询名字不是红楼梦,并且价格大于100的书
models.Book.objects.filter(~Q(name='红楼梦')&Q(price__gt='100'))

分组查询

annotate() 内写聚合函数
  	values在前,表示group by 的字段
    values在后,表示取字段
    filter在前,表示where条件
    filter在后,表示having
    
查询出版社id大于1的出版社id,以及出书平均价格
models.Book.objects.values('publish_id').filter(publish_id__gt=1).annotate(price_ave=Avg('price')).values('publish_id','price_ave')

django查看原生sql

1 queryset对象.query

2 通过日志,如下,配置到setting.py中
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console':{
            'level':'DEBUG',
            'class':'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level':'DEBUG',
        },
    }
}

Djago admin的使用

1 后台管理,方便我们快速的录入书籍
2 使用方法:
	第一步:在admin.py 中把要使用的表注册
    	from app01 import models
        admin.site.register(models.Book)
        admin.site.register(models.Author)
        admin.site.register(models.AuthorDatail)
        admin.site.register(models.Publish)
   第二步:创建个超级管理员
		python3 manage.py createsuperuser 
    	输入用户名,输入密码
        
   第三步:登录,录入书籍
		-http://127.0.0.1:8000/admin/
posted @ 2021-04-12 10:12  最冷不过冬夜  阅读(97)  评论(0编辑  收藏  举报