Python进阶技巧二三事(六):字典解包与外键

零 Python教程评论63字数 4764阅读15分52秒阅读模式

Python进阶技巧二三事(六):字典解包与外键

字典解包

在我们的开发过程中,会碰到这种场景:在查询的时候不明确查询的字段,如果上层传递或参数不为空,就需要将这个参数作为查询字段传入,在Go这种静态语言中通常是通过拼接sql,或者动态修改orm的查询参数来实现这个功能的;而Python这种动态语言自带了一种解决方法,那就是kwargs查询,也被称作字典解包。

ini

代码解读
复制代码
from django.db import models

# Product 模型
class Product(models.Model):
    name = models.CharField(max_length=255)
    version = models.CharField(max_length=255)
    category_id = models.IntegerField(null=True, blank=True)
    is_active = models.BooleanField(default=True)
    environment = models.CharField(max_length=50, default='production')
    checksum = models.CharField(max_length=255, null=True, blank=True)


def get_product(
        name,  # type: str
        version,  # type: str
        category_id=None,  # type: Union[None, int]
        is_active=None,  # type: bool
        environment='production',  # type: str
        checksum=None,  # type: str
):
    # 创建一个包含必需字段的字典
    query_dict = {
        'name': name,
        'version': version,
        'environment': environment,
    }

    # 根据可选参数的值来添加到字典中
    if category_id is not None:
        query_dict['category_id'] = category_id
    if is_active is not None:
        query_dict['is_active'] = is_active
    if checksum is not None:
        query_dict['checksum'] = checksum


    try:
        // 注意这里的语法需要带上**符号
        product_instance = Product.objects.get(**query_dict)
        return product_instance
    except Product.DoesNotExist:
        return None


# Example
product = get_product(
    name='example_product',
    version='1.0.0',
    category_id=123,
    is_active=True,
    checksum='abc123'
)

if product:
    print(f"Found product: {product}")
else:
    print("Product not found")

字段解包查询本质上就是一个灵活的、多字段的get查询,能将字段中的键值对作为关键字的参数传递给get方法,所以在找不到的时候是会抛出DoesNotExistMultipleObjectsReturned异常的,这里需要注意。文章源自灵鲨社区-https://www.0s52.com/bcjc/pythonjc/17417.html

Django外键

外键是什么

外键其实就是用于进行两张表之间建立关联的一种方式,它能够使一张表的某个字段对应着另一张表的主键,这样我们就能实现文章源自灵鲨社区-https://www.0s52.com/bcjc/pythonjc/17417.html

  • 多表之间数据的一致性和完整性:如果一张表的字段被其他表引用,那么这张表的记录是不能被删除的,除非同时进行引用方的删除
  • 实现关系查询:可以同时查询、操作两个表或者多个表的记录

外键的替代方案

外键也有很多缺点,最为之诟病的就是以下两点文章源自灵鲨社区-https://www.0s52.com/bcjc/pythonjc/17417.html

  • 灵活性受损:限制了对数据库的修改,必须先删引用记录才能删本记录
  • 性能变慢:数据库需要维护、查询多表,当数据量大的时候会拖慢速度

虽然阿里巴巴开发手册中不推荐使用外键,但其实也没有什么更好的办法来替代外键的功能,一般来说不使用外键只能通过以下几种方式来作为某种替代,实现表之间关联的能力。文章源自灵鲨社区-https://www.0s52.com/bcjc/pythonjc/17417.html

  • 使用关联表:通过单独的一张表进行不同表之间关系的记录
  • 表字段冗余:只要包含了外键表所需的字段,自然是不用再通过外键进行关联了,但是这会让表变得更大、更复杂
  • 应用层面实现关系,比如在插入、修改某些数据时,先进行外键表的查询,确保不会影响到数据。这是最优雅的实现,但是会增加开发人员的编码压力,并且如果逻辑出错了可能就会导致数据乱掉

在实际开发中,但凡上点规模表比较多的项目都不可避免的会涉及到外键。文章源自灵鲨社区-https://www.0s52.com/bcjc/pythonjc/17417.html

下面是一个外键例子文章源自灵鲨社区-https://www.0s52.com/bcjc/pythonjc/17417.html

ini

代码解读
复制代码
from django.db import models

// 图书馆模型
class Library(models.Model):
    name = models.CharField(max_length=100, verbose_name='图书馆名称')
    address = models.CharField(max_length=200, verbose_name='地址')

    def __str__(self):
        return self.name

