Django框架05 /orm单表操作

Django框架05 /orm单表操作

1. orm使用流程

  • 配置mysql

    # django 连接mysql,settings配置文件中
    DATABASES = {
    'default': {
    'ENGINE': 'django.db.backends.mysql',
    'NAME': 'orm02',
    'USER':'root',
    'PASSWORD':'123',
    'HOST':'127.0.0.1',
    'PORT':3306,
    }
    }
  • 用pymysql替换mysqldb

    # 项目文件夹下的init文件中写上下面内容,用pymysql替换mysqldb
    import pymysql
    pymysql.install_as_MySQLdb()
  • models文件中创建一个类

    class UserInfo(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=10)
    bday = models.DateField()
    checked = models.BooleanField() BooleanField() # 不能设置空值,只能设置默认值
  • 执行数据库同步指令

    python manage.py makemigrations
    python manage.py migrate # 执行数据库同步指令,添加字段的时候别忘了,该字段不能为空,所有要么给默认值,要么设置它允许为空 null=True
  • 创建记录(实例一个对象,调用save方法)

    from app01 import models
    
    def query(request):
    # 创建一条记录,增
    new_obj = models.UserInfo(
    id=2,
    name='张三',
    bday='2019-09-27',
    checked=1,
    )
    new_obj.save()
    # 翻译成sql语句,然后调用pymysql,发送给服务端
    # insert into app01_userinfo values(2,'张三','2019-09-27',1) return HttpResponse('xxx')
  • orm语句执行流程

    orm语句 -- sql -- 调用pymysql客户端发送sql -- mysql服务端接收到指令并执行

2. orm字段

  • CharField

    - 字符串字段, 用于较短的字符串.
    - CharField 要求必须有一个参数 maxlength, 用于从数据库层和Django校验层限制该字段所允许的最大字符数.
  • IntegerField

    用于保存一个整数.
  • DecimalField

    一个浮点数. 必须 提供两个参数:
    
    参数                    描述
    max_digits 总位数(不包括小数点和符号)
    decimal_places 小数位数 # 举例
    # 要保存最大值为 999 (小数点后保存2位),要这样定义字段:
    models.DecimalField(..., max_digits=5, decimal_places=2) # 要保存最大值一百万(小数点后保存10位)的话,要这样定义:
    models.DecimalField(..., max_digits=17, decimal_places=10)
    # max_digits大于等于17就能存储百万以上的数了
  • BooleanField

    用 checkbox 来表示此类字段,用来存储布尔值
  • TextField

    一个容量很大的文本字段
  • EmailField

    判断输入的是不是一个合法的email字段,不接受 maxlength 参数.
  • DateField

    一个日期字段, 共有下列额外的可选参数:
    Argument 描述
    auto_now 当对象被保存时(更新或者添加都行),自动将该字段的值设置为当前时间.
    通常用于表示 "last-modified" 时间戳.
    auto_now_add 当对象首次被创建时,自动将该字段的值设置为当前时间.通常用于表示对象创建时间.
  • DateTimeField

    一个日期时间字段. 类似 DateField 支持同样的附加选项.
  • AutoField

    一个 IntegerField, 添加记录时它会自动增长. 通常不需要直接使用这个字段;
    自定义一个主键:my_id=models.AutoField(primary_key=True)
    如果不指定主键的话,系统会自动添加一个主键字段到model.
  • URLField

    用于保存 URL. 若 verify_exists 参数为 True (默认), 给定的 URL 会预先检查是否存在
    即URL是否被有效装入且没有返回404响应
  • FileField

    一个文件上传字段.
    
    要求一个必须有的参数: upload_to, 一个用于保存上载文件的本地文件系统路径. 这个路径必须包含 strftime 
    
    注意:
    在一个 model 中使用 FileField 或 ImageField 需要以下步骤:
    1、在settings 文件中, 定义一个完整路径给 MEDIA_ROOT 以便让 Django在此处保存上传文件.
    (出于性能考虑,这些文件并不保存到数据库.) 定义MEDIA_URL 作为该目录的公共 URL. 要确保该目录对
    WEB服务器用户帐号是可写的.
    2、在model 中添加 FileField 或 ImageField, 并确保定义了 upload_to 选项,以告诉 Django
    使用 MEDIA_ROOT 的哪个子目录保存上传文件.你的数据库中要保存的只是文件的路径(相对于 MEDIA_ROOT).
  • ImageField

    它有两个可选参数:height_field和width_field,
    类似 FileField, 不过要校验上传对象是否是一个合法图片.
    如果提供这两个参数,则图片将按提供的高度和宽度规格保存.

