【问题标题】:How do I know which child class a Django model object is when selected through the parent class?通过父类选择 Django 模型对象时,如何知道是哪个子类?
【发布时间】:2012-09-23 21:21:35
【问题描述】:

我有一个主要的Event 类和四种事件类型。它们中的每一个都是(至少)Event 的子类。在事件的详细信息页面上,我正在为给定事件添加返回到管理界面的链接,以节省在管理中搜索的时间。不幸的是,无论子类如何,事件都是从父类Event 中选择的。我对这个问题的解决方案是鸭式,在这种情况下我觉得这绝对是糟糕的。 我希望有一个更优雅且易于维护的解决方案来解决我的问题。

型号:

class Event(models.Model):
    ...

class ListedEvent(Event):
    ....

class RSVPEvent(Event):
    ....

class TicketedEvent(Event):
    ....

class TicketedConcert(TicketedEvent):
    ....

要查看活动详细信息,URL 会传递场地信息和活动名称信息。这足以在所有子事件中将单个事件与父 Event 模型隔离开来。它还让我可以将事件类型排除在 URL 之外,使它们更简单、更友好。

@render_to('events/event_details.html')
def event_details(request, venue, slug):
    """
    Detail view of an event.
    """
    try:
        event = Event.objects.select_related(
            'listedevent',
            'rsvpevent',
            'ticketedevent',
            'ticketedconcert',
            'venue',
            'sites',
            'dj',
        ).get(
            slug=slug,
            venue__slug=venue,
        )
    except Event.DoesNotExist:
        raise Http404

    return {'event': event}

在我返回并意识到我正在使用父 Event 模型之前,假设我从其实际模型中选择一个事件(父类 Event 的属性),这个解决方案更加优雅并且在 shell 中运行良好:

@property
def admin_link(self):
    et = self.__class__.__name__.lower()
    # ALWAYS: et == 'event', reverse() fails, returns ''
    return reverse('admin:events_%s_change' % et, args=(self.id,))

我目前的解决方案(父类的属性Event):

@property
def admin_link(self):
    duck = None

    try:
        duck = self.ticketedevent.ticketedconcert.artist_name
        return reverse(
            'admin:events_ticketedconcert_change',
            args=(self.id,)
        )
    except:
        pass

    try:
        duck = self.ticketedevent.max_tickets
        return reverse(
            'admin:events_ticketedevent_change',
            args=(self.id,)
        )
    except:
        pass

    try:
        duck = self.rsvpevent.total_rsvp
        return reverse(
            'admin:events_rsvpevent_change',
            args=(self.id,)
        )
    except:
        pass

    try:
        duck = self.listedevent.name
        return reverse(
            'admin:events_listedevent_change',
            args=(self.id,)
        )
    except:
        pass

必须有一种更简单、更易于维护的方法来找出我正在查看的事件类型。有什么想法吗?

【问题讨论】:

    标签: django django-models python-2.6 django-1.3


    【解决方案1】:

    这是acommonissue,它似乎仍然是 Django 的丑小鸭之一。

    您至少可以重新安排 2 美分的 DRY 收益:

    from django.core.exceptions import ObjectDoesNotExist
    
    @property
    def event_type(self):
         for et in ('ticketedevent', 'rsvpevent', 'sillyhatsonlyevent', ...):
             try:
                 getattr(self, et)
                 return et
             except ObjectDoesNotExist:
                 pass
    
    @property
    def admin_link(self):
        return reverse('admin:events_%s_change' % self.event_type, args=(self.id,))
    

    如果你真的想花哨,你可以使用Event.__subclasses__ 并生成事件类型列表。

    【讨论】:

      猜你喜欢
      • 2012-09-06
      • 1970-01-01
      • 2023-03-14
      • 2011-04-30
      • 1970-01-01
      • 1970-01-01
      • 2013-06-02
      • 2013-08-22
      • 1970-01-01
      相关资源
      最近更新 更多