django rest framework has_object_permission raising PermissionDenied exception - django

Am trying to build a permission class for my django rest framework view, which should either allow or disallow the user access.
class UserPermissions(permissions.DjangoModelPermissions):
"""
"""
def has_object_permission(self, request, view, obj):
# if safe methods (get, retrieve) we check permissions from django perms
if request.method in permissions.SAFE_METHODS:
return super(UserPermissions, self).has_object_permission(request, view, obj)
# else if methods (post, put, patch), we match user with obj and if obj is owner we grant him access
return request.user == obj
the above code seems to be working fine, but while I was build test cases. I built one case where I try to intentionally update user x using user y credentials
def test_patching_someones_else_profile(self):
""" Test patching someone's else profile """
response = self.c.post("/api/account/api-token-auth/", {'username': 'lion', 'password': 'password'})
self.assertEqual(response.status_code, 200, "User couldn't log in")
token = response.data['token']
user_id = response.data['id']
header = {'HTTP_AUTHORIZATION': 'Token {}'.format(token)}
response = self.c.patch(reverse('user-detail', args=['1', ]), {'last_name': 'mooz'}, **header)
the problem am seeing now, its suddenly throws an exception PermissionDenied(), it does not return any status_code to handle, instead the application is crashing with following exception
======================================================================
ERROR: test_patching_someones_else_profile (dlap.apps.account.tests.UserTestCase)
Test patching someone's else profile
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/mo/Projects/pythonic/dl-env/dlap/apps/account/tests.py", line 217, in test_patching_someones_else_profile
response = self.c.patch(reverse('user-detail', args=['1', ]), {'last_name': 'mooz'}, **header)
File "/Users/mo/Projects/pythonic/dl-env/lib/python2.7/site-packages/rest_framework/test.py", line 84, in patch
return self.generic('PATCH', path, data, content_type, **extra)
File "/Users/mo/Projects/pythonic/dl-env/lib/python2.7/site-packages/rest_framework/compat.py", line 487, in generic
return self.request(**r)
File "/Users/mo/Projects/pythonic/dl-env/lib/python2.7/site-packages/rest_framework/test.py", line 143, in request
return super(APIClient, self).request(**kwargs)
File "/Users/mo/Projects/pythonic/dl-env/lib/python2.7/site-packages/rest_framework/test.py", line 95, in request
request = super(APIRequestFactory, self).request(**kwargs)
File "/Users/mo/Projects/pythonic/dl-env/lib/python2.7/site-packages/django/test/client.py", line 444, in request
six.reraise(*exc_info)
File "/Users/mo/Projects/pythonic/dl-env/lib/python2.7/site-packages/django/core/handlers/base.py", line 139, in get_response
response = response.render()
File "/Users/mo/Projects/pythonic/dl-env/lib/python2.7/site-packages/django/template/response.py", line 105, in render
self.content = self.rendered_content
File "/Users/mo/Projects/pythonic/dl-env/lib/python2.7/site-packages/rest_framework/response.py", line 59, in rendered_content
ret = renderer.render(self.data, media_type, context)
File "/Users/mo/Projects/pythonic/dl-env/lib/python2.7/site-packages/rest_framework/renderers.py", line 577, in render
context = self.get_context(data, accepted_media_type, renderer_context)
File "/Users/mo/Projects/pythonic/dl-env/lib/python2.7/site-packages/rest_framework/renderers.py", line 537, in get_context
raw_data_put_form = self.get_raw_data_form(view, 'PUT', request)
File "/Users/mo/Projects/pythonic/dl-env/lib/python2.7/site-packages/rest_framework/renderers.py", line 475, in get_raw_data_form
serializer = view.get_serializer(instance=obj)
File "/Users/mo/Projects/pythonic/dl-env/lib/python2.7/site-packages/rest_framework/generics.py", line 99, in get_serializer
serializer_class = self.get_serializer_class()
File "/Users/mo/Projects/pythonic/dl-env/dlap/apps/account/views.py", line 96, in get_serializer_class
obj = self.get_object()
File "/Users/mo/Projects/pythonic/dl-env/dlap/apps/account/views.py", line 107, in get_object
return super(UserViewSet, self).get_object(queryset=queryset)
File "/Users/mo/Projects/pythonic/dl-env/lib/python2.7/site-packages/rest_framework/generics.py", line 321, in get_object
self.check_object_permissions(self.request, obj)
File "/Users/mo/Projects/pythonic/dl-env/lib/python2.7/site-packages/rest_framework/views.py", line 284, in check_object_permissions
self.permission_denied(request)
File "/Users/mo/Projects/pythonic/dl-env/lib/python2.7/site-packages/rest_framework/views.py", line 135, in permission_denied
raise exceptions.PermissionDenied()
PermissionDenied
Any one faced this issue before? is there a way to return 403 with permission denied message without the app crashing?
Update:
As suggested below that get_seralizer_class() could be causing the problem, it is highly the reason why am facing this error. But, what alternatives do I have to build a dynamic seralizer class method similar to the below?
def get_serializer_class(self):
# decide on which seralizer to use
if u'create_guest' in self.action_map.itervalues():
return UserGuestSerializer
if u'create_user' in self.action_map.itervalues():
return PublicUserSerializer
obj = self.get_object()
if self.request.user.id == obj.id:
if u'set_password' in self.action_map.itervalues():
return PasswordSerializer
return PrivateUserSerializer
return PublicUserSerializer

