ORM表操作

时间:2023-03-09 04:11:27
ORM表操作

1.在python脚本中调用django环境

在根文件夹下,创建test.py文件

import os
if __name__ == '__main__':
    os.environ.setdefault("DJANGO_SETTINGS_MODULE",'day76.settings')
    import django
    django.setup()

2.单表增删改查

-查询api   <1> all():                  查询所有结果                     <2> filter(**kwargs):       它包含了与所给筛选条件相匹配的对象          <3> get(**kwargs):          返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。 注意:返回的是查找到的对象,不是queryset对象。   <4> exclude(**kwargs):      它包含了与所给筛选条件不匹配的对象      <5> order_by(*field):       对查询结果排序('-id')      <6> reverse():              对查询结果反向排序             <8> count():                返回数据库中匹配查询(QuerySet)的对象数量。      <9> first():                返回第一条记录         <10> last():                返回最后一条记录           <11> exists():              如果QuerySet包含数据,就返回True,否则返回False       <12> values(*field):        返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列                        model的实例化对象,而是一个可迭代的字典序列   <13> values_list(*field):   它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列              <14> distinct():            从返回结果中剔除重复纪录
-基于双下划线的模糊查询   Book.objects.filter(price__in=[100,200,300])   Book.objects.filter(price__gt=100)   Book.objects.filter(price__lt=100)   Book.objects.filter(price__gte=100)   Book.objects.filter(price__lte=100)   Book.objects.filter(price__range=[100,200])   Book.objects.filter(title__contains="python")   Book.objects.filter(title__icontains="python")   Book.objects.filter(title__startswith="py")   Book.objects.filter(pub_date__year=2012)
import os
if __name__ == '__main__':
    os.environ.setdefault("DJANGO_SETTINGS_MODULE",'day76.settings')
    import django
    django.setup()
    from app01 import models
    import datetime
    #一、 增,插入数据的两种方式:
    #时间可以传字符串,也可以传日期格式
    ctime=datetime.datetime.now()
    # 方式1:
    # book1=models.Book.objects.create(name='红楼梦',price=25.8,publish='南京出版社',author='曹雪芹',create_date=ctime)
    # print(book1.name)
    # 方式2:先实例化产生对象,然后调用save方法,保存
    # book2=models.Book(name='西游记',price=65.5,publish='东京出版社',author='吴承恩',create_date='2018-05-05')
    # book2.save()
    # print(book2.name)
    #二、删
    # 方式1:
    # ret=models.Book.objects.filter(name='西游记').delete()#ret是影响的行数,因为找到的对象是queryset,可能不止一个值
    # print(ret)
    # 方式2:
    # models.Book.objects.filter(name='西游记').first().delete()#找到指定的对象,然后进行删除
    # 三、修改
    # models.Book.objects.filter(name='西游记').update(price=85)#这个修改的是queryset对象,可能有多个值
    # book=models.Book.objects.filter(name='西游记').first()#这个修改的是找到的单个书对象,无法使用update方法
    # book.price=50#找到对象,修改它的price值
    # book.save()#然后进行保存
    # 四、查询
    # *******查询是重点******#
    '''
    1)all()                     查询所有结果
    2)filter(**kwargs)          包含了与所给筛选条件相匹配的对象
    3)get(**kwargs)             返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有,都会报错
    4)exclude(**kwargs)         它包含了与所给筛选条件不匹配的对象
    5)order_by(*field)          对查询结果排序
    6)reverse()                 对查询结果反向排序
    8)count()                   返回数据库中匹配查询(QuerySet)的对象数量
    9)first()                   返回第一条记录
    10)last()                   返回最后一条记录
    11)exists()                 如果queryset包含数据,就返回True,否则返回False
    12)values(*field)           返回一个valuequeryset一个特殊的queryset,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典序列
    13)values_list(*field)      它与vaule()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
    14)distinct()               从返回结果中剔除重复记录

    基于双下划线的模糊查询
        Book.objects.filter(price__in=[100,200,300])
        Book.objects.filter(price__gt=100)
        Book.objects.filter(price__lt=100)
        Book.objects.filter(price__gte=100)
        Book.objects.filter(price__lte=100)
        Book.objects.filter(price__range=[100,200])
        Book.objects.filter(title__contains="python")
        Book.objects.filter(title__icontains="python")
        Book.objects.filter(title__startswith="py")
        Book.objects.filter(pub_date__year=2012)
    '''
    # all
    # ret=models.Book.objects.all()#查询所有
    # print(ret)
    # ret=models.Book.objects.filter(name='西游记').first()#查询名字为西游记的第一个
    # res=models.Book.objects.filter(name='西游记')[1]#查询名字为西游记的第二个,不支持负数
    # print(ret,res)
    # filter可以传多个参数,用逗号分隔,他们之间是and关系
    # ret=models.Book.objects.filter(name='西游记',price=50)
    # print(ret.query)#query是打印相关sql语句
    # get
    # ret=models.Book.objects.get(name='三国演义')#使用get只在值只有一个时才能用,不然报错,返回的是对象,不是query对象。通常用id来查
    # print(ret)
    # ret=models.Book.objects.get(id=1)
    # print(ret)
    # exclude
    # ret=models.Book.objects.exclude(name='西游记')#查询名字不叫西游记的书,结果也是queryset对象
    # print(ret)
    # ret=models.Book.objects.exclude(name='西游记',price=50)#查询除了名字叫西游记且价格为50的以外的所有书
    # print(ret)
    #order_by排序
    # ret=models.Book.objects.order_by('price')#按价格升序排,也可以传多个
    # print(ret)
    # ret=models.Book.objects.order_by('-price')#按价格降序排
    # print(ret)
    #reverse倒序
    # ret=models.Book.objects.order_by('price').reverse()#反向排序
    # print(ret)
    #count查结果个数,返回数据库中匹配查询queryset的对象数量
    # ret=models.Book.objects.all().count()
    # print(ret)
    # first和last第一个和最后一个
    # ret=models.Book.objects.all().first()
    # res=models.Book.objects.all().last()
    # print(ret,res)
    #exists,返回结果是布尔类型
    # ret=models.Book.objects.filter(name='python').exists()
    # print(ret)
    #values,里面包含了要查询的字段,如果不传值,则默认打印所有字段,返回的对象,里面有字典形式的数据
    # res=models.Book.objects.filter(name='python').values()
    # ret=models.Book.objects.filter(name='红楼梦').values('name','price')
    # print(ret,res)
    #value_list与values非常相似,它返回的是一个元组序列,values返回的是一个字典序列
    #distinct去重,只有都不一样才会去重,可以配合values使用
    # ret=models.Book.objects.all().values('name').distinct()
    # print(ret)

    #基于双下划线的模糊查询
    #__gt大于,__lt小于
    # ret=models.Book.objects.filter(price__lt=40)
    # res=models.Book.objects.filter(price__gt=40)
    # print(ret,res)
    #__gte大于等于,__lte小于等于
    # ret=models.Book.objects.filter(price__gte=85)
    # print(ret)
    # ret=models.Book.objects.filter(price__lte=50)
    # print(ret)
    #in 在某个选择范围中
    # ret=models.Book.objects.filter(price__in=[50,85,60])
    # print(ret)
    #range在某个区间中,是全闭区间(但是好像只有前后封闭的是整数才能取到)
    # ret=models.Book.objects.filter(price__range=[25,85])
    # print(ret)
    #contains内容包含某个字符
    # ret=models.Book.objects.filter(name__contains='p')
    # print(ret)
    #icontains忽略大小写
    # ret=models.Book.objects.filter(name__icontains='P')
    # print(ret)
    #startwith以...开头
    # ret=models.Book.objects.filter(name__startswith='p')
    # print(ret)
    #endswith以...结尾
    # ret=models.Book.objects.filter(name__endswith='on')
    # print(ret)
    #pub_date__year查询某年的对象
    # ret=models.Book.objects.filter(create_date__year=2015)
    # print(ret)