3. orm参数

  • null

    如果为True,Django 将用NULL 来在数据库中存储空值。 默认值是 False.
  • blank

    如果为True,该字段允许不填。默认为False。
    要注意,这与 null 不同。null纯粹是数据库范畴的,而 blank 是数据验证范畴的。
    如果一个字段的blank=True,表单的验证将允许该字段是空值。如果字段的blank=False,该字段就是必填的。
  • default

    字段的默认值。可以是一个值或者可调用对象。如果可调用 ,每有新对象被创建它都会被调用,如果你的字段没有设置可以为空,那么将来如果我们后添加一个字段,这个字段就要给一个default值
  • primary_key

    如果为True,那么这个字段就是模型的主键。如果你没有指定任何一个字段的primary_key=True,
    Django 就会自动添加一个IntegerField字段做为主键,所以除非你想覆盖默认的主键行为,
    否则没必要设置任何一个字段的primary_key=True。
  • unique

    如果该值设置为 True, 这个数据字段的值在整张表中必须是唯一的
  • choices

    由二元组组成的一个可迭代对象(例如,列表或元组),用来给字段提供选择项。 如果设置了choices ,默认的表单将是一个选择框而不是标准的文本框,而且这个选择框的选项就是choices 中的选项。
  • auto_now_add

    配置auto_now_add=True,创建数据记录的时候会把当前时间添加到数据库。
  • auto_now

    配置上auto_now=True,每次更新数据记录的时候会更新该字段,标识这条记录最后一次的修改时间。
  • DatetimeField、DateField、TimeField这个三个时间字段,都可以设置auto_now_add、auto_now属性。

  • 时间问题:auto_now_add/auto_now

    models.UserInfo.objects.create(
    name='张三',
    bday=current_date, # 直接插入时间没有时区问题
    checked=0
    ) now = models.DateTimeField(auto_now_add=True,null=True)
    # 如果自动来插入时间,就会有时区的问题,auto_now_add创建记录时自动添加当前创建记录时的时间,存在时区问题 # 解决方法:
    # settings配置文件中将USE_TZ的值改为False
    # USE_TZ = True
    USE_TZ = False # 告诉mysql存储时间时按照当地时间来存,不要用utc时间
    # 使用pycharm的数据库客户端的时候,时区问题要注意

4. orm单表简单增/删/改

  • 增:

    # 方式1:
    new_obj = models.UserInfo(
    id=2,
    name='张三',
    bday='2019-09-27',
    checked=1,
    )
    new_obj.save() # 方式2:
    # ret 是创建的新的记录的model对象
    ret = models.UserInfo.objects.create(
    name='张三',
    bday='2019-08-07',
    checked=0
    ) print(ret) # UserInfo object
    print(ret.name) # '张三'
    print(ret.bday) # '2019-08-07'
  • 批量增加/bulk_create

    book_list = []
    for i in range(10):
    bk_obj = models.Book(
    name='张三%s'%i,
    addr='北京%s'%i
    )
    book_list.append(bk_obj) models.Book.objects.bulk_create(book_list) # 批量插入,速度快
  • # 简单查询:filter()
    # 结果是queryset类型的数据里面是一个个的model对象,类似于列表 models.UserInfo.objects.filter(id=6).delete() # queryset对象调用
    models.UserInfo.objects.filter(id=6)[0].delete() # model对象调用
  • # 方式1:update
    models.UserInfo.objects.filter(id=2).update(
    name='李四',
    checked = 0,
    ) # 错误示例,model对象不能调用update方法
    models.UserInfo.objects.filter(id=2)[0].update(
    name='李四',
    checked = 0,
    )
    # 方式2
    ret = models.UserInfo.objects.filter(id=2)[0]
    ret.name = '李四'
    ret.checked = 1
    ret.save() nowtime = models.DateTimeField(auto_now=True,null=True)
    # 注意:
    # 更新时的auto_now参数
    # 更新记录时,自动更新时间,创建新纪录时也会帮你自动添加创建时的时间,但是在更新时只有使用方式2的save方法才能自动更新时间,有缺陷

