模型层相关

模型层

单表操作

Django自带的sqlite3数据库对日期格式不是很敏感,处理的时候容易出错。

注册时间记录
class User(models.Model):
    name = models.CharField(max_length=32, verbose_name='姓名')
    age = models.IntegerField(verbose_name='年龄')
    register_time = models.DateField(verbose_name='注册时间')  # 年月日
    """
        - DateField
        - DateTimeField
            - 两个重要的参数
                - auto_now:每次操作数据的时候,该字段会自动将当前时间更新
                - auto_now_add:在创建数据的时候会自动将当前创建的时间记录下来,之后只要不人为的修改时间就不会变
    """

测试脚本书写格式
"""
	- 测试环境的准备 去manage.py中拷贝前四行代码
	- 然后自己写两行
		- import django
		  django.setup()

	- 脚本代码无论是写在应用下的tests.py还是自己单独开设py文件都可以
"""

import os
import sys

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day64.settings")
    import django
    django.setup()
	
    # 所有的代码只有等待环境加载完毕才能进行书写
    from app01 import models

    models.User.objects.all()
单表增删改查
# 增
1.create()
2.对象.save()

# 查
1.all()  # 查询所有
2.filter()  # 筛选条件  没有查询到则返回None
3.get()  # 筛选条件  条件不存在则报错  不推荐使用

# 改
1.update()  # 实际上是QuerySet封装的批量更新方法
2.对象.save()

# 删
1.delete()  # QuerySet封装的批量删除方法
2.对象.delete()  # 对象中封装好的方法

注意:

在实际的项目中,数据不会直接删除,会在数据里添加一个字段进行标记。


# 增
import datetime
now_time = datetime.datetime.now()
user_obj = models.User(name='张三', age='18', register_time=now_time)  # 获取对象
user_obj.save()  # 保存

# 删
"""方式1"""
res = models.User.objects.filter(pk=2).delete()
print(res)  # 返回当前sql语句所影响的行数
"""
        - pk会自动查找当前表的主键字段,指代的就是当前表的主键字段
        - 用了pk就不需要知道当前表的主键字段名称是什么,提高效率
    """

"""方式2"""
user_obj = models.User.objects.filter(pk=3).first()
user_obj.delete()

# 改
"""方式1"""
models.User.objects.filter(pk=1).update(name='李四')

"""方式2"""
user_obj = models.User.objects.get(pk=1)
    print(user_obj)
    """
        User object
        - get方法直接返回当前的数据对象  
        - 但是不推荐使用,一旦数据不存在,则会报错
    """
    user_obj.name = '王五'
    user_obj.save()
    
# 查
query_set = models.User.objects.all()
print(query_set.first().name)

必知必会查询13条
"""常用的查询方式"""
1.all()  # 查询所有数据
2.filter()  # 过滤查询  查询不到返回None
3.get()  # 直接获取数据  查询不到报错
4.values()  # 获取指定字段的对应数据 返回的结果是一个queryset对象(列表套字典形式)
5.values_list()  # 获取指定字段对应的数据 返回的结果是一个queryset对象(列表套元组形式)
6.count()  # 统计查询出来的数据的个数
7.first()  # 拿取queryset里面第一个元素

# 1.all()  查询所有数据

# 2.filter()     带有过滤条件的查询  查询不到数据不会报错  会返回None

# 3.get()        直接拿数据对象 但是条件不存在直接报错

# 4.first()      拿queryset里面第一个元素
# res = models.User.objects.all().first()
# print(res)


# 5.last()
# res = models.User.objects.all().last()
# print(res)

"""重要内容"""
# 6.values()  可以指定获取的数据字段  select name,age from ...     列表套字典
# res = models.User.objects.values('name','age')  # <QuerySet [{'name': 'jason', 'age': 18}, {'name': 'egonPPP', 'age': 84}]>
# print(res)


# 7.values_list()  列表套元组
# res = models.User.objects.values_list('name','age')  # <QuerySet [('jason', 18), ('egonPPP', 84)]>
# print(res)
"""
查看内部封装的sql语句
上述查看sql语句的方式  只能用于queryset对象
只有queryset对象才能够点击query查看内部的sql语句
"""

