模型层

django ORM操作

关键性字段及参数

DateField  年月日

DateTimeField  年月日时分秒

  auto_now :每次操作该数据都会自动跟新时间

  auto_now_add:新增数据的时候会将当前

    import os


        if __name__ == "__main__":
            os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day58.settings")
            import django
            django.setup()
            from app01 import models  # 这一句话必须在这下面导入
单独的py文件测试ORM操作需要配置的参数

 

from django.db import models

# Create your models here.

#单表查询
class User(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    register_time = models.DateField()

    def __str__(self):
        return '对象的名字:%s'%self.name


#多表查询
class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8,decimal_places=2)
    publish_date = models.DateField(auto_now_add=True)
    #外键关系
    publish = models.ForeignKey(to='Publish')
    authors = models.ManyToManyField(to='Author')

    def __str__(self):
        return '书籍对象的名字:%s'%self.title



class Publish(models.Model):
    name = models.CharField(max_length=32)
    addr = models.CharField(max_length=32)
    email = models.EmailField()     #对应的就是varchar类型

    def __str__(self):
        return '出版社对象的名字:%s'%self.name




class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    authordetail = models.OneToOneField(to='AuthorDetail')

    def __str__(self):
        return '作者对象的名字:%s'%self.name




class AuthorDetail(models.Model):
    phone = models.CharField(max_length=32)
    addr = models.CharField(max_length=32)
models.py

 

 

关系字段

 

ForeignKey


外键类型在ORM中用来表示外键关联关系,一般把ForeignKey字段设置在 '一对多'中'多'的一方。

ForeignKey可以和其他表做关联关系同时也可以和自身做关联关系。

字段参数


to

设置要关联的表

to_field

设置要关联的表的字段

on_delete

当删除关联表中的数据时,当前表与其关联的行的行为。

models.CASCADE

删除关联数据,与之关联也删除

db_constraint

是否在数据库中创建外键约束,默认为True。

 其余字段参数
 
def func():
    return 10

class MyModel(models.Model):
    user = models.ForeignKey(
        to="User",
        to_field="id",
        on_delete=models.SET(func)
    )
 

OneToOneField

 

一对一字段。

通常一对一字段用来扩展已有字段。(通俗的说就是一个人的所有信息不是放在一张表里面的,简单的信息一张表,隐私的信息另一张表,之间通过一对一外键关联)

字段参数


to

设置要关联的表。

to_field

设置要关联的字段。

on_delete

当删除关联表中的数据时,当前表与其关联的行的行为。(参考上面的例子)

一般操作


在进行一般操作时先配置一下参数,使得我们可以直接在Django页面中运行我们的测试脚本

在Python脚本中调用Django环境


 

这样就可以直接运行你的test.py文件来运行测试

 必知必会13条

操作下面的操作之前,我们实现创建好了数据表,这里主要演示下面的操作,不再细讲创建准备过程

<1> all(): 查询所有结果

<2> filter(**kwargs): 它包含了与所给筛选条件相匹配的对象

<3> get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。

<4> exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象

<5> values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典序列

<6> values_list(*field): 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列

<7> order_by(*field): 对查询结果排序

<8> reverse(): 对查询结果反向排序,请注意reverse()通常只能在具有已定义顺序的QuerySet上调用(在model类的Meta中指定ordering或调用order_by()方法)。

<9> distinct(): 从返回结果中剔除重复纪录(如果你查询跨越多个表,可能在计算QuerySet时得到重复的结果。此时可以使用distinct(),注意只有在PostgreSQL中支持按字段去重。)

<10> count(): 返回数据库中匹配查询(QuerySet)的对象数量。

<11> first(): 返回第一条记录

<12> last(): 返回最后一条记录

<13> exists(): 如果QuerySet包含数据,就返回True,否则返回False

13个必会操作总结


返回QuerySet对象的方法有

all()

filter()

exclude()

order_by()

reverse()

distinct()

特殊的QuerySet

values()       返回一个可迭代的字典序列

values_list() 返回一个可迭代的元祖序列

返回具体对象的

get()

first()

last()

返回布尔值的方法有:

exists()

返回数字的方法有

count()

Django终端打印SQL语句

 

 

 

 单表操作

#新增数据
#基于create创建
user_obj = models.User.objects.create(name='tank',age=74,reister_time='2019-2-4')
print(user_obj.register_time)    #2019-2-4