5. orm单表查询

5.1 查询api

  1. all()

    • 查询所有结果,结果是queryset类型
    ret = models.Books.objects.all()
    print(ret) < QuerySet[ < Books: Books object >, < Books: Books object >] >
  2. filter(**kwargs) -- 条件查询

    • 包含与所给筛选条件相匹配的对象,结果也是queryset类型
    • 如果没有写查询条件会获取所有数据,queryset类型的数据还能够继续调用fitler方法
    • 查询条件不能匹配到数据时,不会报错,返回一个空的queryset,<QuerySet []>
    ret = models.Books.objects.filter(name='linux')
    print(ret)
    <QuerySet [<Books: Books object>, <Books: Books object>]> #多条件查询用,隔开--是and的关系
    ret = models.Books.objects.filter(name='linux',price=113)
    print(ret)
    <QuerySet [<Books: Books object>, <Books: Books object>]>
  3. get(kwargs) ***

    • 返回与所给筛选条件相匹配的对象,不是queryset类型,是model对象
    • 返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。捕获异常try。
    ret = models.Books.objects.get(id=5)
    print(ret)
    Books object # 报错原因:
    # 1. 查不到数据会报错 :Book matching query does not exist.
    # 2. 超过一个就报错 :returned more than one Book -- it returned 13!
  4. exclude(**kwargs) -- 排除

    • 排除的意思,它包含了与所给筛选条件不匹配的对象,没有不等于的操作,用这个exclude,返回值是queryset类型
    • model对象和queryset对象都可以调用
    Book.objects.exclude(id=6)   # 返回id不等于6的所有的对象
    Book.objects.all().exclude(id=6) # 在queryset基础上调用
    # model对象调用:
    ret = models.Books.objects.exclude(name='python')
    print(ret) <QuerySet [<Books: Books object>, <Books: Books object>, <Books: Books object>]> # queryset对象调用:
    ret = models.Books.objects.all().exclude(name='python')
    print(ret) <QuerySet [<Books: Books object>, <Books: Books object>, <Books: Books object>]>
  5. order_by(*field) -- 排序

    • queryset类型的数据来调用,对查询结果排序,默认是按照id来升序排列的,返回值还是queryset类型
    • 两种方式改变升序和降序:
      • 1.在传入fields参数的时候,在参数前加-代表降序,不加代表升序.
      • 2.在fields的后面,再加上方法进行改变, asc( )代表升序 ,desc( )代表降序.
    • 切忌:
      • 不要在一个order_by后又加一个order_by,后面的会覆盖掉之前的查询结果.
    升序排序:
    models.Book.objects.all().order_by('price') # 默认是按照price升序排列 降序排序:
    models.Book.objects.all().order_by('-price') # 按照字段降序排列,就写个负号就行了 多条件排序:
    models.Book.objects.all().order_by('price','id') # 是多条件排序,按照price进行升序,price相同的数据,按照id进行升序
  6. reverse() -- 反转

    • queryset类型的数据来调用,返回值还是queryset类型
    • 对查询结果反向排序,只适用于已经默认排序或者使用order_by排序过后的查询集,如果未排序,则没有效果.
  7. count() -- 计数、统计返回结果的数量

    • queryset类型的数据来调用,返回数据库中匹配查询(QuerySet)的对象数量
  8. first()

    • queryset类型的数据来调用,得到的都是model对象,返回第一条记录
    Book.objects.all()[0] = Book.objects.all().first()
    # 得到的都是model对象,不是queryset
  9. last()

    • queryset类型的数据来调用,返回最后一条记录
  10. exists() -- 判断返回结果是否有数据

    • queryset类型的数据来调用,如果QuerySet包含数据,就返回True,否则返回False,效率高
    models.Book.objects.all().exists()   # exists() 括号内不能放数据
    
    # 翻译成的sql是SELECT (1) AS `a` FROM `app01_book` LIMIT 1,
    # 就是通过limit 1,取一条来看看是不是有数据
  11. values(*field)

    • queryset类型的数据来调用,返回一个ValueQuerySet——一个特殊的QuerySet
    • model的实例化对象来调用,而是一个可迭代的字典序列,只要是返回的queryset类型,就可以继续链式调用queryset类型的其他的查找方法,其他方法也是一样的。
    # 示例一:
    ret = models.Books.objects.all().values('name')
    print(ret) <QuerySet [{'name': 'python'}, {'name': 'linux'}, {'name': 'Go'}]> # 示例二:
    ret = models.Books.objects.values('name')
    print(ret) <QuerySet [{'name': 'python'}, {'name': 'python'}, {'name': 'linux'}, {'name': 'python'}, {'name': 'linux'}, {'name': 'Go'}]>
    # 调用values或者values_list的对象是objects控制器,那么返回所有数据
  12. values_list(*field)

    • 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
    ret = models.Books.objects.all().values_list('name')
    print(ret)
    <QuerySet [('python',), ('linux',), ('Go',)]>
  13. distinct() -- 去重、配置values和values_list来使用

    • distinct()括号里不能加去重的条件
    • values和values_list得到的queryset类型的数据来调用,从返回结果中剔除重复纪录
    ret = models.Books.objects.values('name').distinct()
    print(ret) <QuerySet [{'name': 'python'}, {'name': 'linux'}, {'name': 'Go'}]> # 错误示例:
    ret = models.Books.objects.all().distinct()
    print(ret)
    <QuerySet [<Books: python>, <Books: python>, <Books: linux>, <Books: python>, <Books: linux>, <Books: Go>]> # 注意:
    # 不在values()、values_list()后面使用没有意义,因为要是所有的内容全相同才会去重

