六、ORM语句——三

多表操作

表与表之间的关系

1、一对多(必须在“多”的表中创建关联字段,外加约束)
2、一对一(在任意表中加关联字段,外加约束)
3、多对多
详细信息在mysql数据库部分已经说过,这里不再细说

用ORM创建多张表及创建他们之间的联系

1、注意事项

  1. 表的名称myapp_modelName,是根据模型中的原数据自动生成的;id字段是自动添加的
  2. 对于外键字段,Django会使用"外键属性_id"来创建表中属性
  3. 这个例子中的CREATE TABLE SQL语句使用PostSQL语法格式,要注意的是Django中根据settings中指定的数据库来使用相应的SQL语句。
  4. 定义好models后,需要告诉Django使用这些模型(在配置文件(settings.py)的INSTALLED_APPS中添加models所在的应用名称)
  5. 外键字段有一个"null=True"的属性,用来表示外键可以接受空值

2、以一个实例来说明用ORM创建多张表及创建他们之间的联系的方法(具体的在代码注释中解释),下面是本实例创建数据表的代码:

#创建图书表book
class Books(models.Model):
    nid = models.AutoField(primary_key=True)
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8,decimal_places=2)#最大位数为8,小数点占两位
    publish = models.ForeignKey(to='Publish',on_delete=models.CASCADE)#创建关联外键,其中参数为关联到那张表,并且必须设置删除方式(级联/非空等),且会自动在publish(属性名)后加"_id",类型会自动设为int型
    pub_date = models.DateField() #创建日期,格式须为"2012-12-12"
    authors = models.ManyToManyField(to='Author') #自动创建第三张表,关联两张表(即自动创建了一个多对多的关系),创建的表名为app01_books_authors
    #类中方法
    def __str__(self):
        return self.title
        
