字典解包
在我们的开发过程中,会碰到这种场景:在查询的时候不明确查询的字段,如果上层传递或参数不为空,就需要将这个参数作为查询字段传入,在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
方法,所以在找不到的时候是会抛出DoesNotExist
和MultipleObjectsReturned
异常的,这里需要注意。文章源自灵鲨社区-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
评论