# ******************************************

# 8.distinct()  去重
# res = models.User.objects.values('name','age').distinct()  # 获取name和age字段数据并去重  一定不能包含主键信息
# print(res)
"""
    去重一定要是一模一样的数据
    如果带有主键那么肯定不一样 你在往后的查询中一定不要忽略主键

"""

# 9.order_by()
# res = models.User.objects.order_by('age')  # 默认升序
# res = models.User.objects.order_by('-age')  # 降序
# print(res)

# 10.reverse()  反转  前提是数据已经排过序了  order_by()
# res = models.User.objects.all()
# res1 = models.User.objects.order_by('age').reverse()
# print(res,res1)

# 11.count()  统计当前数据的个数
# res = models.User.objects.count()
# print(res)

# 12.exclude()  排除在外
# res = models.User.objects.exclude(name='张三')  获取不包含 张三 的字段数据  
# print(res)

# 13.exists()  基本用不到因为数据本身就自带布尔值  返回的是布尔值
# res = models.User.objects.filter(pk=10).exists()
# print(res)
ORM内部的SQL语句的查看
# 方式1
res = models.User.objects.values_list('name','age')  # <QuerySet [('jason', 18), ('egonPPP', 84)]>
print(res.query)

# queryset对象才能够点击query查看内部的sql语句

# 方式2:所有的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',
        },
    }
}
双下划线查询
1.__gt  # 大于  greate than
2.__lt  # 小于  less than
3.__gte # 大于等于
4.__lte  # 小于等于
5.__in  # 成员运算
6.__range  # 范围查询  顾头也顾尾
7.__contains  # 模糊查询  默认区分大小写
8.__icontains  # 模糊查询 忽略大小写

# 只按照年份或者月份查询
9.create_time_year
10.create_time_month

# 1 年龄大于35岁的数据
# res = models.User.objects.filter(age__gt=35)  # greater than
# print(res)
# 2 年龄小于35岁的数据
# res = models.User.objects.filter(age__lt=35)  # less than
# print(res)
# 大于等于 小于等于
# res = models.User.objects.filter(age__gte=32)
# print(res)
# res = models.User.objects.filter(age__lte=32)
# print(res)

# 年龄是18 或者 32 或者40
# res = models.User.objects.filter(age__in=[18,32,40])  # in
# print(res)

# 年龄在18到40岁之间的  首尾都要
# res = models.User.objects.filter(age__range=[18,40])  # range  顾头也顾尾
# print(res)

# 查询出名字里面含有s的数据  模糊查询  sql中是like
# res = models.User.objects.filter(name__contains='s')  # contains -->包含
# print(res)
#
# 是否区分大小写  查询出名字里面含有p的数据  区分大小写
# res = models.User.objects.filter(name__contains='p')
# print(res)
# 忽略大小写
# res = models.User.objects.filter(name__icontains='p')  # icontains  i-->ignore
# print(res)

# res = models.User.objects.filter(name__startswith='j')
# res1 = models.User.objects.filter(name__endswith='j')
# print(res,res1)


# 查询出注册时间是 2020 1月
# res = models.User.objects.filter(register_time__month='1')
# res = models.User.objects.filter(register_time__year='2020')

一对多外键增删改查

from django.db import models

# Create your models here.


class Book(models.Model):
    title = models.CharField(max_length=32, verbose_name='书籍名称')
    price = models.DecimalField(max_digits=8, decimal_places=2, verbose_name='书籍价格')
    publish_date = models.DateField(auto_now_add=True, verbose_name='出版时间')

    """书籍和出版社是一对多的关系"""
    publish = models.ForeignKey(to='Publish')

    """书籍和作者是多对多的关系"""
    authors = models.ManyToManyField(to='Author')

class Publish(models.Model):
    name = models.CharField(max_length=32, verbose_name='出版社名称')
    addr = models.CharField(max_length=64, verbose_name='出版社地址')
    email = models.EmailField()  # 出版社邮箱地址  varchar(254)