You appear to be using a custom .get_serializer_class() method that is calling .get_object() for some reason.
File "/Users/mo/Projects/pythonic/dl-env/dlap/apps/account/views.py", line 96, in get_serializer_class
obj = self.get_object()
This is causing the per-object permission checks to be re-run when the Browsable API response is being rendered. Is it possible to reconsider your get_serializer_class implementation?
Edit: Note that you can probably simply inspect self.kargs['pk'] rather than actually calling through to get_object. It doesn't look like you need to perform the full object retrieval in order to make the ownership check.

Related

add user_id attribute in AuthenticationMiddleware | Django

I have a following question regarding Django authentication middleware:
class AuthenticationMiddleware(MiddlewareMixin):
def process_request(self, request):
assert hasattr(request, 'session'), (
"The Django authentication middleware requires session middleware "
"to be installed. Edit your MIDDLEWARE setting to insert "
"'django.contrib.sessions.middleware.SessionMiddleware' before "
"'django.contrib.auth.middleware.AuthenticationMiddleware'."
)
request.user = SimpleLazyObject(lambda: get_user(request))
As you can see here middleware calls method get_user from backend (in my case simple_jwt) and puts this method in a SimpleLazyObject in order to evaluate later.
def get_user(self, validated_token):
"""
Attempts to find and return a user using the given validated token.
"""
try:
user_id = validated_token[api_settings.USER_ID_CLAIM]
except KeyError:
raise InvalidToken(_('Token contained no recognizable user identification'))
try:
user = User.objects.get(**{api_settings.USER_ID_FIELD: user_id})
except User.DoesNotExist:
raise AuthenticationFailed(_('User not found'), code='user_not_found')
if not user.is_active:
raise AuthenticationFailed(_('User is inactive'), code='user_inactive')
return user
What I want to do is to keep request.user = SimpleLazyObject(lambda: get_user(request)) in order to provide user instance for apps that uses it but for my custom apps I want to add something like
pseudocode
request.user_id = user_id from user (user_id = validated_token[api_settings.USER_ID_CLAIM])
in order to not query database each and every request for user object in case I need only user_id which I already have directly in get_user method in backend.
Question – how to pass user_id from get_user() to AuthenticationMiddleware.process_request() and set request.user_id attribute to request without evaluating SimpleLazyObject?
Strangelly i can't assign attributes to request in class JWTAuthentication(authentication.BaseAuthentication): where get_user() is belong
Thank you.
Internal Server Error: /auth/users/me/
Traceback (most recent call last):
File "C:\ProgramData\Miniconda3\envs\entropy\lib\site-packages\asgiref\sync.py", line 330, in thread_handler
raise exc_info[1]
File "C:\ProgramData\Miniconda3\envs\entropy\lib\site-packages\django\core\handlers\exception.py", line 38, in inner
response = await get_response(request)
File "C:\ProgramData\Miniconda3\envs\entropy\lib\site-packages\django\utils\deprecation.py", line 126, in __acall__
response = await sync_to_async(
File "C:\ProgramData\Miniconda3\envs\entropy\lib\site-packages\asgiref\sync.py", line 296, in __call__
ret = await asyncio.wait_for(future, timeout=None)
File "C:\ProgramData\Miniconda3\envs\entropy\lib\asyncio\tasks.py", line 440, in wait_for
return await fut
File "C:\ProgramData\Miniconda3\envs\entropy\lib\site-packages\asgiref\current_thread_executor.py", line 23, in run
result = self.fn(*self.args, **self.kwargs)
File "C:\ProgramData\Miniconda3\envs\entropy\lib\site-packages\asgiref\sync.py", line 334, in thread_handler
return func(*args, **kwargs)
File "C:\ProgramData\Miniconda3\envs\entropy\lib\site-packages\django\contrib\auth\middleware.py", line 26, in process_request
request.user_id = _get_user_session_key(request)
File "C:\ProgramData\Miniconda3\envs\entropy\lib\site-packages\django\contrib\auth\__init__.py", line 58, in _get_user_session_key
return get_user_model()._meta.pk.to_python(request.session[SESSION_KEY])
File "C:\ProgramData\Miniconda3\envs\entropy\lib\site-packages\django\contrib\sessions\backends\base.py", line 65, in __getitem__
return self._session[key]
KeyError: '_auth_user_id'
You already have the user id available. It's decoded from the session inside auth.get_user() and you can just copy that to your own MiddleWare:
from django.contrib.auth import _get_user_session_key
request.user_id = _get_user_session_key(request)
This is a Django private API, not sure why they kept it private. But you can also just copy the one liner it implements:
request.user_id = get_user_model()._meta.pk.to_python(
request.session[SESSION_KEY]
)

Django Rest Framework APIClient not handling exceptions during tests

I'm testing an API endpoint that is supposed to raise a ValidationError in a Django model (note that the exception is a Django exception, not DRF, because it's in the model).
from rest_framework.test import APITestCase
class TestMyView(APITestCase):
# ...
def test_bad_request(self):
# ...
response = self.client.post(url, data)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
However, my test errors out with an exception instead of passing. It doesn't even fail getting a 500 instead of 400, it doesn't get there at all. Isn't DRF's APIClient supposed to handle every exception? I've search online but found nothing. I've read that DRF doesn't handle Django's native ValidationError, but still that doesn't explain why I am not even getting a 500. Any idea what I'm doing wrong?
Full stack trace:
E
======================================================================
ERROR: test_cannot_create_duplicate_email (organizations.api.tests.test_contacts.TestContactListCreateView)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/code/organizations/api/tests/test_contacts.py", line 98, in test_cannot_create_duplicate_email
response = self.jsonapi_post(self.url(new_partnership), data)
File "/code/config/tests/base.py", line 166, in jsonapi_post
url, data=json.dumps(data), content_type=content_type)
File "/usr/local/lib/python3.7/site-packages/rest_framework/test.py", line 300, in post
path, data=data, format=format, content_type=content_type, **extra)
File "/usr/local/lib/python3.7/site-packages/rest_framework/test.py", line 213, in post
return self.generic('POST', path, data, content_type, **extra)
File "/usr/local/lib/python3.7/site-packages/rest_framework/test.py", line 238, in generic
method, path, data, content_type, secure, **extra)
File "/usr/local/lib/python3.7/site-packages/django/test/client.py", line 422, in generic
return self.request(**r)
File "/usr/local/lib/python3.7/site-packages/rest_framework/test.py", line 289, in request
return super(APIClient, self).request(**kwargs)
File "/usr/local/lib/python3.7/site-packages/rest_framework/test.py", line 241, in request
request = super(APIRequestFactory, self).request(**kwargs)
File "/usr/local/lib/python3.7/site-packages/django/test/client.py", line 503, in request
raise exc_value
File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/usr/local/lib/python3.7/site-packages/django/core/handlers/base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/usr/local/lib/python3.7/site-packages/django/core/handlers/base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/usr/local/lib/python3.7/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "/usr/local/lib/python3.7/site-packages/django/views/generic/base.py", line 71, in view
return self.dispatch(request, *args, **kwargs)
File "/usr/local/lib/python3.7/site-packages/rest_framework/views.py", line 495, in dispatch
response = self.handle_exception(exc)
File "/usr/local/lib/python3.7/site-packages/rest_framework/views.py", line 455, in handle_exception
self.raise_uncaught_exception(exc)
File "/usr/local/lib/python3.7/site-packages/rest_framework/views.py", line 492, in dispatch
response = handler(request, *args, **kwargs)
File "/usr/local/lib/python3.7/site-packages/rest_framework/generics.py", line 244, in post
return self.create(request, *args, **kwargs)
File "/usr/local/lib/python3.7/site-packages/rest_framework/mixins.py", line 21, in create
self.perform_create(serializer)
File "/usr/local/lib/python3.7/site-packages/rest_framework/mixins.py", line 26, in perform_create
serializer.save()
File "/usr/local/lib/python3.7/site-packages/rest_framework/serializers.py", line 214, in save
self.instance = self.create(validated_data)
File "/code/organizations/api/serializers.py", line 441, in create
'partnership': self.context['partnership']
File "/usr/local/lib/python3.7/site-packages/rest_framework/serializers.py", line 943, in create
instance = ModelClass._default_manager.create(**validated_data)
File "/usr/local/lib/python3.7/site-packages/django/db/models/manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/usr/local/lib/python3.7/site-packages/django/db/models/query.py", line 422, in create
obj.save(force_insert=True, using=self.db)
File "/code/organizations/models.py", line 278, in save
self.full_clean()
File "/usr/local/lib/python3.7/site-packages/django/db/models/base.py", line 1203, in full_clean
raise ValidationError(errors)
django.core.exceptions.ValidationError: {'__all__': ['Supplier contact emails must be unique per organization.']}
Question: Isn't DRF's APIClient supposed to handle every exception?
Answer: No. It's a test client, it won't handle any uncaught exceptions, that's how test clients work. Test clients propagate the exception so that the test fails with a "crash" when an exception isn't caught. You can test that exceptions are raised and uncaught with self.assertRaises
Question: The APIView should return HTTP_400_BAD_REQUEST when I raise a ValidationError but the exception isn't caught.
Answer:
You should look at the source code for APIView.
Inside the dispatch() method, all exceptions raised while creating the response object are caught and the method handle_exception() is called.
Your exception is a ValidationError. The crucial lines are:
exception_handler = self.get_exception_handler()
context = self.get_exception_handler_context()
response = exception_handler(exc, context)
if response is None:
self.raise_uncaught_exception(exc)
If you haven't changed settings.EXCEPTION_HANDLER, you get the default DRF exception handler, source code here.
If handles Http404, PermissionDenied and APIException. The APIView itself actually also handles AuthenticationFailed and NotAuthenticated. But not ValidationError. So it returns None and therefore the view raises your ValidationError which stops your test.
You see that in your traceback:
File "/usr/local/lib/python3.7/site-packages/rest_framework/views.py", line 455, in handle_exception
self.raise_uncaught_exception(exc)
You can decide to handle more exceptions than the default ones handled by DRF, you can read this on custom exception handling.
EDIT: You can also raise rest_framework.exceptions.ValidationError instead of the standard Django ValidationError. That is an APIException and therefore will be handled by DRF as a HTTP400_BAD_REQUEST. [1]
Side note: Luckily DRF doesn't catch every single exception! If there's a serious flaw in your code you actually want your code to "crash" and produce an error log and your server to return a HTTP 500. Which is what happens here. The response would be an HTTP 500 if this wasn't the test client.
[1]https://github.com/encode/django-rest-framework/blob/3.9.0/rest_framework/exceptions.py#L142
Something in your code is causing a python error which is halting execution before your POST request can return a valid HTTP response. Your code doesn't even reach the line self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) because there is no response.
If you're calling your tests in the normal way with ./manage.py test then you should see the traceback and be able to narrow down what caused the error.
Django >3.0
Starting with Django 3.0, Client constructor takes raise_request_exception parameter. Set it False and response 500 will returned instead of raising an exception.
Source:
https://docs.djangoproject.com/en/3.2/releases/3.0/#tests
self.client = Client(raise_request_exception=False)
Django <3.0
There is a workaround for this for Django 2.2 and earlier.
TL;DR:
Just mock the store_exc_info method of Client class.
from unittest import mock
class TestMyView(APITestCase):
...
def test_server_error(self):
mock.patch("django.test.client.Client.store_exc_info")
self.client.post("/url/, data)
...
Now, the client will return regular response object with status code = 500.
Explanation:
Django's Test client always raises exceptions, even if they were wrapped in 500 Server error response.
Client connects its method called store_exc_info to the got_request_exception Django's signal (source: https://github.com/django/django/blob/3.2.5/django/test/client.py#L712)
got_request_exception.connect(self.store_exc_info, dispatch_uid=exception_uid)
This method saves an exception info as self.exc_info. This attribute is later tested if its None. If it is, then error is raised. If not, response is normally returned (source: https://github.com/django/django/blob/2.2.24/django/test/client.py#L500)
Mocking the self.store_exc_info makes it do nothing, so exception info is not stored - therefore it's None later :)

Django test case ValueError: The given username must be set

I am testing a Django application, for its user sign-up feature, whether the posted data is correct and post request executes successfully.
In views.py, the Class CustomerSignUpView
class CustomerSignUpView(View):
def post(self, request):
name_r = request.POST.get('customer_username')
password_r = request.POST.get('customer_password')
email_r = request.POST.get('customer_email')
contact_number_r = request.POST.get('customer_contact_number')
profile_picture_r = request.POST.get('customer_profile_picture')
if checkemail(email_r):
# receiving an error here in TEST CASE not in actual program execution
c = User(username=name_r, password=password_r, email=email_r)
c.save()
p = Profile(user=c, phone_number=contact_number_r, profile_picture=profile_picture_r)
p.save()
return render(request, 'catalog/customer_login.html')
else:
return render(request, 'catalog/customer_signup.html')
def get(self, request):
return render(request, 'catalog/customer_signup.html')
This is the test case for user account creation:
class CustomerSignUpViewTest(TestCase):
"""
Test case for User Sign in
"""
def test_registration_view_post_success(self):
"""
A ``POST`` to the ``customer_signup`` view with valid data properly
creates a new user and issues a redirect.
"""
data = {
'username': 'testuser1',
'password': '1X<ISRUkw+tuK',
'email': 'foobar#test.com',
'phone_number': '9876543210',
}
response = self.client.post(reverse('customer_signup'), data, follow=True)
self.assertEqual(response.status_code, 200)
self.assertTrue(response.url.startswith('/catalog/customer_login/'))
The test encounters the following error: ValueError('The given username must be set')
Error
Traceback (most recent call last):
File "/Users/sndtcsi/PycharmProjects/Library/catalog/tests.py", line 54, in test_registration_view_post_success
response = self.client.post(reverse('customer_signup'), data, follow=True)
File "/Users/sndtcsi/PycharmProjects/Library/venv/lib/python3.7/site-packages/django/test/client.py", line 535, in post
response = super().post(path, data=data, content_type=content_type, secure=secure, **extra)
File "/Users/sndtcsi/PycharmProjects/Library/venv/lib/python3.7/site-packages/django/test/client.py", line 349, in post
secure=secure, **extra)
File "/Users/sndtcsi/PycharmProjects/Library/venv/lib/python3.7/site-packages/django/test/client.py", line 414, in generic
return self.request(**r)
File "/Users/sndtcsi/PycharmProjects/Library/venv/lib/python3.7/site-packages/django/test/client.py", line 495, in request
raise exc_value
File "/Users/sndtcsi/PycharmProjects/Library/venv/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/Users/sndtcsi/PycharmProjects/Library/venv/lib/python3.7/site-packages/django/core/handlers/base.py", line 126, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/Users/sndtcsi/PycharmProjects/Library/venv/lib/python3.7/site-packages/django/core/handlers/base.py", line 124, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Users/sndtcsi/PycharmProjects/Library/venv/lib/python3.7/site-packages/django/views/generic/base.py", line 68, in view
return self.dispatch(request, *args, **kwargs)
File "/Users/sndtcsi/PycharmProjects/Library/venv/lib/python3.7/site-packages/django/views/generic/base.py", line 88, in dispatch
return handler(request, *args, **kwargs)
File "/Users/sndtcsi/PycharmProjects/Library/catalog/views.py", line 107, in post
c = User.objects.create_user(username=name_r, password=password_r, email=email_r)
File "/Users/sndtcsi/PycharmProjects/Library/venv/lib/python3.7/site-packages/django/contrib/auth/models.py", line 150, in create_user
return self._create_user(username, email, password, **extra_fields)
File "/Users/sndtcsi/PycharmProjects/Library/venv/lib/python3.7/site-packages/django/contrib/auth/models.py", line 139, in _create_user
raise ValueError('The given username must be set')
While my sign-up feature works perfectly, the test execution shows that the username is not set. I do not understand why that is happening.
You are using bad key in your TestCase. You are trying to get customer_username in the form in your view, but you are actually posting username key in the data in your TestCase. To make this work you should make this lines to use the same keys:
name_r = request.POST['customer_username']
and
'username': 'testuser1',
The same problems are with all another forms in this your code.

Django Tastypie: "error_message": "'bool' object has no attribute 'read'"

I am using Backbone.js + Tastypie + Django and am trying to save a model using patch = true to update the points on a model, like
this.save({
points: newPoints
}, {
patch: true
});
This issues a PUT request as it should with the request payload
points: 105
However, I get a 500 error message
{"error_message": "'bool' object has no attribute 'read'", "traceback": "Traceback (most recent call last):
File \"/Users/me/.virtualenvs/project/lib/python2.7/site-packages/tastypie/resources.py\", line 217, in wrapper
response = callback(request, *args, **kwargs)
File \"/Users/me/.virtualenvs/project/lib/python2.7/site-packages/tastypie/resources.py\", line 468, in dispatch_detail
return self.dispatch('detail', request, **kwargs)
File \"/Users/me/.virtualenvs/project/lib/python2.7/site-packages/tastypie/resources.py\", line 491, in dispatch
response = method(request, **kwargs)
File \"/Users/me/.virtualenvs/project/lib/python2.7/site-packages/tastypie/resources.py\", line 1656, in patch_detail
self.update_in_place(request, bundle, deserialized)
File \"/Users/me/.virtualenvs/project/lib/python2.7/site-packages/tastypie/resources.py\", line 1679, in update_in_place
return self.obj_update(bundle=original_bundle, **kwargs)
File \"/Users/me/.virtualenvs/project/lib/python2.7/site-packages/tastypie/resources.py\", line 2209, in obj_update
bundle = self.full_hydrate(bundle)
File \"/Users/me/.virtualenvs/project/lib/python2.7/site-packages/tastypie/resources.py\", line 909, in full_hydrate
value = field_object.hydrate(bundle)
File \"/Users/me/.virtualenvs/project/lib/python2.7/site-packages/tastypie/fields.py\", line 382, in hydrate
value = make_aware(parse(value))
File \"/Users/me/.virtualenvs/project/lib/python2.7/site-packages/dateutil/parser.py\", line 720, in parse
return DEFAULTPARSER.parse(timestr, **kwargs)
File \"/Users/me/.virtualenvs/project/lib/python2.7/site-packages/dateutil/parser.py\", line 308, in parse
res = self._parse(timestr, **kwargs)
File \"/Users/me/.virtualenvs/project/lib/python2.7/site-packages/dateutil/parser.py\", line 356, in _parse
l = _timelex.split(timestr)
File \"/Users/me/.virtualenvs/project/lib/python2.7/site-packages/dateutil/parser.py\", line 150, in split
return list(cls(s))
File \"/Users/me/.virtualenvs/project/lib/python2.7/site-packages/dateutil/parser.py\", line 147, in next
return self.__next__() # Python 2.x support
File \"/Users/me/.virtualenvs/project/lib/python2.7/site-packages/dateutil/parser.py\", line 141, in __next__
token = self.get_token()
File \"/Users/me/.virtualenvs/project/lib/python2.7/site-packages/dateutil/parser.py\", line 72, in get_token
nextchar = self.instream.read(1)
AttributeError: 'bool' object has no attribute 'read'
"}
Here is my model resource for UserProfile
class UserProfileResource(ModelResource):
"""A resource for the UserProfile model."""
class Meta:
queryset = UserProfile.objects.all()
resource_name = 'userprofile'
authorization = Authorization()
excludes = ['field_to_exclude']
always_return_data = True
Does anyone have tips on how to debug this error?
I had a field which was a datetimefield which was null, and instead of showing up as a a datetime in the api call, is showed up as a boolean. I'm not sure why this happened, but I think this is a bug in tastypie, or I misunderstood something about the configuration, or both.
I excluded this field from the tastypie resource and I was able to PUT and PATCH successfully to the model.

BaseDeleteView throws AttributeError (render_to_response missing)

I try to implement a view based on BaseDeleteView for a website that acts as a frontend to an REST backend. Both sides communicate over HTTP requests. What I want to achieve is that I send a GET request to an activation URI (send per email after registration). Inside this view I first send a HTTP request to a backend, and then delete the activation object from the database of the frontend. I don't want to have a confirmation page, so DeleteView is not possible.
class ActivationView(BaseDeleteView):
success_url = "/activation/success/"
def get_object(self, queryset=None):
uuid = self.kwargs['uuid']
try:
obj = AccountRegistration.objects.get(uuid=uuid)
except ObjectDoesNotExist:
raise Http404('Registration not found.')
return obj
def delete(self, request, *args, **kwargs):
obj = self.get_obj()
if obj.expire_date < datetime.now():
obj.delete()
raise Http404('Registration expired.')
# send a http request to the backend
t = Transaction('/activate/%s/' % obj.account_name)
t.emit()
# delete the object
obj.delete()
# and redirect the request
return HttpResponseRedirect(self.get_success_url())
My urls.py looks like that:
url(r'^activate/(?P<uuid>\w+)/$',
ActivationView.as_view(), name="account-activate"),
But I get the following error:
Traceback (most recent call last):
File "/home/crito/.pythonbrew/venvs/Python-2.7.2/thirty-web/lib/python2.7/site-packages/django/contrib/staticfiles/handlers.py", line 68, in __call__
return self.application(environ, start_response)
File "/home/crito/.pythonbrew/venvs/Python-2.7.2/thirty-web/lib/python2.7/site-packages/django/core/handlers/wsgi.py", line 272, in __call__
response = self.get_response(request)
File "/home/crito/.pythonbrew/venvs/Python-2.7.2/thirty-web/lib/python2.7/site-packages/django/core/handlers/base.py", line 169, in get_response
response = self.handle_uncaught_exception(request, resolver, sys.exc_info())
File "/home/crito/.pythonbrew/venvs/Python-2.7.2/thirty-web/lib/python2.7/site-packages/django/core/handlers/base.py", line 203, in handle_uncaught_exception
return debug.technical_500_response(request, *exc_info)
File "/home/crito/.pythonbrew/venvs/Python-2.7.2/thirty-web/lib/python2.7/site-packages/django/core/handlers/base.py", line 111, in get_response
response = callback(request, *callback_args, **callback_kwargs)
File "/home/crito/.pythonbrew/venvs/Python-2.7.2/thirty-web/lib/python2.7/site-packages/django/views/generic/base.py", line 47, in view
return self.dispatch(request, *args, **kwargs)
File "/home/crito/.pythonbrew/venvs/Python-2.7.2/thirty-web/lib/python2.7/site-packages/django/views/generic/base.py", line 68, in dispatch
return handler(request, *args, **kwargs)
File "/home/crito/.pythonbrew/venvs/Python-2.7.2/thirty-web/lib/python2.7/site-packages/django/views/generic/detail.py", line 100, in get
return self.render_to_response(context)
AttributeError: 'ActivationView' object has no attribute 'render_to_response'
In my eyes it shouldn't even call render_to_response. Any ideas?
If you want to leave out the confirmation page, just call your DeleteView directly with POST. This is most desirable as the deletion of an object should be protected by csrf.
You've inherited from BaseDeleteView, which as the documentation states, doesn't include the TemplateResponseMixin - ie all the bits that are to do with rendering a response.
Inherit from DeleteView instead.