5.2 基于双下划线的模糊查询 / filter双下划线查询

  1. 在里边:__in

    Book.objects.filter(price__in=[100,200,300])
    # price值等于这三个里面的任意一个的对象
  2. 大于:__gt

    Book.objects.filter(price__gt=100)   # 大于
  3. 大于等于:__gte

    Book.objects.filter(price__gte=100)
    # 大于等于,别写price>100,这种参数不支持
  4. 小于:__lt

    Book.objects.filter(price__lt=100)   # 小于
  5. 小于等于:__lte

    Book.objects.filter(price__lte=100)   # 小于
    # 小于等于,别写price>100,这种参数不支持
  6. 包含:__contains

    Book.objects.filter(title__contains="python")
    # title值中包含python的
  7. 包含,不区分大小写:__icontains

    Book.objects.filter(title__icontains="python")
    # 不区分大小写
  8. 以什么开头:__startswith

    Book.objects.filter(title__startswith="py")
    # 以什么开头
  9. 以什么开头,不区分大小写:__istartswith

    Book.objects.filter(title__istartswith="py")
    # 不区分大小写
  10. 日期相关

    # 筛选日期
    Book.objects.filter(pub_date='2012-9-12') # 筛选年份
    Book.objects.filter(pub_date__year=2012)
    # 筛选大于该年份的
    Book.objects.filter(pub_date__ year_gt='2018') # 大于2018年的、2018数字类型也可以 # 筛选某年某月
    Book.objects.filter(pub_date__year='2019' ,pub_ date__ month='8') # 筛选某年某月某日
    Book.objects.filter(pub_date__ year='2019' ,pub_date__month='8',pub_date__day='01')
  11. 判断是否为空

    models.Book.objects.filter(publish_date__isnull=True)
    # 这个字段值为空的那些数据