class Author(models.Model):
    name = models.CharField(max_length=32, verbose_name='作者姓名')
    age = models.IntegerField()

    """作者和作者信息是一对一关系"""
    author_detail = models.OneToOneField(to='AuthorDetail')


class AuthorDetail(models.Model):
    phone = models.BigIntegerField(verbose_name='电话号码')  # 也可以使用CharField()
    addr = models.CharField(max_length=64, verbose_name='住址')




增
"""一对多外键增删改查"""
# 增
"""方式1:直接写实际字段---> id"""
models.Book.objects.create(title='三国演义', price=123.23, publish_id=1)

"""方式2:虚拟字段--->对象"""
publish_obj = models.Publish.objects.filter(pk=2).first()
models.Book.objects.create(title='红楼梦', price=666.66, publish=publish_obj)

删
# 删
models.Publish.objects.filter(pk=1).delete()  # 级联删除  删除出版社-->对应的书籍也删除

改
# 改
"""方式1:直接update方法"""
models.Book.objects.filter(pk=1).update(publish_id=2)  # 将主键为1的书籍对应的出版社改为2

"""方式2:对象方式"""
publish_obj = models.Publish.objects.filter(pk=1).first()
models.Book.objects.filter(pk=1).update(publish=publish_obj)  # 将主键为1的书籍的出版社改为1

多对多外键增删改查

增
"""多对多外键增删改查  --->   实际上是对第三章关系表的增删改查"""
# ****************************
book_obj = models.Book.objects.filter(pk=1).first()  # 先拿到主键为1的书籍的对象
# ****************************

# print(book_obj.authors)  # 就类似于你已经到了第三张关系表了

"""方式1:添加主键"""
book_obj.authors.add(1)  # 书籍主键为1的书籍添加主键为1的作者
book_obj.authors.add(2, 3)  # 书籍主键为1的书籍添加主键为2和3的作者

"""方式2:添加对象"""
author_obj1 = models.Author.objects.filter(pk=1).first()
author_obj2 = models.Author.objects.filter(pk=2).first()
author_obj3 = models.Author.objects.filter(pk=3).first()

book_obj.authors.add(author_obj1)
book_obj.authors.add(author_obj1, author_obj2,author_obj3)


"""
    add给第三张关系表添加数据
    括号内既可以传数字也可以传对象 并且都支持多个
"""
删
# 删
book_obj = models.Book.objects.filter(pk=1).first()  # 先拿到主键为1的书籍的对象
"""方式1:主键"""
book_obj.authors.remove(2)  # 删除author_id为2的数据

"""方式2:对象"""
author_obj1 = models.Author.objects.filter(pk=1).first()
author_obj3 = models.Author.objects.filter(pk=3).first()
book_obj.authors.remove(author_obj1, author_obj3)
"""
    remove
        括号内既可以传数字也可以传对象 并且都支持多个
    """
改
# 改
book_obj = models.Book.objects.filter(pk=1).first()  # 先拿到主键为1的书籍的对象
"""方式1:主键"""
book_obj.authors.set([1, 2])  # set必须传可迭代对象  将对应的作者主键改为1和2
# 有数据就不变 无数据就新增  也就是先删除再新增

"""方式2:对象"""
author_obj1 = models.Author.objects.filter(pk=1).first()
author_obj2 = models.Author.objects.filter(pk=2).first()
author_obj3 = models.Author.objects.filter(pk=3).first()
book_obj.authors.set([author_obj1, author_obj2, author_obj3])

"""
    set
        括号内必须传一个可迭代对象,该对象内既可以数字也可以对象 并且都支持多个
"""
清空
# 清空
# 在第三张关系表中清空某个书籍与作者的绑定关系
book_obj = models.Book.objects.filter(pk=1).first()  # 先拿到主键为1的书籍的对象
book_obj.authors.clear() # 清空主键为1的书籍的全部作者绑定关系

"""
    clear
        括号内不要加任何参数
"""

正反向概念

# 正向
外键字段在我手上那么,我查你就是正向

# 反向
外键字段如果不在手上,我查你就是反向
  
  book >>>外键字段在书那儿(正向)>>> publish
  publish	>>>外键字段在书那儿(反向)>>>book
  
  一对一和多对多正反向的判断也是如此
  