有返回值 返回的就是数据对象本身
from datetime import datetime ctime = datetime.now() models.User.create(name='egon',age=18,regist_time=ctime) #基于对象的绑定方法创建 user_obj =models.User(name='kevin',age=30,register_time='2019-1-1') user_obj.save() #修改数据 #基于对象 user_obj = models.User.objectes.filter(name='jason').first() user_obj.age = 17 user_obj.save() #基于Queryset models.User.objects.filter(name='kevi').update(age=66) #删除数据 #基于Queryset models.User.objects.filter(name='egon').delete() #基于数据对象 user_obj = models.User.objects.filter(name='owen').first() user_obj.delete() #数据对象也可以delete()删除

 

 查询方法

#查询数据
#1 all()  查询所有结果
#2 filter(**kwargs)  它包含了与所给筛选条件相匹配的对象
res = models.User.objects.filter(name='jason',age=17)
#filter内可以放多个限制条件  注意!!条件之间是and关系  
print(res)   #<QuerySet [<User: 对象的名字:jason>]>

# 3 get(**kwargs) 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误 
#不推荐使用

#4 exclude(**kwargs) 它包含了与所给筛选条件不匹配的对象   排除
res = models.User.objects.exclude(name='jason')
print(res)   #<QuerySet [<User: 对象的名字:tank>, <User: 对象的名字:kevin>]>

#5 order_by(*field) 对查询结果排序('-id')/('price')  数字和字符串都可以 默认升序 前面加 - 就是降序
# res = models.User.objects.order_by('age')   #默认是升序
    # print(res)      #<QuerySet [<User: 对象的名字:jason>, <User: 对象的名字:kevin>, <User: 对象的名字:tank>]>

    # res = models.User.objects.order_by('-age')
    # print(res)      #<QuerySet [<User: 对象的名字:tank>, <User: 对象的名字:kevin>, <User: 对象的名字:jason>]>

    # res = models.User.objects.order_by('name')
    # print(res)  #<QuerySet [<User: 对象的名字:jason>, <User: 对象的名字:kevin>, <User: 对象的名字:tank>]>

    # res = models.User.objects.order_by('-name')
    # print(res)  #<QuerySet [<User: 对象的名字:tank>, <User: 对象的名字:kevin>, <User: 对象的名字:jason>]>

#6 reverse()  对查询结果反向排序 》》》前面要先排序才能反向
# res = models.User.objects.order_by('age').reverse()
    # print(res)   #<QuerySet [<User: 对象的名字:tank>, <User: 对象的名字:kevin>, <User: 对象的名字:jason>]>

#7 count() 返回数字库中匹配查询(Queryset)的对象数量
    # res = models.User.objects.count()
    # print(res,type(res))  #3
    # res = models.User.objects.all().count()
    # print(res,type(res))  #3

#8 first() 返回第一条记录
    res = models.User.objects.all().first()
    res= models.User.objects.all()[0]
    print(res) #对象的名字:tank

#9 last()  返回最后一条记录
 res = models.User.objects.all().last()
    print(res)  #对象的名字:jason

#10 exitsts() 如果Queryset包含数据 就返回True 否则返回False
    res = models.User.objects.all().exists()
    res1 = models.User.objects.filter(name='jason',age=3).exists()
    print(res,res1)  #True False

#11 values(*field) 返回一个valuesQuerst 一个特殊的queryset 运行后得到的并不是一系列models的实例化对象,而是一个可迭代的字典序列
    res = models.User.objects.values('name')    #列表套字典
    print(res)  #<QuerySet [{'name': 'tank'}, {'name': 'kevin'}, {'name': 'jason'}]>

    res = models.User.objects.values('name','age')   #列表套字典
    print(res)  #<QuerySet [{'name': 'tank', 'age': 73}, {'name': 'kevin', 'age': 66}, {'name': 'jason', 'age': 17}]>

#12  values_list(*field)  它与values() 非常相似 它返回的是一个元组序列 values返回的是一个字典序列
 res = models.User.objects.values_list('name','age')  #列表套元组
    print(res)  #<QuerySet [('tank', 73), ('kevin', 66), ('jason', 17)]>

#13 distinct()  从返会结果中剔除重复记录 去重的对象必须是完全相同的数据才能取重
res = models.User.objects.values('name','age').distinct()
    print(res)  #<QuerySet [{'name': 'tank', 'age': 73}, {'name': 'kevin', 'age': 66}, {'name': 'jason', 'age': 17}]>

 

 

 单表操作  基于双下划线的查询