// 作者模型
class Author(models.Model):
    name = models.CharField(max_length=100, verbose_name='作者姓名')
    bio = models.TextField(null=True, blank=True, verbose_name='作者简介')

    def __str__(self):
        return self.name

// 书籍模型 有图书馆和作者两个外键
class Book(models.Model):
    title = models.CharField(max_length=200, verbose_name='书名')
    author = models.ForeignKey(
        Author, related_name='books', on_delete=models.CASCADE, verbose_name='作者')
    library = models.ForeignKey(
        Library, related_name='books', on_delete=models.CASCADE, verbose_name='所属图书馆')
    published_date = models.DateField(verbose_name='出版日期')

    def __str__(self):
        return self.title


// 借阅人
class Borrower(models.Model):
    name = models.CharField(max_length=100, verbose_name='借书人姓名')
    email = models.EmailField(verbose_name='电子邮件')

    def __str__(self):
        return self.name

// 借阅记录 有借阅人和书这两个外键
class BorrowRecord(models.Model):
    book = models.ForeignKey(
        Book, related_name='borrow_records', on_delete=models.CASCADE, verbose_name='借阅书籍')
    borrower = models.ForeignKey(
        Borrower, related_name='borrow_records', on_delete=models.CASCADE, verbose_name='借书人')
    borrow_date = models.DateField(verbose_name='借书日期')
    return_date = models.DateField(null=True, blank=True, verbose_name='还书日期')

    def __str__(self):
        return f'{self.book.title} borrowed by {self.borrower.name}'
  • ForeignKey:用于指定外键,比如上述的模型中书籍就有图书馆和作者两个外键
  • related_name:用于指定反向查询使用的名字
  • on_delete:定义关联对象被删除时,所有关联对象的操作
  • verbose_name:管理界面的显示名

on_delete常见的选项包括文章源自灵鲨社区-https://www.0s52.com/bcjc/pythonjc/17417.html

  • CASCADE:删除关联对象的时候,自动删除此对象,也就是级联删除
  • PROTECT:组织删除关联对象,也是外键的默认模式,必须要双删
  • SET_NULL:删除时将外键字段设置为NULL
  • SET_DEFAULT:删除时将外键字段设置一个默认值
  • DO_NOTHING:不做任何处理

查询外键

ini

代码解读
复制代码
//1.通过特定的借阅记录查到书籍和借阅人

borrow_record = BorrowRecord.objects.get(id=1)
book = borrow_record.book
borrower = borrow_record.borrower
print(book.title)  # 输出: Harry Potter and the Philosopher's Stone
print(borrower.name)  # 输出: John Doe

//2.通过特定的书籍查到图书馆和作者
book = Book.objects.get(title='xxx')
author = book.author
library = book.library
print(author.name)  # 输出: J.K. Rowling
print(library.name)  # 输出: Central Library

//3.带外键字段条件的正向查询
borrow_records = BorrowRecord.objects.filter(
    borrower_name='Alice',
    book__title='Harry Potter and the Philosopher's Stone'
) //这里使用外键字段要使用双下划线

for record in borrow_records:
    print(record)

ini

代码解读
复制代码
//1. 通过author查到所有的书,因为这里的related_name=’books‘

author = Author.objects.get(name='J.K. Rowling')
books = author.books.all()
for book in books:
    print(book.title)
# 输出:
# Harry Potter and the Philosopher's Stone
# Harry Potter and the Chamber of Secrets

//2. 同理,通过图书馆查到图书
library = Library.objects.get(name='Central Library')
books = library.books.all()
for book in books:
    print(book.title)
# 输出:
# Harry Potter and the Philosopher's Stone
# Harry Potter and the Chamber of Secrets

//3.带条件的反向查询
author = Author.objects.get(name='J.K. Rowling')
books = author.books.filter(published_date__gt='1998-01-01')
for book in books:
    print(book.title)
# 输出:
# Harry Potter and the Chamber of Secrets
文章源自灵鲨社区-https://www.0s52.com/bcjc/pythonjc/17417.html文章源自灵鲨社区-https://www.0s52.com/bcjc/pythonjc/17417.html

零
  • 转载请务必保留本文链接:https://www.0s52.com/bcjc/pythonjc/17417.html
    本社区资源仅供用于学习和交流,请勿用于商业用途
    未经允许不得进行转载/复制/分享

发表评论