"""
正向查询按字段
反向查询按 表名 小写
				_set
				.all()
"""

多表操作

子查询(基于对象的跨表查询)
  • 正向查询

正向查询按外键字段。

"""基于对象的跨表查询"""
# 1.查询书籍主键为1的出版社
book_obj = models.Book.objects.filter(pk=1).first()
"""正向查询按字段"""
publish = book_obj.publish  # 表中有publish外键字段   拿到的是对象
print(publish)
# 如果数据是多个  则publish.all() 进行数据展示
print(publish.name, publish.addr)


# 2.查询书籍主键为2的作者
book_obj = models.Book.objects.filter(pk=2).first()
"""书查作者-->正向"""
# res = book_obj.authors  # app01.Author.None 则表示ORM语句少一个.all()方法
res = book_obj.authors.all()  # <QuerySet [<Author: Author object>]>
print(res)


# 3.查询作者为王五的电话号码
author_obj = models.Author.objects.filter(name='王五').first()
res = author_obj.author_detail  # AuthorDetail object
print(res)
print(res.phone, res.addr)


"""
    在书写orm语句的时候跟写sql语句一样的
    不要企图一次性将orm语句写完 如果比较复杂 就写一点看一点
    
    正向什么时候需要加.all()
        当你的结果可能有多个的时候就需要加.all()
        如果是一个则直接拿到数据对象
            book_obj.publish
            book_obj.authors.all()
            author_obj.author_detail
"""
  • 反向查询

反向查询按表名小写,有时候需要加_set或者.all()。

"""反向查询"""
# 4.查询是 东方出版社 出版的书籍
publish_obj = models.Publish.objects.filter(name='东方出版社').first()
"""出版社查书--->反向"""
# 反向查询按照 表名小写_set  如:查书 --> book.set
# res = publish_obj.book_set  # app01.Book.None
res = publish_obj.book_set.all()
print(res)


# 5.查询作者是 张三 写过的书籍
author_obj = models.Author.objects.filter(name='张三').first()
"""作者查书--->反向"""
# res = author_obj.book_set  # app01.Book.None
res = author_obj.book_set.all()  # <QuerySet [<Book: Book object>, <Book: Book object>, <Book: Book object>]>
print(res)
for book in res:
    print(book.title, book.price)
    """
            红楼梦 666.66
            三国演义 123.23
            论语 23.23
    """
    

# 6.查询手机号是 888 的作者姓名
author_detail_obj = models.AuthorDetail.objects.filter(phone=888).first()
res = author_detail_obj.author
print(res)  # Author object
print(res.name, res.age)  # 李四 100

基于对象反向查询方法
 """
    基于对象 
        反向查询的时候
            当你的查询结果可以有多个的时候 就必须加_set.all()
            当你的结果只有一个的时候 不需要加_set.all()
"""
联表查询(基于双下划线的跨表查询)
"""MySQL联表操作"""
inner join  # 内连接  拼接共有数据
left join  # 左连接  全展示左表数据  右表无对应数据则显示null
right join  # 右连接  全展示右表数据 左表无对应数据则显示null
union  # 全连接  左右两表数据全部展示出来

"""基于双下划线的跨表查询"""
# 1.查询主键为1的出版社名称和书的名称
res = models.Book.objects.filter(pk=1).values('title', 'publish__name')  # title书的名称  publish__name出版社名称
print(res)  # <QuerySet [{'title': '三国演义', 'publish__name': '东方出版社'}]>
print(res.first().get('title'), res.first().get('publish__name'))  # 三国演义 东方出版社


# 2.查询 张三 的手机号
"""
        - author_detail  到这个表
            - author_detail__phone  要phone这个字段

"""
res = models.Author.objects.filter(name='张三').values('author_detail__phone', 'name')
print(res)  # <QuerySet [{'author_detail__phone': 123, 'name': '张三'}]>


# 3.查询书籍主键为1的作者姓名
"""正向"""
res = models.Book.objects.filter(pk=1).values('authors__name')
print(res)  # <QuerySet [{'authors__name': '张三'}]>

