Reputation: 6764
I am using custom authentication in Django-Tastypie, which returns the username and password when authentication succeeds. In the ModelResource instance, once the authentication is successful, the username and password are available:
class TestResource(ModelResource):
class Meta:
queryset = Test.remote_supported.get_all(username,password)
resource_name = 'test'
filtering = {
'id' : ALL,
}
detail_allowed_methods = ['get', 'post', 'patch']
authorization = Authorization()
authentication = MyCustomAuth()
always_return_data = True
def __init__(self, api_name=None):
self.username = None
self.password = None
super(TestResource, self).__init__(api_name)
def is_authenticated(self, request):
auth_result = self._meta.authentication.is_authenticated(request)
if isinstance(auth_result, HttpResponse):
raise ImmediateHttpResponse(response=auth_result)
if not auth_result is True:
raise ImmediateHttpResponse(response=http.HttpUnauthorized())
# this is where I receive the username and password from my custom auth
self.username, self.password = self._meta.authentication.get_credentials()
This code obviously does not work, because that username and that password are not available in the Metaclass, and even if it were, changing it would not affect only this instance, but all instances, which is not my intention, because the scope of username and password should be per RESTful query.
This is what my model looks like:
class RemoteAuthSupported(models.Manager):
def get_all(self, username, password):
# ... here I do some custom operations with the username and password
return super(RemoteAuthSupported, self).get_query_set()
class Test(models.Model):
objects = models.Manager()
remote_supported = RemoteAuthSupported()
# ... the field declarations follow here ... #
The reason I am trying to do this is that I am using a non-ORM data source with my Django application, which requires authentication of its own, but with the same username and password. What would be the method of handling this parameter passing from a Tastypie ModelResource to a Django Model? I probably should mention here that there is no user model in use.
Upvotes: 0
Views: 413
Reputation: 6764
I looked into the Tastypie documentation, and it seems like the following could be a solution, albeit amateurish:
class TestResource(ModelResource):
class Meta:
queryset = Test.remote_supported.get_all('dummyusername','dummypassword')
resource_name = 'test'
filtering = {
'id' : ALL,
}
detail_allowed_methods = ['get', 'post', 'patch']
authorization = Authorization()
authentication = MyCustomAuth()
always_return_data = True
def get_object_list(self, request):
"""
This method calls a clone of the queryset declared in the Metaclass.
It is called every time a query is executed.
Here the actual username and password is passed to the model.
"""
return Site.remote_supported.get_all(self.username,self.password)
The problem was that the queryset declaration happened in the Metaclass only once, not per query, so the username and password acquired from the http request could not be passed on to the query in the Meta level. But since get_object_list()
clones the declaration and performs the actual call with the updates argument values, this gets the job done. It is working for me, but I feel there should be a better solution for doing this.
Upvotes: 0
Reputation: 15864
What you could do is override the obj_get_list
method that returns the list of resources for a request. Also, you could set the username and password to the request
object itself, so the paramters get carried over the request-response path. Also, you'd need to set the queryset
to all()
.
def obj_get_list(self, bundle, **kwargs):
original = super(TestResource, self).obj_get_list(bundle, **kwargs)
request = bundle.request
return original.get_all(request.username, request.password)
Or the other way round - you could add custom authorization that would filter the objects list. The request
attributes part still holds.
class MyAuth(Authorization):
def authorized_read_list(self, objects, bundle):
request = bundle.request
return objects.get_all(request.username, request.password)
If you would rather imitate queryset
using get_all
than just alternating list endpoint, you could override the get_object_list
.
def get_object_list(self, request):
original = super(TestResource, self).get_object_list(request)
return original.get_all(request.username, request.password)
Upvotes: 1