'Add item ``obj`` to the graph. Returns True (and does nothing)
if the item has been seen already.
The ``parent_obj`` argument must already exist in the graph; if
not, it\'s ignored (but ``obj`` is still added with no
parent). In any case, Model._collect_sub_objects (for whom
this API exists) will never pass a parent that hasn\'t already
been added itself.
These restrictions in combination ensure the graph will remain
acyclic (but can have multiple roots).
``model``, ``pk``, and ``parent_model`` arguments are ignored
in favor of the appropriate lookups on ``obj`` and
``parent_obj``; unlike CollectedObjects, we can\'t maintain
independence from the knowledge that we\'re operating on model
instances, and we don\'t want to allow for inconsistency.
``nullable`` arg is ignored: it doesn\'t affect how the tree of
collected objects should be nested for display.'

def add(self, model, pk, obj, parent_model=None, parent_obj=None, nullable=False):

    (model, pk) = (type(obj), obj._get_pk_val())
    if model._meta.auto_created:
        return True
    key = (model, pk)
    if (key in self.seen):
        return True
    self.seen.setdefault(key, obj)
    if (parent_obj is not None):
        (parent_model, parent_pk) = (type(parent_obj), parent_obj._get_pk_val())
        parent_key = (parent_model, parent_pk)
        if (parent_key in self.seen):
            self.children.setdefault(parent_key, list()).append(key)
            self.parents.setdefault(key, parent_key)
