scholrly / neo4django

Drop-in Neo4j/Django integration.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Mixin multiple-inheritance errors with neo4django.auth.models.User

tonjo opened this issue · comments

EDIT: commented out wrong example and indented correctly

neo4django.auth.models.User "hides" attributes
when used in a multiple inheritance with a mixin.

from neo4django.auth.models import User as AuthUser
class MyMixin(object):
     # WRONG EXAMPLE _test = models.BooleanProperty(default=True)
     def somefunction():
          pass

class Meta:
    abstract = True

class User(MyMixin,AuthUser):
    info = models.StringProperty()

u=User.objects.create(username='joe',info='My poor user')

Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "/home/tonjo/venv/tuned/local/lib/python2.7/site-packages/neo4django/db/models/manager.py", line 43, in create return self.get_query_set().create(**kwargs)
  File "/home/tonjo/venv/tuned/local/lib/python2.7/site-packages/neo4django/db/models/query.py", line 1296, in create return super(NodeQuerySet, self).create(**kwargs)
  File "/home/tonjo/venv/tuned/local/lib/python2.7/site-packages/django/db/models/query.py", line 375, in create obj = self.model(**kwargs)
  File "/home/tonjo/venv/tuned/local/lib/python2.7/site-packages/neo4django/db/models/base.py", line 141, in __init__ super(NodeModel, self).__init__(*args, **kwargs)
  File "/home/tonjo/venv/tuned/local/lib/python2.7/site-packages/django/db/models/base.py", line 367, in __init__ raise TypeError("'%s' is an invalid keyword argument for this function" % kwargs.keys()[0])
 TypeError: 'info' is an invalid keyword argument for this function

EDIT: The error is on info field, which is in the derived class! It's "masked".
Note: inverting the inheritance order:

class User(AuthUser,MyMixin):

does not give that problem, but I think it's not a good practice.

Also, mixing mixins (forgive the pun) with models.NodeModel
seems to be ok. Only neo4django.auth.models.User gives problems.

@tonjo I realize what you're trying to do, but Django fields and models were not meant to work the way you'd like them to. Multiple inheritance of a neo4django NodeModel and any class inheriting from a Model, or a mixin with any defined fields (anything inheriting django.db.models.fields.Field, eg Property, BooleanProperty, ...) is not supported. If you read some of the Django source (relevant bits in https://github.com/django/django/tree/master/django/db/models) you'll see why this is the case- fields and models cooperate via a model metaclass (https://github.com/django/django/blob/master/django/db/models/base.py#L54 , ModelBase) that couldn't easily support a diamond inheritance pattern.

neo4django was built to emulate the Django ORM syntax. In fact, the reason it supports the admin interface is this strong adherence- straying too far would not only make things more difficult for experienced Django developers, but potentially threaten compatibility with the admin interface and other important components. I'd consider departures from that pre-defined goal to better interact with the database, but not to make writing models easier than it already is.

I'm closing this, essentially, as a "WONTFIX". I love multiple inheritance, but I don't think it's a particularly pressing concern writing models.

@tonjo NB - I meant to mention a few issues ago- you can have GitHub indent your Python code properly following Markdown syntax. If you add 4 additional spaces before each line of code, it will be formatted as a code block and be much easier to read.

My mistake, I didn't want to include a Field in the metaclass,
that is not my point.
I understood what you teached me also on StackOverflow,
but here I have another problem, in the derived class User, its own fields are masked.
I want to insist with the following (forgive me for forgetting Markdown):

class MyMixin(object):
    def somefunction():   # No Fields, just some useful functions
        pass
    class Meta:
        abstract = True

and the User as above:

 class User(MyMixin,AuthUser):
     info = models.StringProperty()

User's info field should not "disappear", am I wrong?
Indeed, as I said, deriving from NodeModel instead of neo4django.auth.models.User
there are no problems at all.

PS: You wrote:

relevant bits in https://github.com/django/django/tree/master/django/db/models

which file did you mean?