#神奇的双下划线查询

#查询年纪大于44岁的用户
 res = models.User.objects.filter(age__gt=44)
    print(res)  #<QuerySet [<User: 对象的名字:tank>, <User: 对象的名字:kevin>]>

#查询年纪小于44岁的用户
 res= models.User.objects.filter(age__lt=44)
    print(res)    #<QuerySet [<User: 对象的名字:jason>, <User: 对象的名字:jason>]>


    # 查询年纪大于等于44岁的用户
    res= models.User.objects.filter(age__gte=44)
    print(res)  #<QuerySet [<User: 对象的名字:tank>, <User: 对象的名字:kevin>, <User: 对象的名字:laj>]>

    # 查询年轻小于等于44岁的用户
    res = models.User.objects.filter(age__lte=44)
    print(res)     #<QuerySet [<User: 对象的名字:jason>, <User: 对象的名字:jason>, <User: 对象的名字:laj>]>

    # 查询年龄是44或者22或者73的用户
    res = models.User.objects.filter(age__in=[44,22,73])
    print(res)  #<QuerySet [<User: 对象的名字:tank>, <User: 对象的名字:laj>]>

    # 查询年龄在22到44范围内
    res = models.User.objects.filter(age__range=[22,44])
    print(res)  #<QuerySet [<User: 对象的名字:laj>]>  包含了44

    # 查询名字中包含字母n的用户  sqlite数据库演示不出来大小写的情况!!!
    res = models.User.objects.filter(name__contains='n')  #区分大小写
    print(res)  #<QuerySet [<User: 对象的名字:tank>, <User: 对象的名字:kevin>, <User: 对象的名字:jason>, <User: 对象的名字:jason>]>

    res = models.User.objects.filter(name__icontains='n')  #无视大小写
    print(res)

    # 查询名字以j开头的用户
    res = models.User.objects.filter(name__startswith='j')
    print(res)  #<QuerySet [<User: 对象的名字:jason>, <User: 对象的名字:jason>]>

    # 查询名字以n结尾的用户
    res = models.User.objects.filter(name__endswith='n')
    print(res)  #<QuerySet [<User: 对象的名字:kevin>, <User: 对象的名字:jason>, <User: 对象的名字:jason>]>

    # 查询注册是在2017年的用户
    res = models.User.objects.filter(register_time__year=2017)
    print(res)  #<QuerySet [<User: 对象的名字:jason>, <User: 对象的名字:jason>]>

 

 

 多表操作 增删改

#多表操作

#新增
    models.Book.objects.create(title='红楼梦',price=66.66,publish_id=1)
#传数据对象
    publish_obj = models.Publish.objects.filter(pk=2).first()
    models.Book.objects.create(title='三国演义',price='199',publish=publish_obj)


#修改
#Queryset修改
    models.Book.objects.filter(pk=6).update(publish_id=3)

    publish_obj = models.Publish.objects.filter(pk=4).first()
    models.Book.objects.filter(pk=6).update(publish=publish_obj)
#对象修改
 book_obj = models.Book.objects.filter(pk=6).first()
    book_obj.publish_id = 1  #点表中真是存在的字段名   点表中的publish_id的话就写数字
    book_obj.save()
    book_obj = models.Book.objects.filter(pk=6).first()
    publish_obj = models.Publish.objects.filter(pk=3).first()
    book_obj.publish = publish_obj    #点orm中字段名 传该字段对应的表的数据对象  点orm里面的字段名的话 就传对象
    publish_obj.save()

#删除
    models.Book.objects.filter(pk=6).delete()
    models.Publish.objects.filter(pk=4).delete()

    book_obj = models.Book.objects.filter(pk=5).first()
    book_obj.delete()     #数据对象直接删除

 

 

多对多操作第三张表 manytomanyfield

#给书籍绑定与作者之间的关系
#添加关系 add  支持传数字或 对象, 并且都可以传多个
    book_obj = models.Book.objects.filter(pk=3).first()
    book_obj.authors.add(4)
    book_obj.authors.add(2,3,4,5)

    author_obj = models.Author.objects.filter(pk=4).first()
    author_obj1 = models.Author.objects.filter(pk=3).first()
    book_obj.authors.add(author_obj,author_obj1)