3.多表模型创建

OneToOneField要写to哪个表,to_filed=不写的话,默认是与id(一般是自增主键)相对应

ForeignKey要写to哪个表,to_filed=不写的话,默认是与id(一般是自增主键)相对应

创建唯一性约束时,要加上unique=True

sex_num=models.IntegerField(unique=True)

有时会创建联合唯一约束(这种情况多发生在两个字段分别关联外键),创建联合唯一约束有很多局限性,会降低查询性能。创建联合唯一约束的目的是为了不写脏数据

class UpAndDown(models.Model):
    nid = models.AutoField(primary_key=True)
    user = models.ForeignKey(to='UserInfo', to_field='nid')
    article = models.ForeignKey(to='Article', to_field='nid')
    is_up = models.BooleanField()

    class Meta:
        # 写这些,只是为了不写脏数据,联合唯一
        unique_together = (('user', 'article'),)
from django.db import models

# Create your models here.
'''
使用了OneToOneField和ForeignKey,模型表的字段,后面会自动加上_id
ManyToManyField会自动创建第三张表
*****重点
一对一关系:OneToOneField
一对多关系:ForeignKey
多对多关系:ManyToManyField

'''
class Publish(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=12)
    addr = models.CharField(max_length=64)
    email = models.EmailField(max_length=20)  # email,实际上是varchar
    def __str__(self):
        return self.name

