Last Updated: February 25, 2016
·
1.277K
· gaqzi

Dynamic model resolution in Django

I'm writing a reusable app with several abstract models. These models work together and that is all fine when they're normal concrete models. But when they're abstract and you want to work on a model that has not yet been defined in it's final used location it gets trickier.

The use case: The app is for competition logic. You participate in some kind of competition and then you win a prize and claim it.

So I got a Participant that wins a Prize and when the prize is won it'll create a Claim object.

The logic for creating the claim has been put in Prize but it doesn't have access to Claim directly. So I added an attribute to my model that has the reference to Claim.

from django.db import model

class ClaimClassResolution(object):
    '''To fix object resolution dynamically add a class based off of the
    current models app label
    '''
    _ClaimClass = None
    @property
    def ClaimClass(self):
        if self._ClaimClass is None:
            # self._meta.app_label is available on all models
            self._ClaimClass = models.get_model(self._meta.app_label, 'Claim')

        return self._ClaimClass

And then in my Prize.claim(...) method where I used to do Claim.objects.create(...) I now do self.ClaimClass.objects.create(...)

Worked like a charm and now my model is a little bit more dynamic.

The heavy lifting is done by django.db.models.get_model.

self._meta.app_label is available on all models.