python測試開發django-37.外鍵(ForeignKey)查詢


前言

前面在admin后台頁面通過設置外鍵,可以選擇下拉框的選項,本篇主要講解關於外鍵(ForeignKey)的查詢

models設計

在上一篇的基礎上新增一個BankName表,Card表通過外鍵關聯到BankName

class BankName(models.Model):
    '''銀行信息'''
    bank_name = models.CharField(max_length=50, verbose_name="銀行名稱", default="")
    city = models.CharField(max_length=30, verbose_name="城市", default="")
    point = models.CharField(max_length=60, verbose_name="網點", default="")

    class Meta:
        verbose_name = '銀行'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.bank_name

class Card(models.Model):
    '''銀行卡 基本信息'''
    card_id = models.CharField(max_length=30, verbose_name="卡號", default="")
    card_user = models.CharField(max_length=10, verbose_name="姓名", default="")
    add_time = models.DateField(auto_now=True, verbose_name="添加時間")
    bank_info = models.ForeignKey(BankName, on_delete=models.CASCADE, default="")

    class Meta:
        verbose_name = "銀行卡賬戶_基本信息"
        verbose_name_plural = '銀行卡賬戶'

    def __str__(self):
        return self.card_id


class CardDetail(models.Model):
    '''銀行卡詳情信息'''
    card = models.OneToOneField(Card,
                               on_delete=models.CASCADE,
                               verbose_name="卡號"
                                )
    tel = models.CharField(max_length=30, verbose_name="電話", default="")
    mail = models.CharField(max_length=30, verbose_name="郵箱", default="")
    city = models.CharField(max_length=10, verbose_name="城市", default="")
    address = models.CharField(max_length=30, verbose_name="詳細地址", default="")

    class Meta:
        verbose_name = "賬戶_個人資料"
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.card.card_user

之后執行 makemigrations 和migrate,同步數據

python manage.py makemigrations
python manage.py migrate

shell模式新增測試

為了調試方便,可以使用django的shell模式,對表的數據增刪改查操作,打開cmd,cd到manage.py目錄

python manage.py shell

先新增數據測試數據

D:\web_djo\helloworld>python manage.py shell

>>> from hello.models import Card, BankName
>>> a = BankName.objects.create(bank_name='上海銀行', city='上海', point='徐家匯區')
>>> a.save
>>> c = Card.objects.create(card_id='62270121022100000', card_user='張三', bank_info=a)
>>> c.save

正向查詢

根據Card表的card_id,去查詢關聯的對應的BankName相關信息,這個相對來說簡單一點

>>> from hello.models import BankName, Card
>>> cardxx=Card.objects.get(card_id='62270121022100000')
>>> cardxx.card_user
'張三'

>>> cardxx.bank_info
<BankName: 上海銀行>

>>> cardxx.bank_info.bank_name
'上海銀行'
>>> cardxx.bank_info.city
'上海'
>>>

反向查詢_set

如果想通過銀行名稱“上海銀行”,查詢到此銀行關聯多少張卡,並且查詢其中一個銀行卡的信息。
反向查詢,當ForeignKey沒設置related_name參數,默認是通過關聯表的名稱加_set去查詢

  • 查詢結果是QuerySet集合對象
  • count()函數統計查詢個數
  • [0].card_id 下標取值,獲取對應屬性
>>> bank = BankName.objects.get(bank_name='上海銀行')
>>> bank.city
'上海'

# 反向查詢,表名稱_set
>>> bank.card_set.all()
<QuerySet [<Card: 62270121022100000>]>

# count()函數統計
>>> bank.card_set.all().count()
1

>>> bank.card_set.all()[0].card_id
'62270121022100000'
>>>

related_name

當Card表的外鍵(ForeignKey)只有一個時,可以通過_set去查詢到,當有多個外鍵時,就無法查詢具體哪個外鍵了,這時候就需要加個related_name參數。

class CardGrade(models.Model):
    '''會員等級'''
    nub = models.CharField(max_length=50, verbose_name="會員等級", default="")

    class Meta:
        verbose_name = '會員等級'
        verbose_name_plural = verbose_name


class BankName(models.Model):
    '''銀行信息'''
    bank_name = models.CharField(max_length=50, verbose_name="銀行名稱", default="")
    city = models.CharField(max_length=30, verbose_name="城市", default="")
    point = models.CharField(max_length=60, verbose_name="網點", default="")

    class Meta:
        verbose_name = '銀行'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.bank_name

class Card(models.Model):
    '''銀行卡 基本信息'''
    card_id = models.CharField(max_length=30, verbose_name="卡號", default="")
    card_user = models.CharField(max_length=10, verbose_name="姓名", default="")
    add_time = models.DateField(auto_now=True, verbose_name="添加時間")
    bank_info = models.ForeignKey(BankName, related_name='card_bank', on_delete=models.CASCADE, default="")
    grade = models.ForeignKey(CardGrade, related_name='card_grade',  on_delete=models.CASCADE, default="")

    class Meta:
        verbose_name = "銀行卡賬戶_基本信息"
        verbose_name_plural = '銀行卡賬戶'

    def __str__(self):
        return self.card_id

related_name參數相當於給這個外鍵取了個別名,方便多個外鍵時候去識別。以下是新增數據和正向查詢
當定義了related_name后”_set”這類查詢就被related_name代替了,所以用”_set”會報錯。

# 新增數據
>>> from hello.models import CardGrade,BankName,Card
>>> n=CardGrade.objects.create(nub='黃金會員')
>>> b=BankName.objects.create(bank_name='北京銀行',city='北京')
>>> c=Card.objects.create(card_id='666555000111',card_user='楊過', bank_info=b,
grade=n)

# 正向查詢
>>> c.grade.nub
'黃金會員'

>>> c.bank_info.city
'北京'
>>>

反向查詢需要用到related_name參數,如下

# CardGrade表查Card表
>>> nnn=CardGrade.objects.get(nub='黃金會員')
>>> nnn.card_grade.all()
<QuerySet [<Card: 666555000111>]>
>>> nnn.card_grade.all()[0].card_id
'666555000111'

# BankName表查Card表
>>> bbb=BankName.objects.get(bank_name='上海銀行')
>>> bbb.card_bank.all()
<QuerySet [<Card: 62270121022100000>]>
>>> bbb.card_bank.all()[0].card_id
'62270121022100000'
>>>


免責聲明!

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



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