IT TIP

자식 클래스의 이름을 모르고 django에서 개체의 자식 클래스에 액세스하려면 어떻게해야합니까?

itqueen 2020. 10. 14. 21:30
반응형

자식 클래스의 이름을 모르고 django에서 개체의 자식 클래스에 액세스하려면 어떻게해야합니까?


Django에서 부모 클래스와 그로부터 상속되는 여러 자식 클래스가있을 때 일반적으로 parentclass.childclass1_set 또는 parentclass.childclass2_set을 통해 자식에 액세스하지만 원하는 특정 자식 클래스의 이름을 모르는 경우 어떻게해야합니까?

자식 클래스 이름을 몰라도 부모-> 자식 방향으로 관련 개체를 가져 오는 방법이 있습니까?


( 업데이트 : 따라서 상속 계층 구조 아래로 역 OneToOneField 관계를 통해 쿼리를 select_related (및 따를 수 있습니다 장고 1.2 및 최신)의 경우, 추가 요구하지 않는 사용할 수있는 더 좋은 방법이 있어요 real_type상위 모델에 필드를 그것으로 사용할 수 있습니다. InheritanceManagerdjango-model-utils 프로젝트.)

이를 수행하는 일반적인 방법은 적절한 "리프"클래스의 컨텐츠 유형을 저장하는 Parent 모델의 ContentType에 ForeignKey를 추가하는 것입니다. 이것이 없으면 상속 트리의 크기에 따라 인스턴스를 찾기 위해 자식 테이블에서 많은 쿼리를 수행해야 할 수 있습니다. 한 프로젝트에서 수행 한 방법은 다음과 같습니다.

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를 특정 상속 계층 구조의 부모 클래스에 직접 넣을 수도 있습니다.

이 솔루션은 상위 모델을 수정할 수없는 경우 작동하지 않습니다. 이 경우 모든 하위 클래스를 수동으로 확인하는 데 거의 어려움이 있습니다.


Python에서 ( "new-style") 클래스 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)]

_meta의 함수를 사용하는데, 이는 장고가 발전함에 따라 안정적이라고 보장 할 수 없지만 트릭을 수행하며 필요에 따라 즉석에서 사용할 수 있습니다.


내가 정말로 필요했던 것은 다음과 같다.

콘텐츠 유형 및 상속 인식 관리자를 사용한 모델 상속

그것은 나를 위해 완벽하게 작동했습니다. 그래도 다른 모든 사람들에게 감사합니다. 나는 당신의 답변을 읽고 많은 것을 배웠습니다!


You can use django-polymorphic for that.

It allows to automatically cast derived classes back to their actual type. It also provides Django admin support, more efficient SQL query handling, and proxy model, inlines and formset support.

The basic principle seems to be reinvented many times (including Wagtail's .specific, or the examples outlined in this post). It takes more effort however, to make sure it doesn't result in an N-query issue, or integrate nicely with the admin, formsets/inlines or third party apps.


Here's my solution, again it uses _meta so isn't guaranteed to be stable.

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

You can achieve this looking for all the fields in the parent that are an instance of django.db.models.fields.related.RelatedManager. From your example it seems that the child classes you are talking about are not subclasses. Right?


An alternative approach using proxies can be found in this blog post. Like the other solutions, it has its benefits and liabilities, which are very well put in the end of the post.

참고URL : https://stackoverflow.com/questions/929029/how-do-i-access-the-child-classes-of-an-object-in-django-without-knowing-the-nam

반응형