Return proxied class in many to many relation, Django 2.0

331 Views Asked by At

From another installed app, I have models like this

class Organization(model.Model):
    name = models.CharField(max_length=255, blank=True)

class Person(model.Model):
    name = models.CharField(max_length=255, blank=True)

class Membership(model.Model):

    organization = models.ForeignKey(
        Organization,
        related_name='memberships',
        # memberships will go away if the org does
        on_delete=models.CASCADE,
        help_text="A link to the Organization in which the Person is a member.")

    person = models.ForeignKey(
        Person,
        related_name='memberships',
        null=True,
        # Membership will just unlink if the person goes away
        on_delete=models.SET_NULL,
        help_text="A link to the Person that is a member of the Organization.")

In my app, I need to add some method to some of the models. So I have a model like

class ProxiedOrganization(other_app.models.Organization):
    class Meta:
        proxy = True

    special_attribute = 'foo'


class ProxiedPerson(other_app.models.Person):
    class Meta:
        proxy = True

    def special_method(self):
         print('I do something special')

When I get the memberships from an organization, they are of type other_app.models.Person.

> type(proxied_org_instance.memberships[0].person)
<class 'other_app.models.Person'>

but, I'd like them to be my instances of my proxy class

> type(proxied_org_instance.memberships[0].person)
<class 'my_app.models.ProxiedPerson'>

Is there a good way of doing this? Is this the kind of thing that I can do with a query manager? The solution must work for Django 2.0.

2

There are 2 best solutions below

0
On BEST ANSWER

I adapted Matt Schinckel's work on overriding proxy model relations, for a solution that will work with Django 2.0 and 2.1. The code is available as a library on pypi.

2
On

You need to either put a ForeignKey in Organization to ProxiedPerson. For example:

class MemberShip(models.Model):
    person = models.ForeignKey(
        ProxyPerson,
        related_name='memberships',
        null=True,
        # Membership will just unlink if the person goes away
        on_delete=models.SET_NULL,
        help_text="A link to the Person that is a member of the Organization.")

or you can get the proxy person instance by:

proxy_person = ProxyPerson.objects.get(pk=proxied_org_instance.memberships[0].person.pk)

Or

proxy_persons = ProxyPerson.objects.filter(
                    pk__in = proxied_org_instance.memberships.all().values_list('person_id')
                )

As per documentation

The MyPerson class operates on the same database table as its parent Person class. In particular, any new instances of Person will also be accessible through MyPerson, and vice-versa

Means you can access Person Instance through ProxyPerson Instance or vice versa.