首页 > 其他 > 详细

Django 连表操作

时间:2020-04-04 22:05:25      阅读:74      评论:0      收藏:0      [点我收藏+]

介绍

基本概括

  • 一对多:models.ForeignKey(其他表)
  • 多对多:models.ManyToManyField(其他表)
  • 一对一:models.OneToOneField(其他表)

当你去调用它们时。关系如下:

第一个参数:模型,模型名(str)

第二个参数:是与主表与从表的关系。

  • CASCADE 级联,删除主表数据时连通一起删除外键表中数据
  • PROTECT 保护,通过抛出ProtectedError异常,来阻止删除主表中被外键应用的数据
  • SET_NULL 设置为NULL,仅在该字段null=True允许为null时可用
  • SET_DEFAULT 设置为默认值,仅在该字段设置了默认值时可用
  • SET() 设置为特定值或者调用特定方法
  • DO_NOTHING 不做任何操作,如果数据库前置指明级联性,此选项会抛出IntegrityError异常

注意事项

1.id字段不写的话会自动添加
2.对于外键字段,Django会在字段名上添加"_id"来创建数据库中的列名
3.外键字段ForeignKey有一个null=True的设置,你可以赋给它空值None

文章参考:http://www.py3study.com/Article/details/id/1562.html

一对一

OneToOneField

定义模型

作者与作者详细,可以看成一对一的关系。

class Author(models.Model):
    name = models.CharField(max_length=30)
    age = models.IntegerField()
    gender = models.CharField(max_length=30)
class AuthorDetail(models.Model):
    address = models.CharField(max_length=50)
    phone = models.IntegerField()
    author = models.OneToOneField(Author,models.CASCADE,default=‘‘)

创建数据

创建作者

from my_app import models

    author = models.Author.objects
    data = {
        name:kidd,
        age:18,
        gender:
    }

    author.create(**data)

技术分享图片

创建作者详细

第一种

from my_app import models

    author = models.Author.objects.filter(id=1)[0]
    detail = models.AuthorDetail.objects
    data = {
        address:青岛市,
        phone:12345,
        author:author
    }
    detail.create(**data)

技术分享图片

 第二种

from my_app import models

    detail = models.AuthorDetail.objects
    data = {
        address:青岛市,
        phone:54321,
        author_id:1
    }
    detail.create(**data)

技术分享图片

如果不知道author_id从哪来的,建议先看注意事项。

跨表查询

基于对象

返回类型:str

正向查询

通过作者姓名查询详细地址

from my_app import models

    author = models.Author.objects.filter(name=kidd)[0]
    author_address = author.authordetail.address

反向查询

通过手机号查询作者姓名

from my_app import models

    detail = models.AuthorDetail.objects.get(phone=54321)
    author = detail.author.name

基于下划线

返回类型:QuerySet

正向查询

from my_app import models

address = models.Author.objects.filter(name=kidd).values(authordetail__address)

反向查询

from my_app import models

author = models.AuthorDetail.objects.filter(author__name=kidd).values(address)

一对多

ForeignKey

定义模型

出版社可以出不同的书。

class Publish(models.Model):
    name = models.CharField(max_length=50)
    city = models.CharField(max_length=50)
class Book(models.Model):
    title = models.CharField(max_length=50)
    price = models.IntegerField()
    publish = models.ForeignKey(Publish,models.CASCADE)

创建数据

创建出版社

    from my_app import models

    data = {
        name:清X,
        city:北京,
    }
    models.Publish.objects.create(**data)

技术分享图片

创建书

第一种

from my_app import models

    obj = models.Publish.objects.get(id=1)
    data = [
        {
            title:九阳真经,
            price:68,
            publish:obj
        },
        {
            title:易筋经,
            price:66,
            publish:obj
        }
    ]
    for value in data:
        models.Book.objects.create(**value)

技术分享图片

第二种

    from my_app import models

    data = [
        {
            title:正骨内经,
            price:99,
            publish_id:1
        },
        {
            title: 太玄经,
            price: 89,
            publish_id: 1
        },
    ]
    for value in data:
        models.Book.objects.create(**value)

技术分享图片

跨表查询

基于对象

正向查询

查看书从哪个城市出版

    from my_app import models

    book = models.Book.objects.filter(id=2).first()
    city = book.publish.city

反向查询

查看出版社出版的所有书名

    from my_app import models

    publish = models.Publish.objects.filter(id=1).first()
    books = publish.book_set.all()
    for book in books:
        print(book.title)

基于下划线

正向查询

    from my_app import models

    city = models.Book.objects.filter(id=2).values(publish__city)
    print(city)

反向查询

    from my_app import models

    books = models.Publish.objects.filter(id=1).values(book__title)
    for book in books:
        print(book.get(book__title))

多对多

ManyToManyField

定义模型

作者跟书之间存在多对多的关系,一个作者可以创建好几本书,一本书可以有好几个作者。

class Author(models.Model):
    name = models.CharField(max_length=30)
    age = models.IntegerField()
    gender = models.CharField(max_length=30)

class Book(models.Model):
    title = models.CharField(max_length=50)
    price = models.IntegerField()
    authors = models.ManyToManyField(Author)

当你迁移完数据后,你会发现多了一张表,而这样表是Django自动创建的。我的这站表名为:my_app_book_authors

创建数据

创建作者

from my_app import models

    persons = [
        {
            name: 小明,
            age:28,
            gender:
        },
        {
            name: 小红,
            age: 26,
            gender: 
        },
        {
            name: 小军,
            age: 28,
            gender: 
        },
    ]

    for person in persons:
        models.Author.objects.create(**person)

技术分享图片

