아동 수업의 이름을 알지 못하고 Django의 객체의 어린이 클래스에 어떻게 액세스합니까?
-
06-09-2019 - |
문제
Django에서는 부모 수업과 여러 자식 수업이있을 때 일반적으로 ParentClass.childclass1_set 또는 parentclass.childclass2_set을 통해 자식에 액세스 할 수 있지만 원하는 특정 자식 클래스의 이름을 모르는 경우 어떻게해야합니까?
아동 수업 이름을 모르고 부모-> 아동 방향으로 관련 개체를 얻는 방법이 있습니까?
해결책
(업데이트: Django 1.2 및 Newer의 경우 Reverse OnetoOnefield 관계 (따라서 상속 계층 구조)를 통해 select_related queries를 따를 수있는 새로운 경우 추가를 필요로하지 않는 더 나은 기술이 있습니다. real_type
부모 모델의 필드. 사용할 수 있습니다 상속 공장 에서 Django-Model-utils 프로젝트.)
이를 수행하는 일반적인 방법은 적절한 "리프"클래스의 콘텐츠 유형을 저장하는 상위 모델의 ContentType에 외국 키를 추가하는 것입니다. 이 없으면 상속 트리가 얼마나 큰지에 따라 인스턴스를 찾기 위해 자식 테이블에서 많은 쿼리를 수행해야 할 수도 있습니다. 한 프로젝트에서 수행 한 방법은 다음과 같습니다.
from django.contrib.contenttypes.models import ContentType
from django.db import models
class InheritanceCastModel(models.Model):
"""
An abstract base class that provides a ``real_type`` FK to ContentType.
For use in trees of inherited models, to be able to downcast
parent instances to their child types.
"""
real_type = models.ForeignKey(ContentType, editable=False)
def save(self, *args, **kwargs):
if not self._state.adding:
self.real_type = self._get_real_type()
super(InheritanceCastModel, self).save(*args, **kwargs)
def _get_real_type(self):
return ContentType.objects.get_for_model(type(self))
def cast(self):
return self.real_type.get_object_for_this_type(pk=self.pk)
class Meta:
abstract = True
이것은 재사용 가능하게하기 위해 추상적 인 기본 클래스로 구현됩니다. 이러한 방법과 FK를 특정 상속 계층에서 부모 클래스에 직접 넣을 수도 있습니다.
부모 모델을 수정할 수없는 경우이 솔루션은 작동하지 않습니다. 이 경우 모든 서브 클래스를 수동으로 확인하는 데 거의 고정되어 있습니다.
다른 팁
파이썬에서 ( "새로운 스타일") 클래스 X가 주어지면 (직접) 하위 클래스를 얻을 수 있습니다. X.__subclasses__()
, 클래스 객체 목록을 반환합니다. ( "더 많은 자손"을 원한다면, 당신은 또한 __subclasses__
파이썬에서 효과적으로 수행하는 방법에 대한 도움이 필요한 경우 직접 서브 클래스 등 각각에서 문의하십시오!).
일단 당신이 어떻게 든 아동의 관심을 식별 한 후에 (아마도 모든 아동 서브 클래스의 사례 등을 원한다면) getattr(parentclass,'%s_set' % childclass.__name__)
도움이 필요합니다 (아동 계급의 이름이 'foo'
, 이것은 액세스와 같습니다 parentclass.foo_set
-- 그 이상도 이하도 아닌). 다시 말하지만, 설명이나 예제가 필요하면 문의하십시오!
Carl의 솔루션은 좋은 것입니다. 여기에 여러 관련 아동 수업이있는 경우 수동으로 수행하는 한 가지 방법이 있습니다.
def get_children(self):
rel_objs = self._meta.get_all_related_objects()
return [getattr(self, x.get_accessor_name()) for x in rel_objs if x.model != type(self)]
Django가 진화함에 따라 안정적으로 보장되지는 않지만 _Meta에서 함수를 사용하지만 트릭을 수행하고 필요한 경우 날짜에 사용할 수 있습니다.
내가 정말로 필요로하는 것은 다음과 같습니다.
그것은 나를 위해 완벽하게 작동했습니다. 그래도 다른 모든 분들께 감사드립니다. 나는 당신의 대답을 읽는 것만으로 많이 배웠습니다!
당신이 사용할 수있는 Django- 폴리 모어 그에 대한.
파생 클래스를 실제 유형으로 자동으로 캐스트 할 수 있습니다. 또한 Django 관리자 지원,보다 효율적인 SQL 쿼리 처리 및 프록시 모델, 인라인 및 Formset 지원을 제공합니다.
기본 원칙은 여러 번 재창조되는 것 같습니다 (Wagtail 's 포함 .specific
, 이 게시물에 요약 된 예제). 그러나 N- 쿼리 문제가 발생하지 않도록하거나 관리자, 양식 세트/인라인 또는 타사 앱과 잘 통합하려면 더 많은 노력이 필요합니다.
여기 내 솔루션이 있습니다. 다시 사용합니다 _meta
따라서 안정적으로 보장되지 않습니다.
class Animal(models.model):
name = models.CharField()
number_legs = models.IntegerField()
...
def get_child_animal(self):
child_animal = None
for r in self._meta.get_all_related_objects():
if r.field.name == 'animal_ptr':
child_animal = getattr(self, r.get_accessor_name())
if not child_animal:
raise Exception("No subclass, you shouldn't create Animals directly")
return child_animal
class Dog(Animal):
...
for a in Animal.objects.all():
a.get_child_animal() # returns the dog (or whatever) instance
django.db.models.fields.related.relatedmanager의 인스턴스 인 부모의 모든 필드를 찾을 수 있습니다. 당신의 예에서 당신이 말하는 어린이 수업은 서브 클래스가 아닌 것 같습니다. 오른쪽?
프록시를 사용한 대체 접근법을 찾을 수 있습니다 이 블로그 게시물. 다른 솔루션과 마찬가지로, 그것은 그 이점과 부채가 있으며, 이는 게시물의 끝에 매우 잘 적용됩니다.