Django-ORM

django_ORM

注意不要轻易注释和删除models里面的字段信息

更改models注意要执行两句话

python manage.py makemigrations 生成迁移文件

python mamage.py migrate 真正把记录同步到数据库上面

多表关系的models建立

图书管理 书-作者-出版社-作者简介

一对一 OneToOneField字段

Book-AuthorDetail

class Author(models.Model):
    name = models.CharField(max_length=32)
    phone = models.BigIntegerField()
    # 一对一字段建在哪张表都可以,但是推荐你建在 查询频率比较高的那张表
    author_detail = models.OneToOneField(to='AuthorDetail')
    # 使用OneToOneField字段创建表的时候会自动给该字段添加_id后缀

class AuthorDetail(models.Model):
    addr = models.CharField(max_length=255)
    age = models.IntegerField()

一对多 ForeignKey

Book-Publish

class Book(models.Model):
    title = models.CharField(max_length=32)
    # 总共八位 小数占两位
    price = models.DecimalField(max_digits=8,decimal_places=2)
    # 书和出版社是一对多的关系  外键字段键在多的一方
    publish_id = models.ForeignKey(to='Publish')  # to指定跟谁是外键关联的,默认关联的是表的主键字段
    # ForeignKey字段  django orm在创建表的时候 会自动给该字段添加_id后缀

class Publish(models.Model):
    name = models.CharField(max_length=32)
    addr = models.CharField(max_length=255)

多对多 ManyToManyField

自动创建,不推荐

能够帮助你更加方便的查询,可以使用

Book-Author

class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8,decimal_places=2)
    publish_id = models.ForeignKey(to='Publish')  
    # 书和作者是多对多的关系,外键字段建在任何一方都可以,推荐你建在查询频率比较高的一方
    authors = models.ManyToManyField(to='Author')
    """authors字段仅仅是一个虚拟字段,不会再表中展示出来,仅仅是用来告django orm 书籍表和作者表示多对多的关系
        自动会创建第三张表,多对多关系表
    """
    
class Author(models.Model):
    name = models.CharField(max_length=32)
    phone = models.BigIntegerField()
    author_detail = models.OneToOneField(to='AuthorDetail')

纯手动创建,不推荐

优点:自定义的的功能最强大

缺点:很多方法ORM都不支持,查询会非常麻烦

class Book(models.Model):
	
class Author(models.Models):
    
class Book2Author(models.Model):
	book_id = models.ForeignKey(to='Book')#外键
	author_id = models.ForeignKey(to='Author')#外键
	create_time = models.DateField(auto_now_add=True)#自定义字段

半自动-推荐使用这个,拓展性好

第三张表自己建,但是orm只提供方便的查询方法

但是不支持add(),set(),remove(),clear()

models

注意models.ManyToManyField(to='wl',through='zx_wl',through_fields=('zx','wl'))

关联

class zx(models.Model):
    name = models.CharField(max_length=32)
    wls = models.ManyToManyField(to='wl',through='zx_wl',through_fields=('zx','wl'))

class wl(models.Model):
    name = models.CharField(max_length=32)
    zxs = models.ManyToManyField(to='zx',through='zx_wl',through_fields=('wl','zx'))

class zx_wl(models.Model):
    zx = models.ForeignKey(to='zx')
    wl = models.ForeignKey(to='wl')
    create_time = models.DateField(auto_created=True)

form表单校验组件

DateField

publish_date = models.DateField(auto_now_add=True)

auto_now:每次修改数据的时候,都会自动更新时间

auto_now_add:在创建数据的时候会自动将当前时间记录下来,后期如果你不人为修改就会不不变

ORM执行查看原生SQL的两种方法

1.在setting中配置

            LOGGING = {
                'version': 1,
                'disable_existing_loggers': False,
                'handlers': {
                    'console': {
                        'level': 'DEBUG',
                        'class': 'logging.StreamHandler',
                    },
                },
                'loggers': {
                    'django.db.backends': {
                        'handlers': ['console'],
                        'propagate': True,
                        'level': 'DEBUG',
                    },
                }}

2.如果查询的结果是queryset对象可以.query查看命令