#修改书籍与作者关系 set()  set传的必须是可迭代对象!!!
    #可以传数字或对象 并且支持传多个
    book_obj = models.Book.objects.filter(pk=3).first()
    book_obj.authors.set((4,))  #这个可以用来删除书籍的作者直接重置关系
    book_obj.authors.set((4,2))

    author_list = models.Author.objects.all()
    book_obj = models.Book.objects.filter(pk=3).first()
    book_obj.authors.set(author_list)  #queryset对象

#删除书籍与作者的绑定关系
    book_obj = models.Book.objects.filter(pk=3).first()
    book_obj.authors.remove(2)
    book_obj.authors.remove(3,4)

    author_obj = models.Author.objects.all().first()
    book_obj.authors.remove(author_obj)
    author_list = models.Author.objects.all()
    book_obj.authors.remove(*author_list)   #需要将queryset打散

#清空 clear()  清空的是你当前这个表记录对应的绑定关系
    book_obj = models.Book.objects.filter(pk=3).first()
    book_obj.authors.clear()

 

 

 

 基于对象的表操作  (正向查询按字段  反向查询按表名小写)

  正向查询

    # 查询书籍是三国演义的出版社邮箱
    book_obj = models.Book.objects.filter(title='三国演义').first()
    print(book_obj.publish.email)  #134@qq.com
    # 查询书籍是三国演义的作者的姓名
    book_obj = models.Book.objects.filter(title='三国演义').first()
    print(book_obj.authors.all())
    # <QuerySet [<Author: 作者对象的名字:jason>, <Author: 作者对象的名字:kevin>]>
    # 查询作者为jason电话号码
    user_obj = models.Author.objects.filter(name='jason').first()
    print(user_obj.authordetail.phone)  #120

 

  反向查询  (表名小写_set)   

     # 查询出版涩是东方出版涩出版的书籍
  
   publish_obj = models.Publish.objects.filter(name='东方出版涩').first()
print(publish_obj.book_set) #app01.Book.None !!!! 出现就点all()
print(publish_obj.book_set.all()) #<QuerySet [<Book: 书籍对象的名字:小王子>, <Book: 书籍对象的名字:三国演义>]> # 查询作者jason写过的所有的书 author_obj = models.Author.objects.filter(name='jason').first() print(author_obj.book_set) #app01.Book.None print(author_obj.book_set.all()) #<QuerySet [<Book: 书籍对象的名字:围城>, <Book: 书籍对象的名字:小王子>, <Book: 书籍对象的名字:三国演义>]> # 查询作者电话号码是390的作者姓名 authordetail_obj = models.AuthorDetail.objects.filter(phone=390).first() print(authordetail_obj.author.name) #tank

 

 

基于双下划线的查询

  正向查询

    # 查询书籍为三国演义的出版社地址
    res = models.Book.objects.filter(title='三国演义').values('publish__addr','title')
    print(res)  #<QuerySet [{'publish__addr': '东方', 'title': '三国演义'}]>
    # 查询书籍为小王子的作者的姓名
    res = models.Book.objects.filter(title='小王子').values('authors__name')
    print(res)  #<QuerySet [{'authors__name': 'jason'}, {'authors__name': 'tank'}]>

    # 查询作者为jason的家乡
    res = models.Author.objects.filter(name='jason').values('authordetail__addr')
    print(res)  #<QuerySet [{'authordetail__addr': '上海'}]>

 

  反向查询

    # 查询南方出版社出版的书名
    res = models.Publish.objects.filter(name='南方出版社').values('book__title')
    print(res)  #<QuerySet [{'book__title': '围城'}, {'book__title': '红楼梦'}]>

    # 查询电话号码为203的作者姓名
    res = models.AuthorDetail.objects.filter(phone=203).values('author__name')
    print(res)  #<QuerySet [{'author__name': '六角恐龙'}]>

    # 查询作者为jason的写的书的名字
    res = models.Author.objects.filter(name='jason').values('book__title')
    print(res)  #<QuerySet [{'book__title': '围城'}, {'book__title': '小王子'}, {'book__title': '三国演义'}]>

    # 查询书籍为三国演义的作者的电话号码
    res = models.Book.objects.filter(title='三国演义').values('authors__authordetail__phone','authors__name')
    print(res)
    # <QuerySet [{'authors__authordetail__phone': '120', 'authors__name': 'jason'}, {'authors__authordetail__phone': '149', 'authors__name': 'kevin'}]>


    # 查询jason作者的手机号
    # 正向
    res= models.Author.objects.filter(name='jason').values('authordetail__phone')
    print(res)  #<QuerySet [{'authordetail__phone': '120'}]>
    # 反向
    res = models.AuthorDetail.objects.filter(author__name='jason').values('phone')
    print(res)  #<QuerySet [{'phone': '120'}]>

    # 查询出版涩为东方出版涩的所有的图书的名字和价格
    # 正向
    res = models.Publish.objects.filter(name='东方出版涩').values('book__title','book__price')
    print(res)  #<QuerySet [{'book__title': '小王子', 'book__price': Decimal('38.00')}, {'book__title': '三国演义', 'book__price': Decimal('199.00')}]>

    # 反向
    res = models.Book.objects.filter(publish__name='东方出版涩').values('title','price')
    print(res)  #<QuerySet [{'title': '小王子', 'price': Decimal('38.00')}, {'title': '三国演义', 'price': Decimal('199.00')}]>

    # 查询东方出版社出版的价格大于100的书
    # 反向
    res = models.Book.objects.filter(price__gt=100,publish__name='东方出版涩').values('title')
    print(res)  #<QuerySet [{'title': '三国演义'}]>
    # 正向
    res = models.Publish.objects.filter(name='东方出版涩',book__price__gt=100).values('book__title')
    print(res)  #<QuerySet [{'book__title': '三国演义'}]>

 

 

