def test_related_resource_authorization(self): resource = api.canonical_resource_for('notes') request = MockRequest() request.GET = {'format': 'json'} request.method = 'POST' request.body = '{"content": "The cat is back. The dog coughed him up out back.", "created": "2010-04-03 20:05:00", "is_active": true, "slug": "cat-is-back", "title": "The Cat Is Back", "updated": "2010-04-03 20:05:00", "author": null}' resp = resource.post_list(request) self.assertEqual(resp.status_code, 201) self.assertEqual( User.objects.get(id=self.user.id).username, 'testy_mctesterson') request = MockRequest() request.GET = {'format': 'json'} request.method = 'POST' request.body = '{"content": "The cat is back. The dog coughed him up out back.", "created": "2010-04-03 20:05:00", "is_active": true, "slug": "cat-is-back-2", "title": "The Cat Is Back", "updated": "2010-04-03 20:05:00", "author": {"id": %s, "username": "******"}}' % self.user.id try: resource.post_list(request) except ImmediateHttpResponse as resp: self.assertEqual(resp.response.status_code, 400) else: self.fail("post_list should raise an ImmediateHttpResponse error") # self.assertEqual(resp.status_code, 201) self.assertEqual( User.objects.get(id=self.user.id).username, 'testy_mctesterson', "User resource is GET-only and so should not be updatable")
def test_many_to_many(self): """ Test a related ToMany resource with a nested full ToMany resource """ self.assertEqual(Person.objects.count(), 0) self.assertEqual(Dog.objects.count(), 0) self.assertEqual(Bone.objects.count(), 0) pr = PersonResource() data = { 'name': 'Joan Rivers', 'dogs': [ { 'name': 'Snoopy', 'bones': [ { 'color': 'white' } ] } ] } request = MockRequest() request.GET = {'format': 'json'} request.method = 'POST' request.path = reverse('api_dispatch_list', kwargs={'resource_name': pr._meta.resource_name, 'api_name': pr._meta.api_name}) request.set_body(json.dumps(data)) resp = pr.post_list(request) self.assertEqual(resp.status_code, 201) self.assertEqual(Person.objects.count(), 1) self.assertEqual(Dog.objects.count(), 1) self.assertEqual(Bone.objects.count(), 1) pk = Person.objects.all()[0].pk request = MockRequest() request.method = 'GET' request.path = reverse('api_dispatch_detail', kwargs={'pk': pk, 'resource_name': pr._meta.resource_name, 'api_name': pr._meta.api_name}) resp = pr.get_detail(request, pk=pk) self.assertEqual(resp.status_code, 200) person = json.loads(resp.content.decode('utf-8')) self.assertEqual(person['name'], 'Joan Rivers') self.assertEqual(len(person['dogs']), 1) dog = person['dogs'][0] self.assertEqual(dog['name'], 'Snoopy') self.assertEqual(len(dog['bones']), 1) bone = dog['bones'][0] self.assertEqual(bone['color'], 'white') request = MockRequest() request.GET = {'format': 'json'} request.method = 'PUT' request.set_body(json.dumps(person)) request.path = reverse('api_dispatch_detail', kwargs={'pk': pk, 'resource_name': pr._meta.resource_name, 'api_name': pr._meta.api_name}) resp = pr.put_detail(request, pk=pk) self.assertEqual(resp.status_code, 204)
def test_related_resource_authorization(self): resource = api.canonical_resource_for('notes') request = MockRequest() request.GET = {'format': 'json'} request.method = 'POST' request.set_body( '{"content": "The cat is back. The dog coughed him up out back.", "created": "2010-04-03 20:05:00", "is_active": true, "slug": "cat-is-back", "title": "The Cat Is Back", "updated": "2010-04-03 20:05:00", "author": null}' ) resp = resource.post_list(request) self.assertEqual(resp.status_code, 201) self.assertEqual( User.objects.get(id=self.user.id).username, 'testy_mctesterson') request = MockRequest() request.GET = {'format': 'json'} request.method = 'POST' request.set_body( '{"content": "The cat is back. The dog coughed him up out back.", "created": "2010-04-03 20:05:00", "is_active": true, "slug": "cat-is-back-2", "title": "The Cat Is Back", "updated": "2010-04-03 20:05:00", "author": {"id": %s, "username": "******"}}' % self.user.id) resp = resource.post_list(request) self.assertEqual(resp.status_code, 201) self.assertEqual(User.objects.get(id=self.user.id).username, 'foobar')
def test_one_to_one(self): """ Test a related ToOne resource with a nested full ToOne resource """ self.assertEqual(Person.objects.count(), 0) self.assertEqual(Company.objects.count(), 0) self.assertEqual(Address.objects.count(), 0) pr = PersonResource() data = { 'name': 'Joan Rivers', 'company': { 'name': 'Yum Yum Pie Factory!', 'address': { 'line': 'Somewhere, Utah' } } } request = MockRequest() request.GET = {'format': 'json'} request.method = 'POST' request.raw_post_data = json.dumps(data) resp = pr.post_list(request) self.assertEqual(resp.status_code, 201) pk = Person.objects.all()[0].pk request = MockRequest() request.method = 'GET' request.path = reverse('api_dispatch_detail', kwargs={ 'pk': pk, 'resource_name': pr._meta.resource_name, 'api_name': pr._meta.api_name }) resp = pr.get_detail(request, pk=pk) self.assertEqual(resp.status_code, 200) person = json.loads(resp.content) self.assertEqual(person['name'], 'Joan Rivers') company = person['company'] self.assertEqual(company['name'], 'Yum Yum Pie Factory!') address = company['address'] self.assertEqual(address['line'], 'Somewhere, Utah') request = MockRequest() request.GET = {'format': 'json'} request.method = 'PUT' request.path = reverse('api_dispatch_detail', kwargs={ 'pk': pk, 'resource_name': pr._meta.resource_name, 'api_name': pr._meta.api_name }) request.raw_post_data = resp.content resp = pr.put_detail(request, pk=pk) self.assertEqual(resp.status_code, 204)
def test_one_to_many(self): """ Test a related ToOne resource with a nested full ToMany resource """ self.assertEqual(Person.objects.count(), 0) self.assertEqual(Company.objects.count(), 0) self.assertEqual(Product.objects.count(), 0) pr = PersonResource() data = { 'name': 'Joan Rivers', 'company': { 'name': 'Yum Yum Pie Factory!', 'products': [ { 'name': 'Tasty Pie' } ] } } request = MockRequest() request.GET = {'format': 'json'} request.method = 'POST' setattr(request, self.body_attr, json.dumps(data)) resp = pr.post_list(request) self.assertEqual(resp.status_code, 201) self.assertEqual(Person.objects.count(), 1) self.assertEqual(Company.objects.count(), 1) self.assertEqual(Product.objects.count(), 1) pk = Person.objects.all()[0].pk request = MockRequest() request.method = 'GET' request.path = reverse('api_dispatch_detail', kwargs={'pk': pk, 'resource_name': pr._meta.resource_name, 'api_name': pr._meta.api_name}) resp = pr.get_detail(request, pk=pk) self.assertEqual(resp.status_code, 200) person = json.loads(resp.content) self.assertEqual(person['name'], 'Joan Rivers') company = person['company'] self.assertEqual(company['name'], 'Yum Yum Pie Factory!') self.assertEqual(len(company['products']), 1) product = company['products'][0] self.assertEqual(product['name'], 'Tasty Pie') request = MockRequest() request.GET = {'format': 'json'} request.method = 'PUT' request.path = reverse('api_dispatch_detail', kwargs={'pk': pk, 'resource_name': pr._meta.resource_name, 'api_name': pr._meta.api_name}) setattr(request, self.body_attr, json.dumps(person)) resp = pr.put_detail(request, pk=pk) self.assertEqual(resp.status_code, 204)
def test_many_to_many_change_nested(self): """ Test a related ToMany resource with a nested full ToMany resource """ self.assertEqual(Person.objects.count(), 0) self.assertEqual(Dog.objects.count(), 0) self.assertEqual(Bone.objects.count(), 0) pr = PersonResource() person = Person.objects.create(name='Joan Rivers') dog = person.dogs.create(name='Snoopy') bone = dog.bones.create(color='white') pk = person.pk request = MockRequest() request.method = 'GET' request.path = reverse('api_dispatch_detail', kwargs={ 'pk': pk, 'resource_name': pr._meta.resource_name, 'api_name': pr._meta.api_name }) resp = pr.get_detail(request, pk=pk) self.assertEqual(resp.status_code, 200) data = json.loads(resp.content.decode('utf-8')) self.assertEqual(data['dogs'][0]['bones'][0]['color'], 'white') # Change just a nested resource via PUT request = MockRequest() request.GET = {'format': 'json'} request.method = 'PUT' data['dogs'][0]['bones'][0]['color'] = 'gray' body = json.dumps(data) request.set_body(body) request.path = reverse('api_dispatch_detail', kwargs={ 'pk': pk, 'resource_name': pr._meta.resource_name, 'api_name': pr._meta.api_name }) resp = pr.put_detail(request, pk=pk) self.assertEqual(resp.status_code, 204) self.assertEqual(Bone.objects.count(), 1) bone = Bone.objects.all()[0] self.assertEqual(bone.color, 'gray')
def patch_details(resource, pk, **kwargs): # Post the extradata element which is attached to a "reverse" OneToOne request = MockRequest() request.method = "PATCH" request.body = json.dumps(kwargs) response = resource.patch_detail(request, pk=pk) return response
def test_create_similar(self): # We submit to job with the related payment included. # Note that on the resource, the payment related resource is defined # On the model, the Job class does not have a payment field, # but it has a reverse relationship defined by the Payment class resource = JobResource() data = { 'name': 'OtherJob', 'payment': { 'scheduled': self.some_time_str } } request = MockRequest() request.GET = {'format': 'json'} request.method = 'POST' request.set_body(json.dumps(data)) resp = resource.post_list(request) self.assertEqual(resp.status_code, 201) self.assertEqual(Job.objects.count(), 2) self.assertEqual(Payment.objects.count(), 2) new_job = Job.objects.all().order_by('-id')[0] new_payment = Payment.objects.all().order_by('-id')[0] self.assertEqual(new_job.name, 'OtherJob') self.assertEqual(new_job, new_payment.job)
def test_reverse_items_relationship(self): order_resource = OrderResource() data = { 'name': 'order1', 'items': [{ 'name': 'car', }, { 'name': 'yacht', }] } request = MockRequest() request.GET = {'format': 'json'} request.method = 'POST' request.path = reverse('api_dispatch_list', kwargs={ 'resource_name': order_resource._meta.resource_name, 'api_name': order_resource._meta.api_name }) request.set_body(json.dumps(data)) resp = order_resource.post_list(request) self.assertEqual(resp.status_code, 201) self.assertEqual(Order.objects.count(), 1) self.assertEqual(OrderItem.objects.count(), 2)
def test_incorrect_uri(self): self.assertEqual(Note.objects.count(), 2) nr = NoteResource() # For this test, we need a ``User`` with the same PK as a ``Note``. note_1 = Note.objects.latest('created') User.objects.create(id=note_1.pk, username='******', email='*****@*****.**', password='******') data = { # This URI is flat-out wrong (wrong resource). # This should cause the request to fail. 'author': '/v1/notes/{0}/'.format(note_1.pk), 'title': 'Nopenopenope', 'slug': 'invalid-request', 'content': "This shouldn't work.", 'is_active': True, } request = MockRequest() request.GET = {'format': 'json'} request.method = 'POST' request.set_body(json.dumps(data)) with self.assertRaises(NotFound) as cm: nr.post_list(request) self.assertEqual( str(cm.exception), "An incorrect URL was provided '/v1/notes/2/' for the 'UserResource' resource." ) self.assertEqual(Note.objects.count(), 2)
def test_patch_detail_dont_update_related_without_permission(self): """ When fields are excluded the value of the field should not be set to a default value if updated by bmga. """ resource = NoteResource() note = Note.objects.create(author_id=1) user = User.objects.get(pk=1) self.assertEqual(user.password, 'this_is_not_a_valid_password_string') request = MockRequest() request.GET = {'format': 'json'} request.method = 'PATCH' request.path = "/v1/note/%(pk)s/" % {'pk': note.pk} data = { 'author': { 'id': 1, 'username': '******', 'email': '*****@*****.**', } } request.set_body(json.dumps(data)) resp = resource.patch_detail(request, pk=note.pk) self.assertEqual(resp.status_code, 202) user2 = User.objects.get(pk=1) self.assertEqual(user2.email, '*****@*****.**') self.assertEqual(user2.password, 'this_is_not_a_valid_password_string')
def test_patch_to_one(self): resource = FullCategoryResource() cat1 = Category.objects.create(name='Dad') cat2 = Category.objects.create(parent=cat1, name='Child') request = MockRequest() request.GET = {'format': 'json'} request.method = 'PATCH' request.path = "/v1/category/%(pk)s/" % {'pk': cat2.pk} data = { 'name': 'Kid' } request.set_body(json.dumps(data)) self.assertEqual(cat2.name, 'Child') resp = resource.patch_detail(request, pk=cat2.pk) self.assertEqual(resp.status_code, 202) cat2 = Category.objects.get(pk=2) self.assertEqual(cat2.name, 'Kid')
def test_correct_setup(self): request = MockRequest() request.GET = {'format': 'json'} request.method = 'GET' # Verify the explicit 'through' relationships has been created correctly resource = api.canonical_resource_for('taggabletag') resp = resource.wrap_view('dispatch_detail')(request, pk=self.taggabletag_1.pk) data = json.loads(resp.content) self.assertEqual(resp.status_code, 200) self.assertEqual(data['tag'], '/v1/tag/1/') self.assertEqual(data['taggable'], '/v1/taggable/1/') resource = api.canonical_resource_for('taggable') resp = resource.wrap_view('dispatch_detail')(request, pk=self.taggable_1.pk) data = json.loads(resp.content) self.assertEqual(resp.status_code, 200) self.assertEqual(data['name'], 'exam') resource = api.canonical_resource_for('tag') request.path = "/v1/tag/%(pk)s/" % {'pk': self.tag_1.pk} resp = resource.wrap_view('dispatch_detail')(request, pk=self.tag_1.pk) data = json.loads(resp.content) self.assertEqual(resp.status_code, 200) self.assertEqual(data['name'], 'important') # and check whether the extradata is present self.assertEqual(data['extradata']['name'], u'additional')
def test_one_to_many(self): # Sanity checks. self.assertEqual(Note.objects.count(), 2) self.assertEqual(MediaBit.objects.count(), 0) fnr = FreshNoteResource() data = { 'title': 'Create with related URIs', 'slug': 'create-with-related-uris', 'content': 'Some content here', 'is_active': True, 'media_bits': [{ 'title': 'Picture #1' }] } request = MockRequest() request.GET = {'format': 'json'} request.method = 'POST' request.raw_post_data = json.dumps(data) resp = fnr.post_list(request) self.assertEqual(resp.status_code, 201) self.assertEqual(Note.objects.count(), 3) note = Note.objects.latest('created') self.assertEqual(note.media_bits.count(), 1) self.assertEqual(note.media_bits.all()[0].title, u'Picture #1')
def test_cannot_access_user_resource(self): resource = api.canonical_resource_for('users') request = MockRequest() request.GET = {'format': 'json'} request.method = 'PUT' request.set_body('{"username": "******"}') resp = resource.wrap_view('dispatch_detail')(request, pk=self.user.pk) self.assertEqual(resp.status_code, 405) self.assertEqual(User.objects.get(id=self.user.id).username, self.user.username)
def test_no_save_m2m_related(self): """ When saving an object with a M2M field, don't save that related object's related objects. """ cg1 = ContactGroup.objects.create(name='The Inebriati') cg2 = ContactGroup.objects.create(name='The Stone Cutters') c1 = Contact.objects.create(name='foo') c2 = Contact.objects.create(name='bar') c2.groups.add(cg1, cg2) c3 = Contact.objects.create(name='baz') c3.groups.add(cg1) self.assertEqual(list(c1.groups.all()), []) self.assertEqual(list(c2.groups.all()), [cg1, cg2]) self.assertEqual(list(c3.groups.all()), [cg1]) data = { 'name': c1.name, 'groups': [reverse('api_dispatch_detail', kwargs={'api_name': 'v1', 'resource_name': 'contactgroup', 'pk': cg1.pk})], } resource = api.canonical_resource_for('contact') request = MockRequest() request.GET = {'format': 'json'} request.method = 'PUT' request._load_post_and_files = lambda *args, **kwargs: None request.set_body(json.dumps(data)) with self.withAssertNumQueriesLessThan(9): response = resource.wrap_view('dispatch_detail')(request, pk=c1.pk) self.assertEqual(response.status_code, 204, response.content) new_contacts = Contact.objects.all() new_c1 = new_contacts[0] new_c2 = new_contacts[1] new_c3 = new_contacts[2] self.assertEqual(new_c1.name, c1.name) self.assertEqual(new_c1.id, c1.id) self.assertEqual(list(new_c1.groups.all()), [cg1]) self.assertEqual(new_c2.id, c2.id) self.assertEqual(list(new_c2.groups.all()), [cg1, cg2]) self.assertEqual(new_c3.id, c3.id) self.assertEqual(list(new_c3.groups.all()), [cg1]) new_cg1 = ContactGroup.objects.get(id=cg1.id) new_cg2 = ContactGroup.objects.get(id=cg2.id) self.assertEqual(list(new_cg1.members.all()), [new_c1, new_c2, new_c3]) self.assertEqual(list(new_cg2.members.all()), [new_c2])
def test_apifielderror_missing_not_null_field(self): """ Posting a new detail with no related objects should require one query to save the object """ resource = api.canonical_resource_for('product') request = MockRequest() body = json.dumps({}) request.set_body(body) with self.assertRaises(ApiFieldError): resource.post_list(request)
def test_one_query_for_post_list(self): """ Posting a new detail with no related objects should require one query to save the object """ resource = api.canonical_resource_for('category') request = MockRequest() body = json.dumps({'name': 'Foo', 'parent': None}) request.set_body(body) with self.assertNumQueries(1): resource.post_list(request)
def test_resource_passes_request(self): note = Note.objects.create( title='All aboard the rest train', content='Sometimes it is just better to lorem ipsum') uri = '/api/v1/notes/1/' request = MockRequest() request.GET = {'format': 'json'} request.method = 'GET' result = self.resource.get_via_uri(uri, request=request) self.assertEqual(result, note)
def test_m2m_put_prefetch(self): resource = api.canonical_resource_for('forum') request = MockRequest() request.GET = {'format': 'json'} request.method = 'PUT' forum = Forum.objects.create() user_data_1 = { 'username': '******', 'email': '*****@*****.**', 'password': '******', } user_data_2 = { 'username': '******', 'email': '*****@*****.**', 'password': '******', } user_data_3 = { 'username': '******', 'email': '*****@*****.**', 'password': '******', } forum_data = { 'members': [ user_data_1, user_data_2, ], 'moderators': [ user_data_3, ] } request.set_body(json.dumps(forum_data)) request.path = reverse('api_dispatch_detail', kwargs={ 'pk': forum.pk, 'resource_name': resource._meta.resource_name, 'api_name': resource._meta.api_name }) response = resource.put_detail(request) self.assertEqual(response.status_code, 200) data = json.loads(response.content.decode('utf-8')) # Check that the query does what it's supposed to and only the return value is wrong self.assertEqual(User.objects.count(), 3) self.assertEqual(len(data['members']), 2) self.assertEqual(len(data['moderators']), 1)
def test_related_resource_partial_update(self): note = Note.objects.create(author=self.user, content="Note Content", title="Note Title", slug="note-title") resource = api.canonical_resource_for('notes') request = MockRequest() request.GET = {'format': 'json'} request.method = 'PUT' request.raw_post_data = '{"content": "The note has been changed"}' resp = resource.put_detail(request, pk=note.pk) self.assertEqual(resp.status_code, 201) self.assertEqual( Note.objects.get(id=note.id).content, "The note has been changed")
def setUp(self): self.resource = NoteResource() self.request = MockRequest() self.request.path = '/api/v1/notes/' self.request.GET = {'limit': '100'} user = User.objects.create_user('foo', 'pass') for i in range(0, 200): Note.objects.create(author=user, title='Note #%s' % i, slug='note-%s' % i) super(ResourceProfilingTestCase, self).setUp()
def test_put_null(self): resource = api.canonical_resource_for('category') request = MockRequest() request.GET = {'format': 'json'} request.method = 'PUT' request.set_body('{"parent": null, "name": "Son"}') # Before the PUT, there should be a parent. self.assertEqual(Category.objects.get(pk=self.child_cat_1.pk).parent.pk, self.parent_cat_1.pk) # After the PUT, the parent should be ``None``. resp = resource.put_detail(request, pk=self.child_cat_1.pk) self.assertEqual(resp.status_code, 204) self.assertEqual(Category.objects.get(pk=self.child_cat_1.pk).name, 'Son') self.assertEqual(Category.objects.get(pk=self.child_cat_1.pk).parent, None)
def test_no_save_m2m_unchanged_existing_data_persists(self): """ Data should persist when posting an updated detail object with unchanged reverse related objects. """ person = Person.objects.create(name='Ryan') dog = Dog.objects.create(name='Wilfred', owner=person) bone1 = Bone.objects.create(color='White', dog=dog) bone2 = Bone.objects.create(color='Grey', dog=dog) self.assertEqual(dog.bones.count(), 2) resource = api.canonical_resource_for('dog') request = MockRequest() request.GET = {'format': 'json'} request.method = 'PUT' request._load_post_and_files = lambda *args, **kwargs: None body_dict = { 'id': dog.id, 'name': 'Wilfred', 'bones': [{ 'id': bone1.id, 'color': bone1.color }, { 'id': bone2.id, 'color': bone2.color }] } request.set_body(json.dumps(body_dict)) with self.assertNumQueries(13 if django.VERSION >= (1, 9) else 14): resp = resource.wrap_view('dispatch_detail')(request, pk=dog.pk) self.assertEqual(resp.status_code, 204) dog = Dog.objects.all()[0] dog_bones = dog.bones.all() self.assertEqual(len(dog_bones), 2) self.assertEqual(dog_bones[0], bone1) self.assertEqual(dog_bones[1], bone2)
def test_resource_from_uri(self): note_2 = Note.objects.create(title='Generic and such', content='Sometimes it is to lorem ipsum') gfk_field = GenericForeignKeyField( { Note: NoteResource, Quote: QuoteResource }, 'nofield') request = MockRequest() request.GET = {'format': 'json'} request.method = 'GET' self.assertEqual( gfk_field.resource_from_uri(gfk_field.to_class(), '/api/v1/notes/%s/' % note_2.pk, request).obj, note_2)
def make_request(self, method): request = MockRequest() request.GET = {'format': 'json'} request.method = method request.set_body(json.dumps({ 'members': [ self.user_data[0], self.user_data[1], ], 'moderators': [self.user_data[2]], })) request.path = reverse('api_dispatch_detail', kwargs={ 'pk': self.forum.pk, 'resource_name': self.resource._meta.resource_name, 'api_name': self.resource._meta.api_name }) return request
def test_ok_not_null_field_included(self): """ Posting a new detail with no related objects should require one query to save the object """ company = Company.objects.create() resource = api.canonical_resource_for('product') request = MockRequest() body = json.dumps({ 'producer': {'pk': company.pk}, }) request.set_body(body) resp = resource.post_list(request) self.assertEqual(resp.status_code, 201)
def test_reverse_one_to_one_post(self): ed = ExtraData.objects.create(name='ed_name') resource = TagResource() # Post the extradata element which is attached to a "reverse" OneToOne request = MockRequest() request.method = "POST" request.body = json.dumps({ "name": "tag_name", "tagged": [], "extradata": "/v1/extradata/%s/" % ed.pk }) resp = resource.post_list(request) # Assert that the status code is CREATED self.assertEqual(resp.status_code, 201) tag = Tag.objects.get(pk=int(resp['Location'].split("/")[-2])) self.assertEqual(tag.extradata, ed)
def test_correct_relation(self): resource = api.canonical_resource_for('category') request = MockRequest() request.GET = {'format': 'json'} request.method = 'GET' resp = resource.wrap_view('dispatch_detail')(request, pk=self.parent_cat_1.pk) self.assertEqual(resp.status_code, 200) data = json.loads(resp.content.decode('utf-8')) self.assertEqual(data['parent'], None) self.assertEqual(data['name'], 'Dad') # Now try a child. resp = resource.wrap_view('dispatch_detail')(request, pk=self.child_cat_2.pk) self.assertEqual(resp.status_code, 200) data = json.loads(resp.content.decode('utf-8')) self.assertEqual(data['parent'], '/v1/category/2/') self.assertEqual(data['name'], 'Daughter')
def test_two_queries_for_post_list(self): """ Posting a new detail with one related object, referenced via its ``resource_uri`` should require two queries: one to save the object, and one to lookup the related object. """ parent = Category.objects.create(name='Bar') resource = api.canonical_resource_for('category') request = MockRequest() body = json.dumps({ 'name': 'Foo', 'parent': resource.get_resource_uri(parent) }) request.set_body(body) with self.assertNumQueries(2): resource.post_list(request)