只要是queryset对象就可以无限制的点queryset对象的方法,queryset.filter().filter().filter()

搭建django-ORM测试环境

from django.test import TestCase
import os
# Create your tests here.
if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "zx1.settings")
    import django

    django.setup()
    # 你就可以在下面测试django任何的py文件
    

单表查询

ORM查询数据的三种方式和其他

惰性查询,用它数据才真正的查

1.get()

当查询条件不存在的时候,会直接报错 , 如果存在会直接给你返回数据对象本身 不推荐使用

res = models.Userinfo.objects.get(username=username) 

**2.filter() **

当查询条件不存在的时候,不会报错会返回一个空,返回的是封装过的列表嵌套对象,这个列表支持正数的索引和切片,不支持负数的切片索引,取数据的时候推荐使用它的内置方法(它的底层还是通过切片实现的)

res = models.Userinfo.objects.filter(username=username)
res.first() #取第一个元素

3.all()-first()-last()

first第一个数据

last最后一个数据

拿到表所有数据,返回数据列表嵌套对象

user_queryset = models.Userinfo.objects.all()

print(user_queryset.query)#只有queryset对象可以查看原生的sql语句

其他

count()

count()  统计数据的个数
res = models.Book.objects.count()

exclude()--QuerySet 列表套对象

res = models.Book.objects.exclude(pk=3).filter(pk=4).filter(pk=1).filter(pk=4)
where not

values()--QuerySet 列表套字典

res = models.Book.objects.values('title') 
select title  {'id':1,'name':'zx'}

values_list()--QuerySet 列表套元组

res = models.Book.objects.values_list('title')
select title  (1,'zx')

distinct()--去重

res = models.Book.objects.all().distinct()
res1 = models.Book.objects.values('title','price').distinct()

order_by()--排序

res = models.Book.objects.order_by('price')  # 默认是升序
res1 = models.Book.objects.order_by('-price')  # 加负号就是降序

reverse()--反转

数据必须先排序才能反转

res = models.Book.objects.order_by('price').reverse()

双下划线查询

filter

字段名加__符号位
查询价格大于200的书籍
    # res = models.Book.objects.filter(price__gt=200)

price__gt=200 查询价格大于200的书籍

price__lt=200 查询价格小于200的书籍

price__gte=200 查询价格大于等于200的书籍

price__lte=200 查询价格小于等于200的书籍

price__in=[200,123,23] 查询价格是200或者123或者23的
 
price_range(100,200) 查询价格在100到200的 顾头不顾尾

模糊匹配

filter

# 查询书籍名称中包含p的
    # res = models.Book.objects.filter(title__contains='p')  # 区分大小写

__contains='p' title里面包含p的

__icontains='p' 忽略大小写,title里面包含p,P的

__startwith="啥" 以三开头的

__endwith="P" 以P结尾的

__year='2019' 年为2019的

__month='10' 月份为10月的

多表操作

一对多

# publish_id直接添加版社主键值
models.Book.objects.create(title='三国演义',price=123.23,publish_id=1)  

# publish直接添加出版社数据对象
publish_obj = models.Publish.objects.filter(pk=2).first()
models.Book.objects.create(title='水浒传',price=123.23,publish=publish_obj)  

book_obj = models.Book.objects.filter(pk=1).first()

# 获取到当前书本所对应的出版社对象,可以直接查询到关联的记录对象,多 .一 可以直接查询一的数据
print(book_obj.publish)  
# 获取到的就是表中的实际字段
print(book_obj.publish_id)  

会判断数据是否变化,没有变化不修改

models.Book.objects.filter(pk=1).update(publish_id=3)

#通过对象修改
publish_obj = models.Publish.objects.filter(pk=2).first()
models.Book.objects.filter(pk=1).update(publish=publish_obj)

# models.Publish.objects.filter(pk=2).delete()
# 默认也是级联更新 级联删除

多对多

# 给主键为3的书籍添加两个作者 1 2
book_obj = models.Book.objects.filter(pk=3).first()
print(book_obj.authors)  # 就相当于 已经在书籍和作者的关系表了
book_obj.authors.add(1)
book_obj.authors.add(2,3)