创建书

    from my_app import models

    book = models.Book.objects.create(title=学不会的数学,price=99)
    persons = models.Author.objects.filter(id__lt=5)
    book.authors.add(*persons)

技术分享图片

上面创建方式因为是从book中进行创建的,因为在Book中有author对象

如果想要在作者中创建,即没有ManyToManyField,可以加:模型名__set

关系表:

技术分享图片

现在我想把:作者id=3,书名 学不会的数学且价格为99从关系表中删除。

    from my_app import models

    book = models.Book.objects.filter(title=学不会的数学,price=99).first()
    author = models.Author.objects.filter(id=3).first()
    book.authors.remove(author)

技术分享图片

更多

# 清空被关联对象集合,无需传参
book.authors.clear()
# 先清空再设置,传递的参数必须是可迭代对象,一般为列表,列表内可以是对象,也可以是id
book.authors.set()

跨表查询

基于对象

正向查询

从书中查找所有作者

    from my_app import models

    books = models.Book.objects.filter(title=学不会的数学)[0]
    books = books.authors.all()
    for book in books:
        print(book.name)

反向查询

查看作者写的书

    from my_app import models

    authors = models.Author.objects.get(id=1)
    authors = authors.book_set.all()
    for author in authors:
        print(author.title)

基于下划线

正向查询

按字段

    from my_app import models

    authors = models.Book.objects.filter(title=学不会的数学).values(authors__name)
    for author in authors:
        print(author.get(authors__name))

反向查询

按表名

    from my_app import models

    authors = models.Author.objects.filter(book__title=学不会的数学).values(name)
    for author in authors:
        print(author.get(name))

多对多(手动)

当我们使用Django自带的ManyToManyField时,它会自动的创建第三张表。这里我们将手动创建

class Person(models.Model):
    name = models.CharField(max_length=64)
class Hobby(models.Model): title = models.CharField(max_length=64)
class PH_Key(models.Model): person = models.ForeignKey(Person,models.CASCADE) hobby = models.ForeignKey(Hobby,models.CASCADE) class Meta: unique_together = [person,hobby] # 保证值唯一
from my_app import models
    person = models.Person.objects
    hobby = models.Hobby.objects
    ph_key = models.PH_Key.objects
    ph_key.create(person=person.get(id=1),hobby=hobby.get(id=1))

当你再去创建一样的时,会报错。因为加了值唯一。

技术分享图片

不建议这么去用,还是用Django自带的吧。

聚合查询

语法

aggregate(*args,**kwargs)

是QuerySet中的一个方法。

使用

需要函数,一块联合用应。

算出下图的平均值,总和。

技术分享图片

from django.db.models import Avg,Sum
from my_app import models

# 使用默认键名
result = models.Person.objects.all().aggregate(Avg(age),Sum(age))

# 自定义键名
result = models.Person.objects.all().aggregate(avg=Avg(age),sum=Sum(age))

技术分享图片

更多函数

1.expression
    引用模型字段的一个字符串,或者一个query expression
2.output_field
    用来表示返回值的model field,一个可选的参数
3.extra
    关键字参数可以给聚合函数生成的SQL提供额外的信息
4.Avg
    返回给定表达式的平均值,它必须是数值,除非指定不同的output_field
5.Count
    返回与expression相关的对象的个数,有一个可选的参数distinct,如果distinct=True,那么Count将只计算唯一的实例,默认值是False
6.Max
    返回给定字段的最大值
7.Min
    返回给定字段的最小值
8.Sum
    返回给定字段的总和

分组查询

语法

annotate(*args,**kwargs)

也是QuerySet中的一个方法。

使用

当然,他也需要与函数联合使用。这可能是个糟糕的例子。

如下图:从名字相同中,找出最大年龄。

技术分享图片

from django.db.models import Max
from my_app import models

result = models.Person.objects.all().values(name).annotate(max=Max(age))

技术分享图片

小结

# values在annotate()之前,表示group by。之后,表示为取值

# filter在annotate()之前,表示过滤。之后,表示having

F查询

注意:只能对数值进行操作。

将上面的图,继续拿下来使用。

技术分享图片

现在我想将他们的年龄全部加2岁。

from django.db.models import F
from my_app import models

models.Person.objects.all().update(age=F(age)+2)

技术分享图片

Q查询

说明

# filter()等方法只能是‘AND‘运算。

# filter(id__ge=0,id__le=10) 即:1<id<9

# 如果需要执行复杂的查询,就需要使用Q对象

# 导入包:
from django.db.models import Q

# 操作符:
"&""|""~"

实例

依然是这样图表:

技术分享图片

1、查询 id=1 或 id=3 的人名。

from django.db.models import Q
from my_app import models

result = models.Person.objects.filter(Q(id=1)|Q(id=3)).values(name)

技术分享图片

 

2、人名为kidd,年龄大于20,的id。

from django.db.models import Q
from my_app import models

result = models.Person.objects.filter(Q(name=kidd),age__gt=20).values(id)

也可以这样

result = models.Person.objects.filter(Q(name=kidd) & Q(age__gt=20)).values(id)

技术分享图片

3、人名不为kidd,且年龄为20,其他所有人的人名。

from django.db.models import Q
from my_app import models

result = models.Person.objects.filter(~Q(name=kidd)&Q(age=20)).values(name)

技术分享图片

总结

在数据库中,其实没有一对一,多对多全都是模拟出来的,只有一个一对多也就是ForeignKey。

一对一:

在要限制的字段中,添加只能出现一次就好了,也就是Django中的 unique=Ture

多对多:

创建第三张表,将表进行ForeignKey。

Django 连表操作

原文:https://www.cnblogs.com/py-peng/p/12625214.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!