"""反向"""
res = models.Author.objects.filter(book__id=1).values('name')  # 反向表名小写
print(res)  # <QuerySet [{'name': '张三'}]>


# 4.查询书籍主键是1的作者的手机号
""" book ---> author ---> author_detail"""
res = models.Book.objects.filter(pk=1).values('authors__author_detail__phone')
print(res)  # <QuerySet [{'authors__author_detail__phone': 123}]>
print(res.first().get('authors__author_detail__phone'))  # 123

聚合查询(aggregate)

通常情况下都是配合分组一起使用的。

"""聚合查询:aggregate"""
"""
    聚合查询通常情况下都是配合分组进行使用的
        - 同数据库相关的模块基本上都在django.db.models中
        - 或者在django.db中
"""
from app01 import models
from django.db.models import Max, Min, Sum, Count, Avg

# 1.统计所有书籍的平均价格
avg_price = models.Book.objects.aggregate(Avg('price'))
print(avg_price)  # {'price__avg': 238.376}

# 2.将上述方法一次性全部展示
res = models.Book.objects.aggregate(Max('price'), Min('price'), Sum('price'), Count('pk'), Avg('price'))
print(res)
# {'price__max': Decimal('666.66'), 'price__min': Decimal('23.23'), 'price__sum': Decimal('1191.88'), 'pk__count': 5, 'price__avg': 238.376}

分组查询(annotate)

"""
    MySQL分组查询都有哪些特点
        分组之后默认只能获取到分组的依据 组内其他字段都无法直接获取了
            严格模式
                ONLY_FULL_GROUP_BY
                
"""

"""分组查询:annotate"""
from django.db.models import Max, Min, Sum, Count, Avg

# 1.统计每一本书的作者个数
# res = models.Book.objects.annotate()  # models后面点什么 就是按什么分组  这里是按照书分组
res = models.Book.objects.annotate(author_num=Count('authors')).values('title', 'author_num')  # 正向查询按字段
"""
    author_num是我们自己定义的字段 用来存储统计出来的每本书对应的作者个数
"""
print(res)
# <QuerySet [{'title': '三国演义', 'author_num': 1}, {'title': '红楼梦', 'author_num': 2}, {'title': '论语', 'author_num': 2}, {'title': '中庸', 'author_num': 1}, {'title': '老子', 'author_num': 2}]>
# 等价于以下代码
# res1 = models.Book.objects.annotate(author_num=Count('authors__id')).values('title','author_num')


# 2.统计每个出版社卖的最便宜的书的价格
"""按照出版社分组  获取书籍的价格最小的   反向查询  表名小写__price"""
res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name', 'min_price')
print(res)  # <QuerySet [{'name': '东方出版社', 'min_price': Decimal('23.23')}, {'name': '北方出版社', 'min_price': Decimal('323.23')}]>


# 3.统计不止一个作者的图书
"""
        - 按照图书分组  
            - 先按照图书分组,获取一本书对应的作者个数
            - filter过滤出作者个数>1的图书  __gt
    """
res = models.Book.objects.annotate(author_num = Count('authors')).filter(author_num__gt=1).values('title', 'author_num')
print(res)  # <QuerySet [{'title': '红楼梦', 'author_num': 2}, {'title': '论语', 'author_num': 2}, {'title': '老子', 'author_num': 2}]>

"""
   只要你的orm语句得出的结果还是一个queryset对象
   那么它就可以继续无限制的点queryset对象封装的方法

"""


# 4.查询每个作者出的书的总价格
"""
    - 按照作者分组
        - 作者查书-->反向  book__price 获取书的价格
    - 获取作者书籍的价格并计算总价
"""
res = models.Author.objects.annotate(sum_price=Sum('book__price')).values('name', 'sum_price')
print(res)
# <QuerySet [{'name': '张三', 'sum_price': Decimal('868.65')}, {'name': '李四', 'sum_price': Decimal('745.42')}, {'name': '王五', 'sum_price': Decimal('323.23')}]>

按照指定的字段进行分组

models.Book.objects.values('price').annotate()

进行分组查询报错,则需要修改数据库的严格模式。

F和Q查询

F查询

