Question

I try to use the django REST-framework's tutorial http://django-rest-framework.org/#django-rest-framework to administrate users. (I also use the Neo4j database and the neo4django mapper https://github.com/scholrly/neo4django to acces data via python.)
Whatever, wen I call localhost:8000/users an AttributeError appears.

models.py

from django.utils import timezone
from django.conf import settings

from django.contrib.auth import models as django_auth_models

from ..db import models
from ..db.models.manager import NodeModelManager
from ..decorators import borrows_methods

class UserManager(NodeModelManager, django_auth_models.UserManager):
    pass

# all non-overriden methods of DjangoUser are called this way instead.
# inheritance would be preferred, but isn't an option because of conflicting
# metaclasses and weird class side-effects
USER_PASSTHROUGH_METHODS = (
    "__unicode__", "natural_key", "get_absolute_url",
    "is_anonymous", "is_authenticated", "get_full_name", "set_password",
    "check_password", "set_unusable_password", "has_usable_password",
    "get_group_permissions", "get_all_permissions", "has_perm", "has_perms",
    "has_module_perms", "email_user", 'get_profile','get_username')

@borrows_methods(django_auth_models.User, USER_PASSTHROUGH_METHODS)
class User(models.NodeModel):
    objects = UserManager()

    username = models.StringProperty(indexed=True, unique=True)
    first_name = models.StringProperty()
    last_name = models.StringProperty()

    email = models.EmailProperty(indexed=True)
    password = models.StringProperty()

    is_staff = models.BooleanProperty(default=False)
    is_active = models.BooleanProperty(default=False)
    is_superuser = models.BooleanProperty(default=False)

    last_login = models.DateTimeProperty(default=timezone.now())
    date_joined = models.DateTimeProperty(default=timezone.now())

    USERNAME_FIELD = 'username'
    REQUIRED_FIELDS=['email']

serializers.py

from neo4django.graph_auth.models import User
from rest_framework import serializers


class UserSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = User
        fields = ('url', 'username', 'email')

views.py

from neo4django.graph_auth.models import User
from rest_framework import viewsets

from api.serializers import UserSerializer

class UserViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows users to be viewed or edited.
    """
    queryset = User.objects.all()
    serializer_class = UserSerializer  

I get this:

Environment:  

Request Method: GET
Request URL: http://localhost:8000/users/

Django Version: 1.5.3
Python Version: 2.7.3
Installed Applications:
('core.models',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'neo4django.graph_auth',
 'rest_framework')
Installed Middleware:
('django.middleware.common.CommonMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware')


Traceback:
File "/opt/phaidra/env/local/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
  115.                         response = callback(request, *callback_args, **callback_kwargs)
File "/opt/phaidra/env/local/lib/python2.7/site-packages/rest_framework/viewsets.py" in view
  78.             return self.dispatch(request, *args, **kwargs)
File "/opt/phaidra/env/local/lib/python2.7/site-packages/django/views/decorators/csrf.py" in wrapped_view
  77.         return view_func(*args, **kwargs)
File "/opt/phaidra/env/local/lib/python2.7/site-packages/rest_framework/views.py" in dispatch
  399.             response = self.handle_exception(exc)
File "/opt/phaidra/env/local/lib/python2.7/site-packages/rest_framework/views.py" in dispatch
  396.             response = handler(request, *args, **kwargs)
File "/opt/phaidra/env/local/lib/python2.7/site-packages/rest_framework/mixins.py" in list
  92.             serializer = self.get_pagination_serializer(page)
File "/opt/phaidra/env/local/lib/python2.7/site-packages/rest_framework/generics.py" in get_pagination_serializer
  113.         return pagination_serializer_class(instance=page, context=context)
File "/opt/phaidra/env/local/lib/python2.7/site-packages/rest_framework/pagination.py" in __init__
  85.         self.fields[results_field] = object_serializer(source='object_list', **context_kwarg)
File "/opt/phaidra/env/local/lib/python2.7/site-packages/rest_framework/serializers.py" in __init__
  162.         self.fields = self.get_fields()
File "/opt/phaidra/env/local/lib/python2.7/site-packages/rest_framework/serializers.py" in get_fields
  198.         default_fields = self.get_default_fields()
File "/opt/phaidra/env/local/lib/python2.7/site-packages/rest_framework/serializers.py" in get_default_fields
  599.         while pk_field.rel and pk_field.rel.parent_link:

Exception Type: AttributeError at /users/
Exception Value: 'IdLookup' object has no attribute 'rel'

I am rather new on the Python/Django/REST service area. I hope someone could help. Thanks in advance.

Était-ce utile?

La solution

Firstly I would recommend to either use Tastypie - which is out of the box supported by neo4django - instead of Django Rest Framework - or use Django Rest Framework Serializer instead of the ModelSerializer or (worst choice in my opinion) HyperlinkedModelSerializer.

As for the error you get, the problem is that neo4django does not return the record id, therefore you get the error.

One solution is to override the restore_object function, like this, to include the ID.

# User Serializer
class UserSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    username = serializers.CharField(max_length=30)
    first_name = serializers.CharField(max_length=30)
    last_name = serializers.CharField(max_length=30)

    email = serializers.EmailField()
    password = serializers.CharField(max_length=128)

    is_staff = serializers.BooleanField()
    is_active = serializers.BooleanField()
    is_superuser = serializers.BooleanField()

    last_login = serializers.DateTimeField()
    date_joined = serializers.DateTimeField()

    def restore_object(self, attrs, instance=None):
        """
        Given a dictionary of deserialized field values, either update
        an existing model instance, or create a new model instance.
        """
        if instance is not None:
            instance.id = attrs.get('ID', instance.pk)
            instance.username = attrs.get('Username', instance.username)
            instance.first_name = attrs.get('First Name', instance.first_name)
            instance.last_name = attrs.get('First Name', instance.last_name)
            instance.email = attrs.get('email', instance.email)
            instance.password = attrs.get('Password', instance.password)
            instance.is_staff = attrs.get('Staff', instance.is_staff)
            instance.is_active = attrs.get('Active', instance.is_active)
            instance.is_superuser = attrs.get('Superusers', instance.is_superuser)
            instance.last_login = attrs.get('Last Seen', instance.last_login)
            instance.date_joined = attrs.get('Joined', instance.date_joined)
            return instance
        return User(**attrs)

But I still think it's better to use Tastypie with ModelResource. Here's a gist by Matt Luongo (or Lukas Martini ?) https://gist.github.com/mhluongo/5789513

TIP. Where Serializer in Django Rest Framework, is Resource in Tastypie and always make sure you are using the github version of neo4django (pip install -e git+https://github.com/scholrly/neo4django/#egg=neo4django)

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