Opened 7 years ago

Closed 7 years ago

#6844 closed (fixed)

Generic relations improperly inherited

Reported by: cide@… Owned by: nobody
Component: Database layer (models, ORM) Version: queryset-refactor
Severity: Keywords:
Cc: Triage Stage: Unreviewed
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: UI/UX:

Description

As can be seen below, the generic_models attribute of the BaseModel class is not properly inherited by the child class. In the TestModel example where no inheritance takes place, it works fine.

Code:

from django.db import models
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType

class GenericModel(models.Model):
    # Generic relation-related attributes
    content_type = models.ForeignKey(ContentType)
    content_object = generic.GenericForeignKey()
    object_id = models.PositiveIntegerField()

class BaseModel(models.Model):
    generic_models = generic.GenericRelation(GenericModel)
    
    class Meta:
        abstract = True
        
class ChildModel(BaseModel):
    name = models.CharField(max_length=31)
        
class TestModel(models.Model):
    generic_models = generic.GenericRelation(GenericModel)

Test case:

>>> test_child = TestModel()
>>> test_child.generic_models # Works
<django.contrib.contenttypes.generic.GenericRelatedObjectManager object at 0x01FBCED0>
>>> child = ChildModel(name='Test')
>>> child.generic_models # Raises AttributeError

D:\Python25\lib\site-packages\django\contrib\contenttypes\generic.py in __get__(self, instance, instance_type)
    190             join_table = qn(self.field.m2m_db_table()),
    191             source_col_name = qn(self.field.m2m_column_name()),
--> 192             target_col_name = qn(self.field.m2m_reverse_name()),
    193             content_type = ContentType.objects.get_for_model(self.field.model),
    194             content_type_field_name = self.field.content_type_field_name,

D:\Python25\lib\site-packages\django\contrib\contenttypes\generic.py in m2m_reverse_name(self)
    132
    133     def m2m_reverse_name(self):
--> 134         return self.model._meta.pk.column
    135
    136     def contribute_to_class(self, cls, name):

AttributeError: 'NoneType' object has no attribute 'column'

Attachments (1)

generic_relations_inheritance.diff (746 bytes) - added by cide@… 7 years ago.
Patch that locally fixes the issue

Download all attachments as: .zip

Change History (4)

Changed 7 years ago by cide@…

Patch that locally fixes the issue

comment:1 Changed 7 years ago by cide@…

  • Has patch set
  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset

I have attached a patch that locally fixes the issue. As far as I can tell, inherited classes m2m fields were not added to the class. However, my experience with django's internals is limited at best, so someone definitely needs to look over the patch and make sure it works.

comment:2 Changed 7 years ago by mtredinnick

Well done on finding the cause! There's some tricky code to navigate there.

The patch is almost correct. There's no need to loop over anything more than _meta.local_many_to_many, however, which is a little faster. So we'll do that.

comment:3 Changed 7 years ago by mtredinnick

  • Resolution set to fixed
  • Status changed from new to closed

(In [7345]) queryset-refactor: Correctly inherit m2m fields from abstract base classes.
Based on a patch from cide@…. Fixed #6844.

Note: See TracTickets for help on using tickets.
Back to Top