能够帮助你直接获取到表中某个字段对应的数据。

"""F查询"""
from app01 import models
from django.db.models import F
# 1.查询销量大于库存的书籍
res = models.Book.objects.filter(sales__gt=F('stock'))
print(res)
for book in res:
    print(book.title)  # 论语 中庸 老子

# 2.将所有书籍的价格提升100块
    """
    也就是所有书的价格基于原来书的价格增加100
    """
models.Book.objects.update(price=F('price') + 100)

# 3.将所有书的名称后面加上爆款两个字
    """
    在操作字符类型的数据的时候 F不能够直接做到字符串的拼接
    """
from django.db.models.functions import Concat  # 拼接模块
from django.db.models import Value

models.Book.objects.update(title=Concat(F('title'), Value('爆款')))
Q查询
"""Q查询"""
from app01 import models
from django.db.models import Q
# 1.查询销量大于100或者价格小于600的书籍
# res = models.Book.objects.filter(maichu__gt=100,price__lt=600)
"""filter括号内多个参数是and关系"""
res1 = models.Book.objects.filter(Q(maichu__gt=100),Q(price__lt=600)) # , 与
res2 = models.Book.objects.filter(Q(sales__gt=100)|Q(price__lt=600))  # | 或
res3 = models.Book.objects.filter(~Q(maichu__gt=100)|Q(price__lt=600)) # ~ 非
print(res2)
for book in res2:
    print(book.title, book.sales, book.price)
    """
        三国演义 800 323.23
        红楼梦 1000 866.66
        论语 2000 223.23
        中庸 800 523.23
        老子 1500 255.53
       """

# Q的高阶用法  能够将查询条件的左边也变成字符串的形式   用户能够指定其搜索形式
q = Q()
q.connector = 'or'  # 将默认的and改为or
"""
Q源码解析:
# Connection types
    AND = 'AND'
    OR = 'OR'
    default = AND
"""
q.children.append(('sales__gt', 100))
q.children.append(('price__lt', 600))
res = models.Book.objects.filter(q)  # 默认为and关系
print(res) # <QuerySet [<Book: Book object>, <Book: Book object>, <Book: Book object>, <Book: Book object>, <Book: Book object>]>
for book in res:
    print(book.title, book.sales, book.price)

Django中事务的开启

"""
事务
	ACID
		原子性
			不可分割的最小单位
		一致性
			跟原子性是相辅相成
		隔离性
			事务之间互相不干扰
		持久性
			事务一旦确认永久生效
	
	事务的回滚 
		rollback
	事务的确认
		commit
"""
# 目前你只需要掌握Django中如何简单的开启事务
# 事务
    from django.db import transaction
    try:
        with transaction.atomic():
            # sql1
            # sql2
            ...
            # 在with代码块内书写的所有ORM操作都是属于同一个事务
    except Exception as e:
        print(e)
    print('执行其他操作')

ORM中常用字段及参数

AutoField()

主键字段 primary_key=True。

CharField

对应到数据库里面是varchar,verbose_name字段的注释,max_length长度。

IntegerField

对应数据库中的int。

BigIntegerField

对应数据库中的bigint。

DateField

日期字段,日期格式 YYYY-MM-DD,相当于Python中的datetime.date()实例。

DateTimeField

日期时间字段,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],相当于Python中的datetime.datetime()实例。

auto_now:每次修改数据的时候都会自动更新当前时间
auto_now_add:只在创建数据的时候记录创建时间,后续不会自动修改
EmailField()

字符串类型,Django Admin以及ModelForm中提供验证机制,相当于varcahr(254)。

TextField()

文本类型,用来存大段内容(文章、博客等大内容)。

FileField()

文件字段。

- 字符串,路径保存在数据库,文件上传到指定目录
        - 参数:
            upload_to = ""      上传文件的保存路径
            storage = None      存储组件,默认django.core.files.storage.FileSystemStorage
            
         - upload_to = "/data"
给该字段传一个文件对象,会自动将文件保存到/data目录下,
然后将文件路径保存到数据库中
  /data/a.txt