class Author(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=12)
    sex = models.IntegerField()  # 整型
    # 可以用foreignkey,但是得设置唯一性约束,会报警告,不建议用
    authordetail = models.OneToOneField(to='Authordetail', to_field='id')
    def __str__(self):
        return self.name

class Authordetail(models.Model):
    id = models.AutoField(primary_key=True)
    phone = models.CharField(max_length=12)
    addr = models.CharField(max_length=64)
    def __str__(self):
        return self.id

class Book(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=12)
    price = models.DecimalField(max_digits=5,decimal_places=1)
    publish=models.ForeignKey(to='Publish',to_field='id')#to表示关联哪张表,to_field表示关联哪个字段
    authors=models.ManyToManyField(to='Author')#多对多会自动创建第三张表
    def __str__(self):
        return self.name

4.多表增删改查

update在pycharm没有tab提示

注意多表的add,remove,set的用法

add绑定多对多关系

book.authors.add(1,4)可接对象或数字

book.authors.remove(1,2)可接对象或数字

book.authors.clear()清空被关联对象集合

book.author.set((1,4))先清空后设置,只能接一个参数,可以传列表,元组。

import os
if __name__ == '__main__':
    os.environ.setdefault('DJANGO_SETTINGS_MODULE','day77.settings')
    import django
    django.setup()
    from app01.models import *
    #一对多新增数据
    # 方式1:
    #外键输入id时,可以输字符串,也可以输数字
    # ret=Book.objects.create(name='狼图腾',price=48.8,publish_id='2')
    # print(ret)
    # 方式2:存对象
    # publish=Publish.objects.filter(name='北京出版社').first()
    # ret=Book.objects.create(name='花仙子',price=55.8,publish=publish)
    # print(ret)
    #一对多修改数据
    # 方式1:
    # book=Book.objects.get(pk=1)
    # book.publish_id=3
    # book.save()
    # 方式2:#publish既可以传数字,也可以传对象,但是为了使用起来看起来方便,还是publish对对象,publish_id对数字
    # publish=Publish.objects.filter(id=3).first()
    # Book.objects.filter(id=1).update(publish=publish)
    #多对多关系
    #add添加
    #为西游记新增lqz作者
    # book=Book.objects.filter(name='西游记').first()
    # book.authors.add(1,2)#可以直接添加数字
    # author=Author.objects.filter(id=3).first()
    # book = Book.objects.filter(name='西游记').first()
    # book.authors.add(author)#也可以添加对象
    #remove删除
    # author = Author.objects.filter(id=3).first()
    # book = Book.objects.filter(name='西游记').first()
    # # book.authors.remove(1)#可以传数字
    # book.authors.remove(author)#可以传对象,不要数字和对象混着用
    #clear清除所有
    # book = Book.objects.filter(name='西游记').first()
    # book.authors.clear()
    #set先清空再添加
    # book = Book.objects.filter(name='西游记').first()
    # book.authors.set([1,3])#必须穿一个可迭代的数据,传列表就完事了。

    #基于对象的跨表查询
    #1.一对一
    #正向查询 author--关联字段在author--authordetail--按字段
    #反向     authordetail--关联字段在author--author--按表名小写
    #查询作者lqz的手机号
    #1)正向查
    # ret=Author.objects.filter(name='lqz').first().authordetail.phone
    # print(ret)
    # ret=Author.objects.filter(name='lqz').first().authordetail.phone
    # print(ret)
    #2)反向查 查询地址为上海的作者名字
    # authordetail=Authordetail.objects.filter(addr='上海').first()
    # author=authordetail.author
    # print(author.name)
    # res=Authordetail.objects.filter(author__name='lqz').first().phone
    # print(res)
    #2.一对多
    # 正向: 正向查询按字段
    #正向查询,查询西游记这本书的出版社邮箱
    # ret=Book.objects.filter(name='西游记').first().publish.email
    # print(ret)
    # 反向: 反向按表名小写_set.all()
    #反向查询,查询地址是北京的出版社出版的图书
    # ret=Book.objects.filter(publish__addr='北京')
    # print(ret)
    # publish=Publish.objects.filter(addr='北京').first()
    # books=publish.book_set.all()#一个出版社可以出版多个图书,是一个出版社对多个图书的关系,所以是publish.book_set.all()
    # print(books)
    #多对多
    # 正向: 正向查询按字段
    # 反向查询: 反向按表名小写_set.all()
    #  ** ** ** 基于对象的查询, 多次查询(子查询)
    #正向查询西游记这本书所有的作者
    # ret=Book.objects.filter(name='西游记').first().authors.all()
    # print(ret)
    #反向查询lqz写过的所有的书
    # lqz=Author.objects.filter(name='lqz').first()
    # books=lqz.book_set.all()
    # print(books)
    #查询西游记这本书所有作者的手机号,基于对象的查询,多次查询(子查询)
    # authors=Book.objects.filter(name='西游记').first().authors.all()
    # for author in authors:
    #     print(author.authordetail.phone)

    #基于双下划线的查询,连表查询
    #一对一
    #查询lqz作者的手机号
    #以author表作为基表    正向查询,跨表的话按字段
    # ret=Author.objects.filter(name='lqz').values('authordetail__phone')
    # print(ret)
    #以authordetail作为基表    反向查询,跨表的话,表名按小写
    # ret=Authordetail.objects.filter(author__name='lqz').values('phone')
    # print(ret)

