我想知道哪些模型是模型的子模型,以便检索它们的on_delete
属性。如我所知,如下图所示,如果ownerModel
是childModel1
和check1Model
的母体:
import uuid
from django.db import models
class ownerModel(models.Model):
ownerId = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True, editable=False, blank=True)
class check1Model(models.Model):
checkId = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True, editable=False, blank=True)
owner=models.ForeignKey(ownerModel,on_delete=models.CASCADE)
class childModel1(models.Model):
childId = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True, editable=False, blank=True)
check2=models.ForeignKey(ownerModel,on_delete=models.CASCADE)
然后我们可以得到ownerModel
的子模型,代码如下:
class myView(views.APIView):
def get(self, request, format=None):
for f in ownerModel._meta.get_fields():
if 'field' in f.__dict__.keys():
print('***childModels***')
print(f.__dict__)
print()
return Response({'0000'}, status=status.HTTP_200_OK)
我的意思是在ownerModel._meta.get_fields()
的项中检查field
键是否在__dict__.keys()
中。
当然,这里我们得到了关于子模型的扩展信息:
***childModels***
{'field': <django.db.models.fields.related.ForeignKey: owner>, 'model': <class 'Users.models.ownerModel'>, 'related_name': None, 'related_query_name': None, 'limit_choices_to': {}, 'parent_link': False, 'on_delete': <function
CASCADE at 0x00000286550848B0>, 'symmetrical': False, 'multiple': True, 'field_name': 'ownerId', 'related_model': <class 'Users.models.check1Model'>, 'hidden': False}
***childModels***
{'field': <django.db.models.fields.related.ForeignKey: check2>, 'model': <class 'Users.models.ownerModel'>, 'related_name': None, 'related_query_name': None, 'limit_choices_to': {}, 'parent_link': False, 'on_delete': <function CASCADE at 0x00000286550848B0>, 'symmetrical': False, 'multiple': True, 'field_name': 'ownerId', 'related_model': <class 'Users.models.childModel1'>, 'hidden': False}
所以我发现这两个条件是获得子模型信息所必需的:
- 在子模型中,确保使用如下行设置子关系:
models.ForeignKey(ownerModel,on_delete=models.CASCADE)
- 如前所述,如果
field
键在ownerModel._meta.get_fields()
项的__dict__.keys()
中;获取儿童信息。
但问题是,在某些情况下,我不能从父模型获得子信息。所以:
- 这让我想知道这两个条件是否足以找出哪些模型是模型的孩子?
- 是否有其他类似的方法来获得哪些模型是模型的孩子?
顺便说一下,我也想有on_delete
,并且有on_delete
是我使用_meta.get_fields()
超过_meta.fields
的唯一原因,因为_meta.fields
不提供on_delete
属性。
这是我的代码,如果你想看一下。注意,在完整的回答中,我也想知道是什么造成了问题。因此,在这种情况下,__dict__.keys()
不提供键中没有field
的项(不提供子模型细节)。因为通常这两个条件提供了子模型的细节。所以以后我可以在所有代码中获得子模型的详细信息。
问题是,即使有for f in ownerModel._meta.get_fields(include_hidden=True)
,没有任何进一步的if
s不检索行包括on_delete
属性在这个项目。但在其他项目中,ownerModel._meta.get_fields()
提供了它们。我不知道ownerModel._meta.get_fields()
有时提供这些关系信息,有时不提供的原因。
您可以使用Model._meta.related_objects
查找模型的子节点
# Example Code
from django.utils.functional import classproperty
from django.db import models
class SomeModel(models.Model):
class Meta:
abstract = True
@classproperty
def related_objects(cls):
"""
Return list of related models within the same module
ManyToManyRel not supported
"""
related_objects = [
rel
for rel in cls._meta.related_objects
if isinstance(rel, (models.ManyToOneRel, models.OneToOneRel))
]
return [
(rel.related_model, rel.on_delete)
for rel in related_objects
if rel.related_model._meta.app_label == cls._meta.app_label
]
你可以使用这个类作为你的模型的mro
。
更新
在评论中进一步调查后,发现问题是模型没有在models
子模块中定义。如Django文档中所述:
一旦你定义了你的模型,你需要告诉Django你将要使用这些模型。为此,编辑您的设置文件并更改INSTALLED_APPS设置,以添加包含models.py的模块名称。.
这个要求也可以在Django处理模型检测的源代码中得到确认:
MODELS_MODULE_NAME = "models"
class AppConfig:
...
def import_models(self):
# Dictionary of models for this app, primarily maintained in the
# 'all_models' attribute of the Apps this AppConfig is attached to.
self.models = self.apps.all_models[self.label]
if module_has_submodule(self.module, MODELS_MODULE_NAME):
models_module_name = "%s.%s" % (self.name, MODELS_MODULE_NAME)
self.models_module = import_module(models_module_name)
原始回答
没有明显的理由为什么使用__dict__
不能工作。然而,__dict__
并不是真正用于这种用法的。这是不可靠的,没有理由在hasattr()
上使用它。
以下是__dict__
可能出错的几个例子:
In [1]: class A:
...: def __init__(self):
...: self.foo = 'foobaz'
...: self.bar = 'barbaz'
...:
In [2]: a = A()
In [3]: a.__dict__
Out[3]: {'foo': 'foobaz', 'bar': 'barbaz'}
In [4]: class B(A):
...: @property
...: def bar(self):
...: return 'barfoo'
...: @bar.setter
...: def bar(self, value):
...: pass
...:
In [5]: b = B()
In [6]: b.__dict__
Out[6]: {'foo': 'foobaz'}
# B redefined 'bar' as a property, which removed it from __dict__
In [7]: 'bar' in b.__dict__
Out[7]: False
In [8]: hasattr(b, 'bar')
Out[8]: True
In [9]: class C(A):
...: __slots__ = ('foo', 'bar')
...:
In [10]: c = C()
In [11]: c.foo
Out[11]: 'foobaz'
In [12]: c.bar
Out[12]: 'barbaz'
In [13]: c.__dict__
Out[13]: {}
# C defined 'foo' and 'bar' as slots, which removed them from __dict__
In [14]: hasattr(c, 'foo')
Out[14]: True
你可以使用hasattr()
:
for f in ownerModel._meta.get_fields():
if hasattr(f, 'field'):
print(f, f.on_delete)
print()
然而,检查field
属性的存在似乎并不是确定字段是否为向后关系的可靠解决方案。我宁愿推荐依赖one_to_one
和one_to_many
属性,它们是非关系字段的None
,关系字段的True/False
:
for f in ownerModel._meta.get_fields():
if (f.one_to_one or f.one_to_many) and hasattr(f, 'on_delete'):
print(f, f.on_delete)
print()
我还在条件中包含了hasattr(f, 'on_delete')
,以排除ownerModel
中定义的OneToOneField
关系。不过,测试isinstance(f, ForeignObjectRel)
可能更简洁:
from django.db.models import ForeignObjectRel
for f in ownerModel._meta.get_fields():
if isinstance(f, ForeignObjectRel) and (f.one_to_one or f.one_to_many):
print(f, f.on_delete)
print()
如果您想检索到这个模型的反向关系,您可以使用ownerModel._meta.related_objects
。然而,这是Django私有API的一部分,没有官方文档/支持。您还可以在源代码中找到文档。
返回所有指向当前模型的相关对象。相关对象可以来自一对一、一对多或多对多的字段关系类型。
私有API,仅供Django自己使用;
get_fields()
结合字段属性过滤是获取该字段列表的公共API。
您也可以通过过滤get_fields()
:
related_objects = [
f for f in ownerModel._meta.get_fields(include_hidden=True)
if (not f.hidden and (f.one_to_one or f.one_to_many)) or f.many_to_many
]
此解决方案还为您提供了在ownerModel
中定义的多对多关系,如果您想要多对多,这可能是预期的。要排除所有的多对多关系,只需从条件中删除它们:
related_objects = [
f for f in ownerModel._meta.get_fields(include_hidden=True)
if not f.hidden and (f.one_to_one or f.one_to_many)
]
一种严格地只得到反向关系的方法(即。删除ownerModel
中定义的多对多和一对一关系),可能是为了测试ForeignObjectRel
在字段层次结构中的存在。
from django.db.models import ForeignObjectRel
related_objects = [
f for f in ownerModel._meta.get_fields(include_hidden=True)
if isinstance(f, ForeignObjectRel) and (not f.hidden or f.many_to_many)
]
如果您想要显示on_delete
属性的值,您可以将结果限制为一对一和一对多字段。
from django.db.models import ForeignObjectRel
related_objects = [
f for f in ownerModel._meta.get_fields()
if isinstance(f, ForeignObjectRel)
and (f.one_to_one or f.one_to_many)
]
for f in related_objects:
print(f, f.on_delete)