常用和非常用字段
 AutoField(Field)
        - int自增列,必须填入参数 primary_key=True

    BigAutoField(AutoField)
        - bigint自增列,必须填入参数 primary_key=True

        注:当model中如果没有自增列,则自动会创建一个列名为id的列
        from django.db import models

        class UserInfo(models.Model):
            # 自动创建一个列名为id的且为自增的整数列
            username = models.CharField(max_length=32)

        class Group(models.Model):
            # 自定义自增列
            nid = models.AutoField(primary_key=True)
            name = models.CharField(max_length=32)

    SmallIntegerField(IntegerField):
        - 小整数 -32768 ~ 32767

    PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
        - 正小整数 0 ~ 32767
    IntegerField(Field)
        - 整数列(有符号的) -2147483648 ~ 2147483647

    PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
        - 正整数 0 ~ 2147483647

    BigIntegerField(IntegerField):
        - 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807

    BooleanField(Field)
        - 布尔值类型

    NullBooleanField(Field):
        - 可以为空的布尔值

    CharField(Field)
        - 字符类型
        - 必须提供max_length参数, max_length表示字符长度

    TextField(Field)
        - 文本类型

    EmailField(CharField):
        - 字符串类型,Django Admin以及ModelForm中提供验证机制

    IPAddressField(Field)
        - 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制

    GenericIPAddressField(Field)
        - 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6
        - 参数:
            protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
            unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启此功能,需要protocol="both"

    URLField(CharField)
        - 字符串类型,Django Admin以及ModelForm中提供验证 URL

    SlugField(CharField)
        - 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)

    CommaSeparatedIntegerField(CharField)
        - 字符串类型,格式必须为逗号分割的数字

    UUIDField(Field)
        - 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证

    FilePathField(Field)
        - 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能
        - 参数:
                path,                      文件夹路径
                match=None,                正则匹配
                recursive=False,           递归下面的文件夹
                allow_files=True,          允许文件
                allow_folders=False,       允许文件夹

    FileField(Field)
        - 字符串,路径保存在数据库,文件上传到指定目录
        - 参数:
            upload_to = ""      上传文件的保存路径
            storage = None      存储组件,默认django.core.files.storage.FileSystemStorage

    ImageField(FileField)
        - 字符串,路径保存在数据库,文件上传到指定目录
        - 参数:
            upload_to = ""      上传文件的保存路径
            storage = None      存储组件,默认django.core.files.storage.FileSystemStorage
            width_field=None,   上传图片的高度保存的数据库字段名(字符串)
            height_field=None   上传图片的宽度保存的数据库字段名(字符串)

    DateTimeField(DateField)
        - 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]

    DateField(DateTimeCheckMixin, Field)
        - 日期格式      YYYY-MM-DD

    TimeField(DateTimeCheckMixin, Field)
        - 时间格式      HH:MM[:ss[.uuuuuu]]

    DurationField(Field)
        - 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型

    FloatField(Field)
        - 浮点型

    DecimalField(Field)
        - 10进制小数
        - 参数:
            max_digits,小数总长度
            decimal_places,小数位长度

    BinaryField(Field)
        - 二进制类型
字段同数据库的对应关系
	'AutoField': 'integer AUTO_INCREMENT',
    'BigAutoField': 'bigint AUTO_INCREMENT',
    'BinaryField': 'longblob',
    'BooleanField': 'bool',
    'CharField': 'varchar(%(max_length)s)',
    'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
    'DateField': 'date',
    'DateTimeField': 'datetime',
    'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
    'DurationField': 'bigint',
    'FileField': 'varchar(%(max_length)s)',
    'FilePathField': 'varchar(%(max_length)s)',
    'FloatField': 'double precision',
    'IntegerField': 'integer',
    'BigIntegerField': 'bigint',
    'IPAddressField': 'char(15)',
    'GenericIPAddressField': 'char(39)',
    'NullBooleanField': 'bool',
    'OneToOneField': 'integer',
    'PositiveIntegerField': 'integer UNSIGNED',
    'PositiveSmallIntegerField': 'smallint UNSIGNED',
    'SlugField': 'varchar(%(max_length)s)',
    'SmallIntegerField': 'smallint',
    'TextField': 'longtext',
    'TimeField': 'time',
    'UUIDField': 'char(32)',