5.基于双下划线的增删改查

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

import os
if __name__ == '__main__':
    os.environ.setdefault('DJANGO_SETTINGS_MODULE','day77.settings')
    import django
    django.setup()
    from app01.models import *
    #基于双下划线的一对多查询
    #查询出版社为北京出版社的所有图书的名字
    # ret=Publish.objects.filter(name='北京出版社').values('book__name','book__price')
    # print(ret)
    #查询北京出版社出版的价格大于19的书
    # ret=Publish.objects.filter(name='北京出版社',book__price__gt=19).values('book__name')
    # print(ret)

    #多对多
    #查询西游记的所有作者名字
    # ret=Book.objects.filter(name='西游记').values('authors__name')
    # print(ret)
    #查询图书价格大于30的所有作者的名字
    # ret=Book.objects.filter(price__gt=30).values('authors__name')
    # print(ret)
    #连续跨表
    #查询北京出版社出版过的所有书籍的名字以及作者名字
    # ret=Publish.objects.filter(name='北京出版社').values('book__name','book__authors__name')
    # print(ret)

只有查询到的结果是queryset对象时,才能打印queryset的query,也就是查询的sql语句

books = models.Book.objects.filter(authors__name='lqz')
    print(books.query)

6.聚合查询

使用聚合函数首先要导入相应模块

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

aggregate()是queryset的一个终止子句,意思是说,它返回一个包含一些键值对的字典。键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。

简单记忆方法:聚合要父母agree,所以是aggregate函数

聚合查询查出的结果是字典

 from django.db.models import Avg, Count, Max, Min, Sum
    #聚合查询,在mysql数据库不用做上下比较,从头到尾取完数据可以直接进行统计的用aggregate
    #使用聚合函数,Avg,Count,Max,Min,Sum等跨表查询可能不会智能提示,
    #计算所有图书的平均价格
    # ret=Book.objects.all().aggregate(Avg('price'))
    # print(ret)
    #计算图书的最高价格和最低价格
    # ret=Book.objects.all().aggregate(Max('price'),Min('price'))
    # print(ret)

7.分组查询