author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
book_obj.authors.add(author_obj)
book_obj.authors.add(author_obj,author_obj1)
"""
add() 括号内既可以传数字也可以传数据对象
并且都支持传多个
"""

book_obj = models.Book.objects.filter(pk=3).first()
book_obj.authors.set([3,])
book_obj.authors.set([1,3])

author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
book_obj.authors.set((author_obj,))
book_obj.authors.set((author_obj,author_obj1))

"""
set() 括号内 既可以传数字也传对象 
并且也是支持传多个的
但是需要注意 括号内必须是一个可迭代对象
"""

# 删
book_obj = models.Book.objects.filter(pk=3).first()
book_obj.authors.remove(2)
book_obj.authors.remove(1,2)

author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
book_obj.authors.remove(author_obj)
book_obj.authors.remove(author_obj,author_obj1)
"""
remove() 括号内 既可以传数字也传对象 
并且也是支持传多个的
"""
# 清空
book_obj = models.Book.objects.filter(pk=3).first()
book_obj.authors.clear()
"""clear()括号内不需要传任何参数 直接清空当前书籍对象所有的记录
"""

多表查询

多表查询有两种形式

子查询和连表查询

基于对象的跨表查询 子查询

1.查询书籍是python入门的出版社名称
book_obj = models.Book.objects.filter(title='python入门').first()
正向查询按字段
print(book_obj.publish.name)
print(book_obj.publish.addr)

2.查询书籍主键是6的作者姓名
book_obj = models.Book.objects.filter(pk=6).first()

print(book_obj.authors)  # app01.Author.None
print(book_obj.authors.all())

3.查询作者是jason的手机号
author_obj = models.Author.objects.filter(name='jason').first()

print(author_obj.author_detail.phone)
print(author_obj.author_detail.addr)

"""
正向查询 按字段 
当该字段所对应的数据有多个的时候 需要加.all()
对象点外键字段直接就能够拿到数据对象
"""
4.查询出版社是东方出版社出版过的书籍
publish_obj = models.Publish.objects.filter(name='东方出版社').first()

print(publish_obj.book_set)  # app01.Book.None
print(publish_obj.book_set.all())

5.查询作者是jason写过的所有的书
author_obj = models.Author.objects.filter(name='jason').first()

print(author_obj.book_set)  # app01.Book.None
print(author_obj.book_set.all())

6.查询手机号是110的作者
author_detail_obj = models.AuthorDetail.objects.filter(phone=110).first()

print(author_detail_obj.author)
print(author_detail_obj.author.name)
print(author_detail_obj.author.age)

7.查询书籍是python入门的作者的手机号
book_obj = models.Book.objects.filter(title='python入门').first()
print(book_obj.authors.all())

一对一正反都不用set,注意单个对象才能.
"""
反向查询按表名小写 
什么时候需要加_set
当查询的结果可以是多个的情况下 需要加_set.all()
什么时候不需要加_set
当查询的结果有且只有一个的情况下 不需要加任何东西 直接表名小写即可
"""

基于双下划线的跨表查询 连表查询

"""
MySQL
left join
inner join
right join
union
"""

1.查询书籍是python入门的出版社名称
正向
res = models.Book.objects.filter(title='python入门').values('publish__name')
print(res)
反向
res = models.Publish.objects.filter(book__title='python入门').values('name')
print(res)

2.查询作者是jason的手机号码
正向
res1 = models.Author.objects.filter(name='jason').values('author_detail__phone')
print(res1)
反向
res = models.AuthorDetail.objects.filter(author__name='jason').values('phone','author__age')
print(res)

3.查询手机号是120的作者姓名
res2 = models.AuthorDetail.objects.filter(phone=120).values('author__name')
print(res2)
res = models.Author.objects.filter(author_detail__phone=120).values('name','author_detail__addr')
print(res)

4.查询出版社是东方出版社出版的书籍名称
res = models.Publish.objects.filter(name='东方出版社').values('book__title','addr')
print(res)
5.查询作者是jason的写过的书的名字和价格
res = models.Author.objects.filter(name='jason').values('book__title','book__price')
print(res)

