Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django proxy model and ForeignKey

Tags:

How to make entry.category to be instance of CategoryProxy? See code for details:

class Category(models.Model): pass

class Entry(models.Model):
    category = models.ForeignKey(Category)

class EntryProxy(Entry):
    class Meta:
        proxy = True

class CategoryProxy(Category):
    class Meta:
        proxy = True

entry = EntryProxy.objects.get(pk=1)
entry.category # !!! I want CategoryProxy instance here

Cast from Category to CategoryProxy is ok too, but I am not very familiar with ORM internals to properly copy internal state...

EDIT. Reason: I added method to CategoryProxy and want to use him:

EntryProxy.objects.get(pk=1).category.method_at_category_proxy()

EDIT 2. Currently I implemented it like this:

EntryProxy._meta.get_field_by_name('category')[0].rel.to = CategoryProxy

but it looks terrible...

like image 789
Vladimir Mihailenco Avatar asked Oct 08 '10 15:10

Vladimir Mihailenco


People also ask

What is Django ForeignKey model?

ForeignKey is a Django ORM field-to-column mapping for creating and working with relationships between tables in relational databases.

What is proxy model in Django?

A proxy model is a subclass of a database-table defining model. Typically creating a subclass of a model results in a new database table with a reference back to the original model's table - multi-table inheritance. A proxy model doesn't get its own database table. Instead it operates on the original table.

What is meta class in Django model?

Model Meta is basically the inner class of your model class. Model Meta is basically used to change the behavior of your model fields like changing order options,verbose_name, and a lot of other options. It's completely optional to add a Meta class to your model.


2 Answers

To switch from a model class to a proxy class without hitting the database:

class EntryProxy(Entry):
    @property
    def category(self):
        new_inst = EntryProxy()
        new_inst.__dict__ = super(EntryProxy, self).category.__dict__
        return new_inst

edit: the snippet above seems not working on django 1.4.

Since django 1.4, I take all value fields manually like this:

class EntryProxy(Entry):
    @property
    def category(self):
        category = super(EntryProxy, self).category
        new_inst = EntryProxy()
        for attr in [f.attname for f in category.__class__._meta.fields] + ['_state']:
            setattr(new_inst, attr, getattr(category, attr))
        return new_inst

To switch from a queryset to a child proxy class without hitting database:

class CategoryProxy(Category):
    @property
    def entry_set(self):
        qs = super(CategoryProxy, self).entry_set
        qs.model = EntryProxy
        return qs
like image 154
christophe31 Avatar answered Sep 21 '22 00:09

christophe31


This is an open Django issue: #10961 (Allow users to override forward and reverse relationships on proxy models with ForeignKey fields)

You can work around it by resetting the fields in question after you define the proxy models:

EntryProxy.add_to_class('category', CategoryProxy)
like image 40
Pi Delport Avatar answered Sep 23 '22 00:09

Pi Delport