简单记忆方法:分组,分成一个一个的,是an,所以是annotate函数

以什么为分组,就以什么为基表开始查。

查询出的结果是queryset对象,里面有一大堆的字典

#分组查询,其实就是要在mysql做那种上下进行比较的筛选,这时候用annotate,也就是分组
    #统计每一本书作者个数
    # ret=Book.objects.all().annotate(c=Count('authors'))#意思是把所有书的对象筛选出来,然后算有多少个作者
    # for r in ret:
    #     print(r.c)
    # ret=Book.objects.all().annotate(c=Count('authors')).values('name','c')#不循环,直接取值
    # print(ret)

    #统计每一个出版社的最便宜的书(以谁group by 就以谁为基表)
    # ret=Publish.objects.all().annotate(c=Min('book__price')).values('name','c')
    # print(ret)
    #统计每一本以py开头的书籍的作者个数
    # ret=Book.objects.filter(name__startswith='py').annotate(c=Count('authors')).values('c')
    # print(ret.query)
    #总结 group by 谁,就以谁做基表,filter过滤,annotate去分组,values取值
    #总结终极版本
        #values在前,表示group by,再后表示取值(其实默认查询都会写values在前一次,group by的是id。)
        #filter在前,表示过滤(where),在后,表示having(对分组之后的结果再进行过滤)
    #统计每一本以py开头的书籍的作者个数(和上面的sql语句一样)
    # ret=Book.objects.all().values('pk').filter(name__startswith='py').annotate(c=Count('authors')).values('name','c')
    # print(ret.query)
    #查询每个作者出的书的总价格
    # ret=Author.objects.all().values('id').annotate(c=Sum('book__price')).values('name','c')
    # print(ret)
    #查询写的书的总价格大于30的所有作者
    # ret=Author.objects.all().annotate(c=Sum('book__price')).filter(c__gt=30).values('name','c')
    # print(ret)

8.F函数

F函数一般用于同一个对象的不同字段,其数据进行对比时,比如一本书的评论数大于阅读数,这时就需要用到F函数进行包裹一下。

#F函数
    from  django.db.models import F
    #为了字段=后面的值,不能放字段,所以用F函数包裹一下就可以了
    #查询阅读数大于评论数的书
    # ret=Book.objects.filter(read_num__gt=F('meat_num'))
    # print(ret)
    #把所有书的评论数加1
    # Book.objects.all().update(read_num=F('read_num')+1)
    #把西游记这本书阅读数-5
    # Book.objects.filter(name='西游记').update(read_num=F('read_num')-5)

9.Q函数

 #Q函数    为了构造与&,或|,非~的关系
    from django.db.models import Q
    #查询作者名字是lqz或egon的书
    # book=Book.objects.filter(Q(authors__name='lqz')|Q(authors__name='egon')).distinct()
    # print(book)
    #查询作者不是lqz的书
    # ret=Book.objects.filter(~Q(authors__name='lqz'))
    # print(ret)

10.ORM字段参数

null      可以为空

unique      唯一性约束

default      默认值

db_index   为该字段建索引

只给日期型和时间型用

  auto_now_add  新增数据时,默认把当前时间存入

  auto_now    修改的时候,默认把当前时间存入

  related_name  反向操作时,使用的字段名,用于代替原反向查询时的'表名_set'(一般情况下不用)

11.元信息

在models里建表时,可以在表里定义一个Meta类,里面封装了一些数据库的信息,主要字段如下:

db_table        ORM在数据库中的表名默认是app_类名,可以通过db_table可以重写表名

index_together     联合索引

unique_together     联合唯一索引

ordering        指定默认按什么字段排序

class Test(models.Model):
    name=models.CharField(max_length=12)
    class Meta:
        db_table='test'

12.choice

前面在建表时,在作者表,有一项是性别,1是男,2是女。在不数据库不怎么变动,这种映射关系不改变的情况下,可以使用choice

