Django 連表操作


介紹

基本概括

  • 一對多: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')

查詢結果

有時候在多對多表中,常常會有重復的ID。

例如,老師跟班級之間的關系,老師可以交多個班級,班級可以有多個老師,當你在取數據時會出現一個老師出現多次的情況,為了避免這種情況可以簡單做一個字典操作。

obj = models.Teacher.objects.all().values("id","name","grade__caption","grade__id")
    obj_dic = {}
    for key in obj:
        nid = key["id"]
        if obj_dic.get(nid):
            obj_dic[nid]["grade_list"].append({"grade_id":key["grade__id"],"caption":key["grade__caption"]})
        else:
            obj_dic[nid] = {
                "nid":nid,
                "name":key["name"],
                "grade_list":[
                    {"grade_id":key["grade__id"],"caption":key["grade__caption"]}
                ]
            }

總結

在數據庫中,其實沒有一對一,多對多全都是模擬出來的,只有一個一對多也就是ForeignKey。

一對一:

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

多對多:

創建第三張表,將表進行ForeignKey。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM