views:

39

answers:

2

The following code is given:

class BaseMedium(models.Model):
    title = models.CharField(max_length=40)
    slug = models.SlugField()

class A(BaseMedium):
    url = models.URLField()

class B(BaseMedium):
    email = models.EmailField()

I now want to query every BaseMedium.

 b = BaseMedium.objects.all()

How do I print every information including the subclass fields without knowing what the subclass type is?

b[0].a would print the information if b[0] is actually related to an A instance but if it's related to B it would print an DoesNotExist Exception. This makes sense but I'd like to have a common variable or method that returns the related object. Maybe my Database layout isn't really great to query that way if so I'd be glad if you'd recommend a better layout. I thought about using a GenericForeignKey

class Generic(models.Model):
    basemedium = models.ForeignKey('BaseMedium')
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    object = generic.GenericForeignKey('content_type', 'object_id')

but this solution seems to be to complicated and I think you guys have better solutions.

A: 

The only way to do this is to explicitly store on the base model what type it is. So have a derived_type (or whatever) field on BaseMedium, and set it on save. Then you can have a get_derived_type method:

def get_derived_type(self):
    if self.derived_type ==  'A':
        return self.a
    elif self.derived_type == 'B':
        return self.b

and so on.

Daniel Roseman
A: 

Thanks mr. Roseman for your reply. I developed your idea a bit further. Here is what I came up with:

def related_object(self, default_pointer_name='_ptr'):
        models = [A,B] #models
        object = None

        argument = '%s%s' %(self.__class__.__name__.lower(), default_pointer_name)
        query = { argument : self}

        for model in models:
            try:
                object = model.objects.get(**query)
            except model.DoesNotExist:
                pass
            else:
                return object

        if object == None:
            raise RelatedObjectException
        return object

This is a method used by BaseMedium.

rotrotrot
You should be carefull with this one. If you have 1000 of records to be retrieved from DB this will be done in one SELECT but then it will be 1000 single selects to get subtype for each BaseMedium object. Anyway I don't know better idea how to do that. I use something simillar, which produces a lot of extra db queries...
Lukasz Dziedzia
shoot you're right.Custom sql could be an option...The weird thing is I don't get how this is not a common problem with known solution.
rotrotrot