自定义字段类型
# django除了给你提供了很多字段类型之外 还支持你自定义字段
class MyCharField(models.Field):
    def __init__(self,max_length,*args,**kwargs):
        self.max_length = max_length
        # 调用父类的init方法
        super().__init__(max_length=max_length,*args,**kwargs)  # 一定要是关键字的形式传入 
        # __init__有默认的参数

    def db_type(self, connection):
        """
        返回真正的数据类型及各种约束条件
        :param connection:
        :return:
        """
        return 'char(%s)'%self.max_length

# 自定义字段使用
myfield = MyCharField(max_length=16,null=True)



# 外键字段及参数
unique=True
	ForeignKey(unique=True)   ===			OneToOneField()
  # 你在用前面字段创建一对一 orm会有一个提示信息 orm推荐你使用后者但是前者也能用
  
db_index
	如果db_index=True 则代表着为此字段设置索引
  (复习索引是什么)

to_field
	设置要关联的表的字段  默认不写关联的就是另外一张的主键字段

on_delete
	当删除关联表中的数据时,当前表与其关联的行的行为。
  """
  django2.X及以上版本 需要你自己指定外键字段的级联更新级联删除
  """
ORM字段及参数
# null
用于表示某个字段可以为空。

# unique
如果设置为unique=True 则该字段在此表中必须是唯一的。
ForeignKey(unique=True)   <--->	  OneToOneField()

# db_index
如果db_index=True 则代表着为此字段设置索引。

# default
为该字段设置默认值。

数据库查询优化

only与defer	
select_related与prefetch_related

"""
orm语句的特点:
	惰性查询
		如果你仅仅只是书写了orm语句 在后面根本没有用到该语句所查询出来的参数
		那么orm会自动识别 直接不执行
"""
# only与defer
# res = models.Book.objects.all()
    # print(res)  # 要用数据了才会走数据库

    # 想要获取书籍表中所有数的名字
    # res = models.Book.objects.values('title')
    # for d in res:
    #     print(d.get('title'))
    # 你给我实现获取到的是一个数据对象 然后点title就能够拿到书名 并且没有其他字段
    # res = models.Book.objects.only('title')
    # res = models.Book.objects.all()
    # print(res)  # <QuerySet [<Book: 三国演义爆款>, <Book: 红楼梦爆款>, <Book: 论语爆款>, <Book: 聊斋爆款>, <Book: 老子爆款>]>
    # for i in res:
        # print(i.title)  # 点击only括号内的字段 不会走数据库
        # print(i.price)  # 点击only括号内没有的字段 会重新走数据库查询而all不需要走了

    res = models.Book.objects.defer('title')  # 对象除了没有title属性之外其他的都有
    for i in res:
        print(i.price)
    """
    defer与only刚好相反
        defer括号内放的字段不在查询出来的对象里面 查询该字段需要重新走数据
        而如果查询的是非括号内的字段 则不需要走数据库了

    """
    

# select_related与prefetch_related
# select_related与prefetch_related  跟跨表操作有关
    # res = models.Book.objects.all()
    # for i in res:
    #     print(i.publish.name)  # 每循环一次就要走一次数据库查询

    # res = models.Book.objects.select_related('authors')  # INNER JOIN
    """
    select_related内部直接先将book与publish连起来 然后一次性将大表里面的所有数据
    全部封装给查询出来的对象
        这个时候对象无论是点击book表的数据还是publish的数据都无需再走数据库查询了
    
    select_related括号内只能放外键字段    一对多 一对一
        多对多也不行
    
    """
    # for i in res:
    #     print(i.publish.name)  # 每循环一次就要走一次数据库查询

    res = models.Book.objects.prefetch_related('publish')  # 子查询
    """
    prefetch_related该方法内部其实就是子查询
        将子查询查询出来的所有结果也给你封装到对象中
        给你的感觉好像也是一次性搞定的
    """
    for i in res:
        print(i.publish.name)
posted @ 2021-05-23 21:30  taxuebufeng  阅读(126)  评论(0)    收藏  举报