Question

Considering my previous question, I try to implement what I need.
The following is the content of a django app models.py.

from neo4django.db import models
from neo4django.auth.models import User as AuthUser

class MyManager(models.manager.NodeModelManager):
    def filterLocation(self,**kwargs):
        qs = self.get_query_set()
        if 'dist' in kwargs:
            qs = qs.filter(_where_dist=kwargs['dist'])
        elif 'prov' in kwargs:
            qs = qs.filter(_where_prov=kwargs['prov'])
        elif 'reg' in kwargs:
            qs = qs.filter(_where_reg=kwargs['reg'])
        return qs


class MyMixin(object):
    _test = models.BooleanProperty(default=True)
    _where_dist = models.StringProperty(indexed=True)
    _where_prov = models.StringProperty(indexed=True)
    _where_reg = models.StringProperty(indexed=True)

    search = MyManager()

    class Meta:
        abstract = True

class Activity(MyMixin,models.NodeModel):
    name = models.StringProperty()

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

I have many problems. The first is the non-inheritance of MyMixin's attributes:

>>> joe=User.objects.create(username='joe') # OK!
>>> joe
<User: joe>
>>> bill=User.objects.create(username='bill',_test=True)

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: '_test' is an invalid keyword argument for this function

But also the create fails to set User's own attributes!

>>> k=User.objects.create(username='kevin',info='The Best')

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

None of the mixin or User class own attributes exist in User. If I derived in reverse order:

class User(AuthUser,MyMixin):  

Here they are present, but I don't think is a good practice, should not core models go to the right? Anyway, as we see below, Activity does not have this problem,
like if AuthUser removed all attributes (intended behavior?).

While the alternative creation method works:

>>> k=User(username='kevin',info='The Best')
>>> k.save()
>>> k
<User: kevin>

But using the other Model, Activity, which inherits directly from NodeModelManager
(with User we have an intermediate parent AuthUser), things are better:

>>> a=Activity.objects.create(name="AA")
>>> a
<Activity: Activity object>

Several tests made with a simple NodeModel inheritance were ok, the problems arise with multiple inheritance and mixins.

Another problem, with my NodeModelManager:

>>> User.search.filterLocation(dist="b")

Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "/home/tonjo/prj/tuned_prj/tuned_django/myapp/models.py", line 6, in filterLocation
    qs = self.get_query_set()
  File "/home/tonjo/venv/tuned/local/lib/python2.7/site-packages/neo4django/db/models/manager.py", line 31, in get_query_
set
    return NodeQuerySet(self.model)
  File "/home/tonjo/venv/tuned/local/lib/python2.7/site-packages/neo4django/db/models/query.py", line 1222, in __init__
    self._app_label = model._meta.app_label
AttributeError: 'NoneType' object has no attribute '_meta'

This one is beyond my comprehension ;) MyManager worked well when in a previous test I derived from a NodeModel's child, not from a mixin.

Était-ce utile?

La solution

This is a pretty complicated question, but hopefully I can give you a pointer.

First- you need to understand that Django fields (and by extension neo4django properties) cooperate with the class on which they're defined. That's why they only work when defined on a Model (or, in neo4django, a NodeModel). There is no easy way to do multiple inheritance using Django models and fields- my mixin suggestion from your other question allows adding Python methods and attributes, but won't magically make Property or Field play nicely with object as a parent class.

If you really want to avoid duplication of property definitions in this situation, you have a few choices.

One is to use a shared super class- but in this case, you can't, since you need to inherit from neo4django.auth.models.User with one of your classes. This particular requirement will when neo4django supports Django 1.5+, which allows swappable user models.

Most metaprogramming won't work easily, since Django and neo4django make use of metaclasses. That said, I'm sure you could hack around this with a clever class decorator or child metaclass- but I'm not sure you should from a sanity standpoint :)

Let me know how it goes- maybe I'm missing an easier approach.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top