class Author(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    mychoice=((1,'男'),(2,'女'))
    sex = models.IntegerField(choices=mychoice)
    addr = models.CharField(max_length=64)
    authordetail = models.OneToOneField(to='AuthorDetail', to_field='id', null=True)
    def __str__(self):
        return self.name

这时候,当想要在取值时,直接打印出男女性别结果时,可以使用get_sex_display()的方法。注意,是查到的对象调用get_sex_display()方法,不是queryset调用get_sex_display()方法.

if __name__ == '__main__':
    os.environ.setdefault('DJANGO_SETTINGS_MODULE','ff12.settings')
    import django
    django.setup()
    from app01 import models
    author=models.Author.objects.filter(pk=3).first()
    author2=models.Author.objects.filter(pk=1).first()
    print(author.get_sex_display())
    print(author2.get_sex_display())

注意,当取的值,比如sex是3,没有相应男女关系映射时,这时候直接显示的是3。如果取的值有相应男女关系映射时,比如sex是1,则显示“男”。

当然,还有一种方法是做外键关联,另一张表写上“男”“女”。这样在取值时,可以去这张表进行查。只是在这里不太适合,在这里性别选项不会再多出变动,所以可以直接在数据库用choice选项。遇到其他情况,比如说VIP1-VIP10,金牌VIP,钻石VIP等等这种比较复杂的关系映射,甚至还有可能会进行变更的情况,这种情况下建议用外键关联而不是用choice。

13.only

需求:一个表有很多很多个字段,如果只要其中的一两个字段,name,我们只需要取出这一两个字段就可以了,效率会提升

import os
if __name__ == '__main__':
    os.environ.setdefault('DJANGO_SETTINGS_MODULE','ff12.settings')
    import django
    django.setup()
    from app01 import models
    ret=models.Book.objects.all().only('name')
    print(ret)
    print(ret[0])
    print(ret.first().price)

这么做的原因是为了优化sql查询,减轻mysql服务器的压力。

defer:除了指定之外的其他字段的所有值。同样查出来的也是存放在queryset中的对象

import os
if __name__ == '__main__':
    os.environ.setdefault('DJANGO_SETTINGS_MODULE','ff12.settings')
    import django
    django.setup()
    from app01 import models
    ret=models.Book.objects.all().defer('name')
    print(ret)
    print(ret[0].price)

14.手动创建第三张表

自动创建第三张表使用manytomany的方法的话,字段无法自己定制,甚至连插数据都找不到表。因此有了自己手动创建第三张表,根据业务需要进行自行定制相应字段等。

class Book(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    pub_date = models.DateTimeField()
    publish = models.ForeignKey(to='Publish', to_field='id')
    #to是和哪张表进行关联,through是手动创建的第三张表,through_fields是关联的字段,通过author向book字段进行关联(可以理解为author是自身上看不见的一个字段)
    author = models.ManyToManyField(to='Author',through='Book2Author',through_fields=('book','author'))
    def __str__(self):
        return self.name
class Book2Author(models.Model):
    id=models.AutoField(primary_key=True)
    book=models.ForeignKey(to='Book',to_field='id')
    author=models.ForeignKey(to='Author',to_field='id')
    test=models.CharField(max_length=32)
class Author(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    mychoice = ((1, '男'), (2, '女'))
    sex = models.IntegerField(choices=mychoice)
    addr = models.CharField(max_length=64)
    authordetail = models.OneToOneField(to='AuthorDetail', to_field='id', null=True)
    def __str__(self):
        return self.name

这时,再进行要帮书籍添加作者时,则需要调用第三张表

import os
if __name__ == '__main__':
    os.environ.setdefault('DJANGO_SETTINGS_MODULE','ff12.settings')
    import django
    django.setup()
    from app01 import models
    book=models.Book.objects.filter(pk=1).first()
    models.Book2Author.objects.create(test='haha',book_id=1,author_id=3)

15.建表可以选择DateField和DateTimeField

视业务需求而定

DateField可以选择用filter(pub_date='2018-12-12')这种形式去过滤

但是DateTimeField则不行,因为DateTimeField带了时分秒。

所以DateTimeField可以用filter(pub_date__day='28')

前端<input type='date'>传过来的时间带了时分秒?

16删除

级联删除:可以近似的把它理解成一个触发器,主表数据没了,外键关联部分也会跟着一起删除

publish = models.ForeignKey(to='Publish',to_field='nid',on_delete=models.CASCADE)

17.当models配置了choice选项时,显示其文字信息

# 固定用法:get_字段名字_display()
        user_type_name = request.user.get_user_type_display()