Accessing child attribute from parent class

I have three abstract base classes: DataContainer, BaseFileContainer and BaseImageContainer.

class BaseFileContainer(m.Model):
    class Meta:
        abstract = True
    # file - internally hosted file
    file = m.FileField(upload_to=archive_path, blank=True)


class BaseImageContainer(m.Model):
    class Meta:
        abstract = True
    # image - internally hosted file
    image = m.ImageField(upload_to=archive_path, blank=True)


class DataContainer(BaseDataContainer):
    class Meta:
        abstract = True
    # choices
    # render information for this hoster
    YOUTUBE = 'yt'
    render_type_choices = (
        (YOUTUBE, _('YouTube')),
    )
    # automatic properties
    cr_date = m.DateTimeField(auto_now_add=True, editable=False, verbose_name=_('Date of Creation'))  # date of creation
    # data type
    # common properties
    internal = m.BooleanField(default=True)
    # external - externally hosted data
    render_type = m.CharField(max_length=2, choices=render_type_choices, blank=True)  # a renderer for the hoster
    url = m.URLField(blank=True)
    # internal
    downloadable = m.BooleanField(default=False)
    # meta information
    name = m.CharField(max_length=255)
    created_on = m.DateTimeField(blank=True)  # When was this media created?
    created_by = m.CharField(max_length=255, blank=True)  # Who created it?
    created_at = m.CharField(max_length=255, blank=True)  # Where was it created?
    notes = m.TextField(blank=True)  # Notes for internal use
    # relationships with other models
    added_by = m.ForeignKey(User, null=True, default=None, on_delete=m.SET_NULL, editable=False)

These classes become concrete in these two classes:

class BaseImage(DataContainer, BaseImageContainer):
    pass


class BaseFile(DataContainer, BaseFileContainer):
    pass

I have a method defined for DataContainer that retrieves the media url. In order to do this, I need to either access the child class BaseFileContainer or BaseImageContainer.

def get_media_url(self):
    if self.internal and self.downloadable:
        if hasattr(self, 'file'):
            url = format_html(LINK, getattr(self, 'file').url, self.name)
        if hasattr(self, 'image'):
            url = format_html(LINK, getattr(self, 'image').url, self.name)
    elif self.external:
        url = format_html(LINK, self.url, self.name)
    else:
        url = '-'

Is it proper to access child attributes like this or should I rather define the method for the child classes? If I do that, I would have to basically define the same method twice which isn’t very DRY. Which way do you think is better?

In general terms, I’ve seen Python described as being ‘whatever you define as “proper” for your code is proper.’

<opinion> One of the real strengths of Python is that it doesn’t put any artificial constraints on how you structure your code. <opinion>

By design, Python exposes features that are intentionally blocked or hidden by other languages - making it possible and appropriate for you to write code like this.

2 Likes