• 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_djohelloworld>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'
    >>>
  • 相关阅读:
    Java基础知识强化94:Calendar类之Calendar概述和获取日历字段的方法
    Java基础知识强化93:算一下你来到这个世界多少天的案例
    Java基础知识强化92:日期工具类的编写和测试案例
    Java基础知识强化91:DateFormat类之DateFormat实现日期和字符串的相互转换
    Java基础知识强化90:Date类之Data类中日期和毫秒相互转换
    Java基础知识强化89:Date类之Data类概述及其方法
    Java基础知识强化88:BigDecimal类之BigDecimal类引入和概述 以及 BigDecimal的使用(加减乘除)
    Java基础知识强化87:BigInteger类之BigInteger加减乘除法的使用
    Java基础知识强化86:BigInteger类之BigInteger概述和构造方法
    Java基础知识强化85:System类之arraycopy()方法(数组拷贝)
  • 原文地址:https://www.cnblogs.com/mashuqi/p/11022063.html
Copyright © 2020-2023  润新知