总结

"""
总结 其实你在查询的时候先把orm查询语句写出来,再看用到的条件是否在当前表内,在就直接获取,不在就按照正向按字段反向按表名来查即可
比如:
    1.查询出版社为北方出版社的所有图书的名字和价格
    res1 = Publish.objects.filter(name='').values('book__name','book__price')
    res2 = Book.objects.filter(publish__name='').values('name','price')
    2.查询北方出版社出版的价格大于19的书
    res1 = Publish.objects.filter(name='',book__price__gt=19).values('book__name','book__price)
"""

 

 

 

聚合查询  aggregate

    from django.db.models import Max, Min, Count, Sum, Avg

    # 查询所有书籍的作者个数
    res = models.Book.objects.filter(pk=3).aggregate(cont_num=Count('authors'))
    print(res)  #{'cont_num': 4}
    # 查询所有出版社出版的书的平均价格
    res = models.Publish.objects.aggregate(avg_price=Avg('book__price'))
    print(res)  #{'avg_price': 89.665}
    # 统计东方出版社出版的书籍的个数
    res = models.Publish.objects.filter(name='东方出版涩').aggregate(count_num=Count('book__pk'))
    print(res)  #{'count_num': 2}

 

 

分组查询(group_by)   annotate

    # 统计每个出版社出版的书的平均价格
    res = models.Publish.objects.annotate(avg_price=Avg('book__price')).values('name','avg_price')
    print(res)  #<QuerySet [{'name': '南方出版社', 'avg_price': 60.83}, {'name': '东方出版涩', 'avg_price': 118.5}, {'name': '北方出版涩', 'avg_price': None}]>
    # 统计每一本书的作者个数
    res = models.Book.objects.annotate(count_num=Count('authors__pk')).values('title', 'count_num')
    print( res)  # <QuerySet [{'title': '围城', 'count_num': 3}, {'title': '小王子', 'count_num': 2}, {'title': '红楼梦', 'count_num': 1}, {'title': '三国演义', 'count_num': 2}]>
    # 统计出每个出版社卖的最便宜的书的价格
    res = models.Publish.objects.annotate(min_price = Min('book__price')).values('name','min_price')
    print(res)  #<QuerySet [{'name': '南方出版社', 'min_price': Decimal('55.00')}, {'name': '东方出版涩', 'min_price': Decimal('38.00')}, {'name': '北方出版涩', 'min_price': None}]>
    # 查询每个作者出的书的总价格
    res = models.Author.objects.annotate(sum_price=Sum('book__price')).values('name','sum_price')
    print(res)
    #<QuerySet [{'name': 'jason', 'sum_price': Decimal('292.00')}, {'name': 'egon', 'sum_price': Decimal('55.00')}, {'name': 'tank', 'sum_price': Decimal('93.00')}, {'name': 'kevin', 'sum_price': Decimal('265.66')}, {'name': '六角恐龙', 'sum_price': None}]>

 

 

 

 

 django终端打印SQL语句

#配置文件配置参数查看所有的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',
                        },
                    }
                }
        

 

posted @ 2019-06-13 15:07  读自己  阅读(229)  评论(0编辑  收藏  举报