Search code examples
djangotastypie

TastyPie: related resource returns NULL


I have UserProfile model which extends Django's User model:

class UserProfile(models.Model):
    user = models.OneToOneField(User, related_name="profile")
    avatar = models.CharField(max_length=40, default='0')
    activation_key = models.CharField(max_length=40, blank=True)
    key_expires = models.DateTimeField(default=django.utils.timezone.now)

    def __str__(self):
        return self.user.username

    class Meta:
        verbose_name_plural = u'User profiles'

I have two resources:

class UserProfileResource(ModelResource):
    class Meta:
        queryset = UserProfile.objects.all()
        resource_name = 'profile'
        allowed_methods = ['get']

and

class UserResource(ModelResource):
    profile = fields.ToOneField('api.api.UserProfileResource',
                                'profile', full=True, null=True)
    class Meta:
        queryset = User.objects.all()
        #fields = ['first_name', 'last_name', 'email', 'date_joined', 'profile']
        fields = [ 'profile' ]
        allowed_methods = ['get', 'post']
        resource_name = 'user'
        authentication = SessionAuthentication()
        authorization = DjangoAuthorization()
        detail_uri_name = 'username'

    def obj_create(self, bundle, **kwargs):
        return super(UserResource, self).obj_create(bundle, user=bundle.request.user)

    def authorized_read_list(self, object_list, bundle):
        return object_list.filter(user=bundle.request.user)

I trying to make a GET request:

http://localhost:8000/api/v1/user/<some_username>

And I receive:

Object { profile: null, resource_uri: "/api/v1/user/<some_username>/" }

It's correct that the profile is NULL, because I have an attribute null=True in my UserResource. The response is empty, that is why I receive NULL. But how I can solve this problem? What is wrong?

Maybe it's because of the structure of the project? The resources file is:

<project_name>/api/api.py

Solution

  • Accidentally I found the decision. Model:

    class UserProfile(models.Model):
        user = models.OneToOneField(User)
        avatar = models.CharField(max_length=40, default='0')
        activation_key = models.CharField(max_length=40, blank=True)
        key_expires = models.DateTimeField(default=django.utils.timezone.now)
    
        def __str__(self):
            return self.user.username
    
        class Meta:
            verbose_name_plural = u'User profiles'
    

    Resources:

    class UserProfileResource(ModelResource):
    
        class Meta:
            queryset = UserProfile.objects.all()
            authentication = SessionAuthentication()
            authorization = DjangoAuthorization()
            allowed_methods = ['get', 'post']
            resource_name = 'profile'
            include_resource_uri = False
    
    class UserResource(ModelResource):
        userprofile = fields.ToOneField(UserProfileResource, 'userprofile', null=True, full=True)
    
        class Meta:
            queryset = User.objects.all()
            fields = ['first_name', 'last_name', 'email', 'date_joined', 'userprofile']
            allowed_methods = ['get', 'post']
            resource_name = 'user'
            detail_uri_name = 'username'
            authentication = SessionAuthentication()
            authorization = DjangoAuthorization()
    

    As you can see, this line is important:

    userprofile = fields.ToOneField(UserProfileResource, 'userprofile', null=True, full=True)
    

    The name of this property (userprofile) should be equal to the name of the model (UserProfile).

    GET request:

    http://localhost:8000/api/v1/user/<some_username>
    

    Response:

    {
        "date_joined": "2016-03-01T08:22:40", 
        "email": "[email protected]", 
        "first_name": "Ivan", 
        "last_name": "Ivan", 
        "resource_uri": "/api/v1/user/<some_username>/", 
        "userprofile": {
            "activation_key": "...", 
            "avatar": "...", 
            "id": 22, 
            "key_expires": "2016-03-14T17:11:01"
        }
    }