#创建出版社表
class Publish(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    email = models.CharField(max_length=32)
    
#创建作者表
class Author(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    age = models.CharField(max_length=32)#此处用models.IntegerField()更好
    email = models.CharField(max_length=32)
    #ad = models.OneToOneField(to='AuthorDetail',on_delete=models.CASCADE)#创建一个关联字段(由于author表在此之前已经创好,表示创建一个关联字段,关联的表是“AuthorDetail”
    
#创建一张表,关联作者表和书籍表(关系类型为多对多)
class Author2Book(models.Model):
   nid = models.AutoField(primary_key=True)
   book = models.ForeignKey(to='Books',on_delete=models.CASCADE)#创建外键,外键是Books表的主键。删除方式为级联。
   author = models.ForeignKey(to='Author',on_delete=models.CASCADE)

#一对一表(作者详情表)
class AuthorDetail(models.Model):
   addr = models.CharField(max_length=46)
   tel = models.IntegerField()
   author = models.OneToOneField(to='Author',on_delete=models.CASCADE)#创建关联字段,这个是关联Author表,如果在Author表中已经创建语句,则此句可以省略。
跨表查询

1、正向查询与反向查询
从有关联字段的那个表查起,为正向查询,反之则为反向查询
2、跨表查询的要点:
正向查询按字段;反向查询按表名小写,下面以实例来解释这两句话
3、实例

>一对多查询
   >#表一(查询一个结果)
    book = Books.objects.filter().first()
    #表二
    publish = Publish.objects.filter(nid=book.publish_id).first()
    #将以上两个组合成最终结果进行打印即可
   >#直接用"."运算符取到相应的对象,然后在取到相应的值(查询一个结果)
    book.publish.name(跨表查询)
    book.publish.email
   >查询某出版社的书籍(查询多个结果)(正向反向查询)
    pub_obj = Publish.objects.filter().first()
    pub_obj.book_set #表名_set:将所有结果放在一个集合内(反向查询使用)
    正式语法:pub_obj.book_set.all()
>多对多查询
   >正向查询按字段:book.authors.all()#authors字段
   >反向查询按"表名小写_set":book_set.all()
>一对一查询
   >正向查询按字段:book.字段
   >反向查询按表名小写:author.book
>示例:
   >
2、基于双下划线(基于join实现,其本质就是拼表):本实例在ORM2项目中的query2路径下
>要点(核心):正向查询按字段,反向查询按表名小写
>查询结果形式:以queryset数据类型(类列表),将每个结果组成一个字典,每个字典为列表的一个元素
  >实例一:查询《花》这本书的出版社的名字和邮箱(多对一)
   >对应的sql语句如下:select app01_publish.`name`,app01_publish.email from app01_books 
              inner join app01_publish on app01_books.publish_id=app01_publish.nid where app01_books.title="花"
  >整个实例的函数如下:
       def query2(request):
        #####################################基于双下划线的跨表查询(基于join实现)################################
        查询要点:正向查询按字段,反向查询按表名小写
        查询《花》这本书的出版社的名字和邮箱(多对一):此处可以用Books表开头,也可以用Publish表开头
        以Books为基表进行查询和连接组合
            ret = Books.objects.filter(title='花').values('publish__name','publish__email')#这里是跨表查询,首先在values()方法中,告诉ORM要进行跨表(所跨表为publish,用__表示跨表)查询(正向),然后再接"__name"告诉ORM引擎要显示publish表下的name和email字段
        以Publish为基表进行查询和连接组合,首先告诉ORM引擎,要用表名小写的方式,然后再用__字段名来指示用连接的表的那个字段
            ret = Publish.objects.filter(books__title='花').values('name','email')#values()方法中的字段表示要显示那个字段
            print(ret)
        查询“人民出版社”出版的所有书籍的名称(一对多)
            ret = Publish.objects.filter(name='人民出版社').values('books__title')
            print(ret)
            ret = Books.objects.filter(publish__name="人民出版社").values('title')
            print(ret)
        查询《计算机网络》这本书的作者的年龄(一对多)
            ret = Books.objects.filter(title='计算机网络').values('authors__age')
            print(ret)
            ret = Author.objects.filter(books__title='计算机网络').values('age')
            print(ret)
        查询“老舍”编写的所有书籍的名称(多对多)
            ret = Author.objects.filter(name='老舍').values('books__title')
            print(ret)
            ret = Books.objects.filter(authors__name='老舍').values('title')
            print(ret)
        查询“老舍”的手机号(一对一)
            ret = Author.objects.filter(name='老舍').values('authordetail__tel')
            print(ret)
            ret = AuthorDetail.objects.filter(author__name="老舍").values('tel')
            print(ret)
        查询手机号为“668956”的作者名字
            ret = Author.objects.filter(authordetail__tel=668956).values('name')
            print(ret)
            ret = AuthorDetail.objects.filter(tel=668956).values('author__name')
            print(ret)
            return HttpResponse('ok')
>延伸:连续跨表
   Publish.objects.filter(name='人民出版社').values('books__title','books__authors__name')#books__authors__name为:先跨到books表,然后再跨到authors字段下的表,最后再取其中的属性name
   >从Publish跨到books表,从Publish表跨到books表,然后再按字段跨到Author表,再取其中相应属性name
分组查询

分组查询函数为annotate(别名=具体的函数,如Avg,Count等);而且当分组复杂时,报alias错误,另外,别名也是必须的;其具体语法为:类名.objects.values(分组依据的字段名).annotate(别名=具体的函数,如Avg,Count等),这句话表示的是按照前面values()里面的字段进行分组。
此外,单表分组查询时分组的依据一定不能是主键,因为没有意义(跨表同样,不能用表的主键进行划分)。
1、分组查询的思路

  1. 先将涉及到的表组合成一张表,再用单表查询的方式进行查询
  2. 跨表的分组查询
    实例:
  # 查询每个出版社的名称和其出版的书籍的个数(示例)    
 Publish.objects.values('name').annotate(price_avg=Avg("books__price"))
  1. 需要注意的是,分组默认是采用主表的主键进行分组的。
#常用语句:
Publish.objects.all().annotate(price_avg=Avg('books__price'))#返回的是按publish的nid分类的三个对象,并且对每个对象下的books书的价格求了平均值
#其中最后会有四个属性,第四个属性为price_avg,后可接values()方法,可以控制最后要显示的结果
#由于默认是用主键进行分组,所以可以省略all()方法

2、实例:查询书籍表每一个出版社id以及对应的书籍个数

Books.objects.all().values('title')等价于Books.objects.values('title')
Books.objects.values('publish_id').annotate(Count(1))#按照前面values()里面的字段进行分组
'''
对应的SQL语句为:select Count(1) from books group by publish_id
'''
F与Q查询

1、F查询(用来比较两个字段的大小时用到)

#1、步骤:
  >引入F函数:from django.db.model import F
  >示例:查询评论数大于点赞数的书籍
        Books.objects.filter(comment_count__gt=F("poll_count"))
    #后面的F()函数还可以接运算式进行结果运算(如F()+3,即大于点赞数加3)

2、Q查询(用于或关系的查询)(且的关系在filter()方法中直接加入多个参数进行约束即可)

>步骤:
   >引入Q函数:from django.db.model import Q
   >示例:查询评论数大于3000或者售价大于100的书籍
       Books.objects.filter(Q(comment_count__gt=3000)|Q(price__gt=100))
    >其中将每个条件分别包在Q函数里,然后将两个Q函数用关系运算符相联,"|"表示或,“&”表示且,"~"表示非,如下:
       Books.objects.filter(Q(comment_count__gt=3000)&Q(price__gt=100))
     >这段代码表示查询评论数大于3000且售价大于100的书籍,其等价于:Books.objects.filter(comment_count__gt=3000,price__gt=100)
ORM聚合函数

ORM中,聚合函数都是写在aggregate()函数中的,具体的语法为aggregate(具体的聚合函数,如Avg等)
聚合的步骤为:

聚合的步骤:
  >引入相应的聚合函数:from django.db.models import Avg,Max,Sum,Min,Count
  >编写ORM语句,如下:
    #查询所有书籍的平均价格(实例)
    ret = Books.objects.all().aggregate(Avg('price'))#结果为{avg_price:值},其中参数也可以起别名,如(priceAvg=Avg('price')
    return HttpResponse(ret)
静态文件的设置

在web项目中,会有很多的图片、视频、.css、.js等文件,我们把这些文件统称为静态文件,而Django不允许在页面中直接用本地(实际)路径去访问这些文件,而需要将其放在静态文件夹下,才可以。
具体的配置方法如下:

1、在Django项目文件夹下建立"static"包(即static文件夹)
2、建立"img"文件夹
3、建立"js"文件夹等各种文件夹
4、导入项目用到的静态文件
5、在"settings.py"文件夹中做如下设置:

  1. 添加:
    STATIC_URL = ‘/static/’ #这个是给下面的STATICFILES_DIRS起别名,以后通过/static/就可以直接找到static包,而原本的路径是后面列表中的路径(以os开头的)
    STATICFILES_DIRS = [
    os.path.join(BASE_DIR,‘static’)#其中"static"参数为第一步建立的包的名称,两者须保持一致
    ]
    以上这两句话为一套东西,其中STATIC_URL在"settings.py"文件的末尾
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值