总结:

  1. 新增字段(必须设置可以为空或者设置默认值)

  2. UTC时间格式格林尼治时间

  3. model对象不能调用update方法

  4. USE_TZ = False

  5. orm整体流程代码示例

    orm > settings.py

    DATABASES = {
    'default': {
    'ENGINE': 'django.db.backends.mysql',
    'NAME': 'orm1',
    'HOST':'127.0.0.1',
    'PORT':3306,
    'USER':'root',
    'PASSWORD':'123'
    }
    } # 设置mysql默认使用当地时间
    USE_TZ = False # 不是跨时区的应用,不需要考虑时区问题,就将这个值改为False
    # mysql是对时区不敏感,django往mysql里面出数据的时候
    # 如果这里的值为True,那么将让mysql强制使用UTC时间
    # 那么存储时间后,当查询的时候,就会发现,时间晚了8小时

    orm1 > __init__.py

    import pymysql
    pymysql.install_as_MySQLdb()

    models.py

    from django.db import models
    
    class Userinfo(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=16)
    register_time = models.DateField(null=True)
    # auto_now_add=True 修改记录不会改变,只会在添加数据的时候添加时间
    update_time = models.DateTimeField(auto_now=True,null=True)
    # auto_now=True, 修改记录用方式一/update不会改变、用方式二/ret.save()会更新
    checked = models.BooleanField(default=0)

    views.py

    from django.shortcuts import render,HttpResponse
    from app01 import models
    from datetime import datetime def query(request):
    # 创建记录
    # 方式一
    current_time = datetime.now()
    new_obj = models.Userinfo(
    id = 1,
    name = 'ZHANGSAN'
    )
    new_obj.save() # 方式二
    ret =models.Userinfo.objects.create(
    name='ZHANGSAN',
    register_time='2019-8-8',
    update_time='2019-8-10 12:12:12',
    checked=1, )
    ret = models.Userinfo.objects.filter(name='ZHANGSAN')
    print(ret) # 删除
    ret = models.Userinfo.objects.filter(id=7)[0].delete()
    print(ret)
    # 将符合条件的第一条记录删除 ret = models.Userinfo.objects.filter(id=7).delete()
    print(ret)
    # 将符合条件的所有记录删除
    # 注意:filter搜索出来的是queryset类型的列表:queryset<[对象1,对象2,对象3]> # 修改
    # 方式一
    models.Userinfo.objects.filter(id=1).update(
    name='ZHANGSAN',
    checked=1,
    register_time = '2019-1-1',
    update_time = '2020-06-03',
    ) # 方式二
    ret = models.Userinfo.objects.filter(id=1)[0]
    ret.name='LISI'
    ret.save()
    return HttpResponse('OK')
    # 注意:model对象不能调用update()方法
  6. 单表查询返回models对象的方法

    1.get(**kwargs)
    2.create(**kwargs)
    3.count()
    # 该方法返回与之匹配的数据库中对象的个数,并且有一个最大的特点,永远不会返回异常
    4.first()
    5.last()
    6.get_or_create(defaults=None,**kwargs)
    # 如果存在则返回查找的对象,如果不存在则创建一个新的对象并且保存.
    7.update_or_create(defaults= None,** kwargs)
    # 该方法查找defaults中的对象,如果找到则更新数值,如果没有,则创建对象.
  7. 单表查询返回queryset对象的方法

    1.all()
    2.filter(**kwargs)
    3.exclude(**kwargs)
    4.order_by( *fields)
    5.reverse()
    6.distinct()
    7.values(*fields,)
    8.values_list(*fields,)
上一篇:Django框架之ORM的相关操作之分页(六)


下一篇:2017年11月8日最新仿互站导航t5友价商城-9套模板首页都增加微信登陆