2011-11-30 2 views
0

데이터베이스에 목차 구조를 유지하려고합니다. 간단한 예 :Django - 다중 테이블 상속성 쿼리의 유형 확인

models.py

class Section (models.Model): 
    title = models.CharField(max_length=80) 
    order = models.IntegerField() 

class SectionClickable(Section): 
    link = models.CharField(max_length=80) 

class SectionHeading(Section): 
    background_color = models.CharField(max_length=6) 

views.py

나는 그것이 (장고 설명서와 같은) SectionHeading 예,하지만 경우 일부 처리 작업을 할 필요가
sections = Section.objects.filter(title="Hello!") 
for section in sections: 
     if(section.sectionheading): 
      logger.debug("It's a heading") 

에 액세스 객체가 SectionHeading 유형이 아닌 경우 section.sectionheading은 DoesNotExist 오류를 발생시킵니다.

저는 이런 종류의 문제에 대한 대안을 조사해 왔으며 contenttypes 패키지의 일반 외래 키를 사용하지 않습니다. 그러나 이것은 장고 관리자 측면에서 더욱 두통을 일으킬 것 같습니다. 위의 솔루션보다 나은 솔루션에 대해 조언 해 줄 수 있습니까?

편집 : order 필드 때문에 추상 상속을 피했습니다. 난 당신이 유형 확인할 수 있습니다 함께 두 개의 검색어 세트에 가입하기 위해 잘

+0

'Section'과'SectionHeading'을 어떻게 관련 지으시겠습니까? – second

+0

SectionHeading은 섹션 – bcoughlan

+0

아의 서브 클래스입니다. 아, 죄송합니다. 통지하지 않았습니다. – second

답변

2

별로 정렬 할 것이다 :

if isinstance(section, SectionHeading) 

하지만 duck typing은 일반적으로 선호를

편집 : 실제로

아마도 작동하지 않을 것입니다. 개체는 Section이됩니다.

if hasattr(section, 'sectionheading') 

또는

try: 
    do_something_with(section.sectionheading) 
except AttributeError: 
    pass # i guess it wasn't one of those 
0
내가 second 그의 편집에 제안 것과 유사한 것을 사용하고

: : 이제

class SomeBaseModel(models.Model): 
    reverse_name_cache = models.CharField(_('relation cache'), max_length=10, 
              null=True, editable=False) 

    def get_reverse_instance(self): 
     try: 
      return getattr(self, self.reverse_name_cache) 
     except AttributeError: 
      for name in ['sectionclickable', 'sectionheading']: 
       try: 
        i = getattr(self, name) 
        self.reverse_name_cache = name 
        return i 
       except ObjectDoesNotExist: 
        pass 

을,이 ISN '하지만 당신은 속성도 찾아보실 수 있습니다 정확히 예쁘지 만 중앙 위치에서 서브 클래스 인스턴스를 반환하므로 try으로 다른 명령문을 래핑 할 필요가 없습니다. 아마도 하위 클래스 리버스 관리자 이름의 하드 코딩은 피할 수 있지만이 접근 방식은 내 필요에 충분했다.

1

내가 사용하여 온 솔루션은 (오히려 유용)를 가리키는 추가 필드 ContentType 클래스 참여 :

class Section(models.Model): 
    name = models.CharField(max_length=50) 
    content_type = models.ForeignKey(ContentType,editable=False,null=True) 

    def __unicode__(self): 
     try: 
      return self.as_leaf_class().__unicode__() 
     except: 
      return self.name 

    def save(self, *args, **kwargs): 
     if(not self.content_type): 
      self.content_type = ContentType.objects.get_for_model(self.__class__) 
     super(Section, self).save(*args, **kwargs) 

    def as_leaf_class(self): 
     content_type = self.content_type 
     model = content_type.model_class() 
     if(model == Section): 
      return self 
     return model.objects.get(id=self.id) 

당신이 "기본"을 통과하는 경우 객체가 생각이 솔루션은 꽤 좋은 및 함께 일하기 쉽다.

0

여기 OP.

second의 질문에 대한 대답은 정확하지만이 시나리오에서는 다중 테이블 상속이 비효율적이라고 생각합니다. 하위 클래스 모델의 속성에 액세스하면 쿼리가 발생하므로 반환 된 모든 행에 대한 쿼리가 필요합니다. 아야. 내가 알 수있는 한, select_related은 다중 테이블 상속을 위해 아직 작동하지 않습니다.

나는 ContentType을 우아하게 처리하지 못했고 많은 쿼리를 필요로하기 때문에 ContentType을 배제했다. 마지막으로 나는에 템플릿 태그를 만든

section_clickables = SectionClickable.objects.filter(video=video) 
section_headings= SectionHeading.objects.filter(video=video) 

함께

#Join querysets http://stackoverflow.com/questions/431628/how-to-combine-2-or-more-querysets-in-a-django-view 
s = sorted(chain(section_headings, section_clickables), key=attrgetter('order')) 

을 두 검색어 세트에 가입 :

class Section (models.Model): 
    title = models.CharField(max_length=80) 
    order = models.IntegerField() 

    class Meta: 
     abstract=True 
     ordering=['order'] 

문의 한 두 테이블 :

나는 추상 클래스를 사용하여 정착 인스턴스를 확인하십시오 :

from my.models import SectionHeading, SectionClickable 

@register.filter() 
def is_instance(obj, c): 
    try: 
     return isinstance(obj, eval(c)) 
    except: 
     raise ObjectDoesNotExist('Class supplied to is_instance could not be found. Import it in the template tag file.') 

그래서 내 템플릿 (HamlPy)에서 나는이 작업을 수행 할 수 있습니다 :

- if s|is_instance:"SectionClickable" 
    %span {{s.title}} 
- if s|is_instance:"SectionHeading" 
    %span{'style':'color: #{{s.color}};'} 
     {{s.title}} 

결과는 I 만 SectionHeading 개체에 대한 SectionClickable 객체 하나를 얻기 위해 두 개의 쿼리를 사용한다는 것입니다