I'm using Tastypie to POST and create a new Resource, which works fine:
class TestResource(ModelResource):
class Meta:
queryset = MemberParticipant.objects.all()
resource_name = 'participant'
allowed_methods = ['post']
def obj_create(self, bundle, request=None, **kwargs):
"""
Creates a new object based on the provided data.
This method overwrites the resource create
as we need to preform extra method calls.
"""
bundle = self.full_hydrate(bundle)
# Check data is valid before trying to create a new resource.
self.is_valid(bundle)
if bundle.errors:
raise ImmediateHttpResponse(response=self.error_response(bundle.request, bundle.errors))
new_user = MemberParticipant.objects.create_user(email=bundle.data['email'],
password=bundle.data['password'])
# Log the user in
email = new_user.email
password = bundle.data['password']
user = authenticate(username=email, password=password)
login(bundle.request, user)
return bundle
I then use in the Meta class always_return_data = True
to always return the created resource in the AJAX call.
However, doing this gives now gives me the following error:
invalid literal for int() with base 10: /django-env/lib/python2.7/site-packages/tastypie/fields.py\", line 234, in convert\n return int(value)\n\nValueError: invalid literal for int() with base 10: ''\n"}
Why?
Full error traceback:
{
"error_message": "invalid literal for int() with base 10: ''",
"traceback": "Traceback (most recent call last):
File \"/Users/user/Documents/workspace/test/django-env/lib/python2.7/site-packages/tastypie/resources.py\", line 195, in wrapper
response = callback(request, *args, **kwargs)
File \"/Users/user/Documents/workspace/test/django-env/lib/python2.7/site-packages/tastypie/resources.py\", line 426, in dispatch_list
return self.dispatch('list', request, **kwargs)
File \"/Users/user/Documents/workspace/test/django-env/lib/python2.7/site-packages/tastypie/resources.py\", line 458, in dispatch
response = method(request, **kwargs)
File \"/Users/user/Documents/workspace/test/django-env/lib/python2.7/site-packages/tastypie/resources.py\", line 1326, in post_list
updated_bundle = self.full_dehydrate(updated_bundle)
File \"/Users/user/Documents/workspace/test/django-env/lib/python2.7/site-packages/tastypie/resources.py\", line 832, in full_dehydrate
bundle.data[field_name] = field_object.dehydrate(bundle, for_list=for_list)
File \"/Users/user/Documents/workspace/test/django-env/lib/python2.7/site-packages/tastypie/fields.py\", line 135, in dehydrate
return self.convert(current_object)
File \"/Users/user/Documents/workspace/test/django-env/lib/python2.7/site-packages/tastypie/fields.py\", line 234, in convert
return int(value)
ValueError: invalid literal for int() with base 10: ''"
}
In short, you are missing bundle.obj
and @mariodev is correct that if you just assign the object from create_user()
to this bundle object it'll work. But take a step back and there is an easier way.
The purpose of ModelResource.obj_create()
is to create a new model object, that object is stored as bundle.obj
, and Tastypie has all the code to perform this. The only task you are doing differently is to login a newly created user. Yet you override obj_create()
, duplicate some Tastypie code and skip out on a bunch more. You check validation and check for errors, but ModelResource
will also check authorization and save related models, which you aren't doing. Tastypie also builds up bundle.obj
differently. Well, specifically you aren't building that object, but if you were it'd only contain email and password. What if the user submitted their name and other data? (Depends on your input code of course, but here you are creating a brittle implementation assumption.) Point is, you can have Tastypie do all the work and inject your log-in logic more simply.
class TestResource(ModelResource):
...
def obj_create(self, bundle, **kwargs):
bundle = super(TestResource, self).obj_create(bundle, **kwargs)
user = authenticate(username=bundle.obj.email, password=bundle.obj.password)
if user is not None and user.is_active:
login(bundle.request, user)
return bundle
Two more points: Perhaps at this point you could do username=bundle.obj.username
if your model has this field. I took the user/active check from Django's docs here.