我如何获取一个 Django 对象并将其包装成一个只有一个项目的 QuerySet?
m: SomeModel = SomeModel.objects.get(pk=8)
但是,后面的函数期望 m 是一个 QuerySet(即使长度为 1)。
下面的答案适用于只需要包装特定模型的情况,但是有没有办法像下面的伪代码那样做一些事情?
def generic_model2qs(m: Model) -> "QuerySet[Model]":
return m.get_model().objects.filter(pk=m.pk)
Django 有类似 .get_model() 的函数吗?
请您参考如下方法:
执行此操作的一种方法类似于以下函数
def wrap_some_model(m: SomeModel) -> "QuerySet[SomeModel]":
return SomeModel.objects.filter(pk=m.pk)
但是,这不是一般情况,需要针对每个不同的模型重新实现。
来自 this answer for getting the model name from an unknown object 的提示的更通用的答案我已经为我自己的项目实现了:
def self_as_qs(s, model: Optional[models.Model] = None) -> "QuerySet[models.Model]":
"""
Takes the input and returns it wrapped in a QuerySet
:param s: the thing you want to transform
:param model: optional specification to stop errors when using potentially-heterogeneous (nested) Iterables
:return: A QuerySet representation of the input
"""
# since you can't create a generic empty QuerySet
generic_empty: QuerySet = model.objects.none() if model else SomeModel.objects.none()
if isinstance(s, QuerySet) and not model: # check inner QS if a model is specified
return s # it's already a QuerySet
if isinstance(s, Iterable):
# only works if all items are of the same model
n = generic_empty
for item in s:
n = n | self_as_qs(item, model) # handle nested lists
return n
if not s:
return generic_empty
if model and not isinstance(s, type(model.objects.all()[0])):
return generic_empty
# for future extensibility
m = type(s)
n = [s.pk]
return m.objects.filter(pk__in=n)
注意事项:
- 由于使用了
|运算符,在 Iterable(QuerySet、List、Tuple 等)上运行时不会保留顺序和嵌套结构 - 关于
generic_empty: QuerySet = model.objects.none() if model else SomeModel.objects.none()的行是为了确保您有一个空的 QuerySet 可以在程序需要时返回这样做。你需要to specify some model that you actually have here (但不必与其他任何地方相关),如 there doesn't seem to be any generic empty QuerySet generator .
