Backwards relation not showing up via related_name in inherited models

47 views
Skip to first unread message

Joshua Orvis

unread,
Oct 28, 2013, 3:29:39 AM10/28/13
to django...@googlegroups.com
I'm using Django 1.6 RC1 and Python 3.3 with the following models:

class StepBlueprint(models.Model):
    parents = models.ManyToManyField('self', blank=True, null=True, related_name='children')
    name   = models.CharField( max_length=100 )

    def __str__(self):
        return self.name

class FlowBlueprint(StepBlueprint):
    description = models.TextField()
        
    def get_children(self):
        print("DEBUG: processing ({0})".format(self))
        print(dir(self))

        # why isn't this working??  this is what related_name is supposed to provide
        return self.children

When I call get_children() here, I get the following:

DEBUG: processing (Prodigal)
['DoesNotExist', 'MultipleObjectsReturned', 'TYPES', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_base_manager', '_default_manager', '_deferred', '_do_insert', '_do_update', '_get_FIELD_display', '_get_next_or_previous_by_FIELD', '_get_next_or_previous_in_order', '_get_pk_val', '_get_unique_checks', '_meta', '_perform_date_checks', '_perform_unique_checks', '_save_parents', '_save_table', '_set_pk_val', '_state', 'build', 'clean', 'clean_fields', 'commandblueprint', 'conditional_code', 'date_error_message', 'delete', 'description', 'flow_set', 'flowblueprint', 'full_clean', 'get_children', 'get_command', 'get_type_display', 'id', 'name', 'objects', 'parents', 'pk', 'prepare_database_save', 'save', 'save_base', 'serializable_value', 'standalonetool_set', 'stepblueprint_ptr', 'stepblueprint_ptr_id', 'type', 'unique_error_message', 'validate_unique']
Traceback (most recent call last):
  [ call stack ... ]
    return self.children
AttributeError: 'FlowBlueprint' object has no attribute 'children'

What am I doing wrong here?  From within the FlowBlueprint object I want to be able to get the backwards relation of all those objects pointing to it, and it seems like related_name is supposed to provide that.  Its value doesn't show up in the dir() output.

Any help would be greatly appreciated.

Daniel Roseman

unread,
Oct 28, 2013, 7:56:40 AM10/28/13
to django...@googlegroups.com
This has nothing to do with inheritance - you would get the same result if you called `self.children` from StepBlueprint.

See the documentation on many-to-many relationships with self:
(emphasis added):

"When Django processes this model, it identifies that it has a ManyToManyField on itself, and as a result, it **doesn’t add a person_set attribute to the Person class**. Instead, the ManyToManyField is assumed to be symmetrical – that is, if I am your friend, then you are my friend.
If you do not want symmetry in many-to-many relationships with self, set symmetrical to False. This will force Django to add the descriptor for the reverse relationship, allowing ManyToManyField relationships to be non-symmetrical."
--
DR.

Joshua Orvis

unread,
Oct 28, 2013, 11:11:24 AM10/28/13
to django...@googlegroups.com
Thank you for responding, that's extremely helpful.  I'm still failing to query against it though.  How would I implement a query for the get_children() method in the example above?  That is, for any given instance of FlowBlueprint how do I get all objects with a relation to it?

Daniel Roseman

unread,
Oct 28, 2013, 12:07:34 PM10/28/13
to django...@googlegroups.com
On Monday, 28 October 2013 15:11:24 UTC, Joshua Orvis wrote:
Thank you for responding, that's extremely helpful.  I'm still failing to query against it though.  How would I implement a query for the get_children() method in the example above?  That is, for any given instance of FlowBlueprint how do I get all objects with a relation to it?

The point is that unless the M2M field has `symmetrical=False`, there's only one side of the relation, which is `parents`. So in this case you would just do `self.parents.all()`. That said, for a parent/child relationship like this you probably do want to set symmetrical to False, in which case `self.children.all()` would work.
--
DR.

Reply all
Reply to author
Forward
0 new messages