6.查询书籍是python入门的作者的手机号
res = models.Book.objects.filter(title='python入门').values('authors__author_detail__phone')
print(res)

添加-修改-删除

添加

user_obj = models.Userinfo.objects.create(username=username,password=password)
# insert into userinfo(username,password) values('admin','666');
1.create方法会有一个返回值  返回值就是当前被创建的数据对象

2.user_obj=user(username="zx")利用对象点方法方式
user_obj.save()  把当前对象保存到数据库中

修改

models.Author.objects.filter(pk=author_id).update(name=name,phone=phone)
#pk为查询主键,更改查询出来的所有数据对象

也可以获取对象.属性修改.save()    不推荐,所有数据全部重新写入,效率低

删除

models.Author.objects.filter(pk=author_id).delete()
#批量删除

聚合查询

关键字:aggregate
    """
    from django.db.models import Max,Min,Count,Sum,Avg
    # 统计所有书平均价格
    # res = models.Book.objects.all().aggregate(Avg('price'))
    # res1 = models.Book.objects.all().aggregate(Max('price'))
    # res2 = models.Book.objects.all().aggregate(Min('price'))
    # res3 = models.Book.objects.all().aggregate(Sum('price'))
    # res4 = models.Book.objects.all().aggregate(Count('title'))
    # res5 = models.Book.objects.all().aggregate(Avg('price'),Max('price'),Min('price'),Sum('price'),Count('title'))
    # print(res5)

    """

分组查询

关键字:annotate
    """
    # 1.统计每一本书的作者个数
    # res = models.Book.objects.annotate(author_num = Count('authors')).values('author_num')
    # print(res)

    # 2.统计出每个出版社卖的最便宜的书的价格
    # res = models.Publish.objects.annotate(price_min=Min('book__price')).values('price_min')
    # print(res)

    # 3.统计不止一个作者的图书
    """
    1.统计每本书对应的作者个数
    2.基于上面的结果 筛选出作者个数大于1 的
    
    """
    # res = models.Book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1).values('author_num')
    # print(res)

    # 4.查询各个作者出的书的总价格
    # res = models.Author.objects.annotate(sum_price=Sum('book__price')).values('sum_price')
    # print(res)

F与Q查询

我们之前在查询数据库的时候条件都是我们自己手写的
但是现在出现了条件是从数据库里面获取的

F查询

	from django.db.models import F,Q
    # 1.查询出卖出数大于库存数的书籍
    # res = models.Book.objects.filter(maichu__gt=F('kucun'))
    # print(res)

    # 2.将所有的书的价格 全部提高100块
    # models.Book.objects.update(price=F('price') + 100)

    # 3.了解  尝试着将所有的书的名字后面都加上 爆款

   

Q查询

 # 1.查询书籍名称是python入门或者价格是544.44的书
    # res = models.Book.objects.filter(title='python入门',price=544.44)
    # res = models.Book.objects.filter(Q(title='python入门'),Q(price=544.44))  # 逗号就是and
    # res = models.Book.objects.filter(Q(title='python入门')|Q(kucun=666))  # 用来Q之后 就能够支持|表示或
    # res = models.Book.objects.filter(~Q(title='python入门')|Q(kucun=666))  # esc下面那个键 波浪号  表示非
    # print(res)

    # Q查询进阶用法   用Q产生对象 然后再使用
    # q = Q()
    # q.connector = 'or'
    # q.children.append(('title__icontains','p'))
    # # q.children.append(('kucun',666))
    # res = models.Book.objects.filter(q)
    # print(res)
    """
    字符串的左边 跟你的变量名条件书写一模一样
    """

参数渲染的方式

字典传值

today = datetime.datetime.now()
content = {'date':today}
return render(request,'login.html',content)

{{date}}

函数局部变量全部传递local()

user_queryset = models.Userinfo.objects.all()
return render(request,'userlist.html',locals())

{% for re in res %}
{% endfor %}
posted @ 2019-10-22 20:25  zx125  阅读(135)  评论(0编辑  收藏  举报