Permalink
Browse files

Improving the rest api's treatment of nullable FKs, per Alex's

suggestions
  • Loading branch information...
1 parent 053a637 commit 20fcba901371e5a109cf59dc71b3009e05f0aa5f @coleifer committed May 19, 2012
Showing with 175 additions and 2 deletions.
  1. +6 −1 flask_peewee/tests/base.py
  2. +151 −1 flask_peewee/tests/rest.py
  3. +16 −0 flask_peewee/tests/test_app.py
  4. +2 −0 flask_peewee/utils.py
@@ -1,7 +1,7 @@
import unittest
from flask_peewee.tests import test_app
-from flask_peewee.tests.test_app import User, Message, Note, AModel, BModel, CModel, DModel, BDetails
+from flask_peewee.tests.test_app import User, Message, Note, AModel, BModel, CModel, DModel, BDetails, EModel, FModel
class FlaskPeeweeTestCase(unittest.TestCase):
@@ -12,6 +12,11 @@ def setUp(self):
User.create_table()
Message.create_table()
Note.create_table()
+
+ FModel.drop_table(True)
+ EModel.drop_table(True)
+ EModel.create_table()
+ FModel.create_table()
self.flask_app = test_app.app
self.flask_app._template_context = {}
View
@@ -13,7 +13,7 @@
from flask_peewee.rest import RestAPI, RestResource, Authentication, UserAuthentication
from flask_peewee.tests.base import FlaskPeeweeTestCase
-from flask_peewee.tests.test_app import User, Message, Note, TestModel, APIKey, AModel, BModel, CModel
+from flask_peewee.tests.test_app import User, Message, Note, TestModel, APIKey, AModel, BModel, CModel, EModel, FModel
from flask_peewee.utils import get_next, make_password, check_password
@@ -91,6 +91,8 @@ def assertAPITestModels(self, json_data, tms):
class RestApiResourceTestCase(RestApiTestCase):
def setUp(self):
super(RestApiResourceTestCase, self).setUp()
+ FModel.delete().execute()
+ EModel.delete().execute()
CModel.delete().execute()
BModel.delete().execute()
AModel.delete().execute()
@@ -102,6 +104,11 @@ def create_test_models(self):
self.b2 = BModel.create(b_field='b2', a=self.a2)
self.c1 = CModel.create(c_field='c1', b=self.b1)
self.c2 = CModel.create(c_field='c2', b=self.b2)
+
+ self.e1 = EModel.create(e_field='e1')
+ self.e2 = EModel.create(e_field='e2')
+ self.f1 = FModel.create(f_field='f1', e=self.e1)
+ self.f2 = FModel.create(f_field='f2')
def test_resources_list_detail(self):
self.create_test_models()
@@ -152,11 +159,35 @@ def test_resources_list_detail(self):
'c_field': 'c2',
'b': {'id': self.b2.id, 'b_field': 'b2', 'a': {'id': self.a2.id, 'a_field': 'a2'}},
})
+
+ # fmodel
+ resp = self.app.get('/api/fmodel/?ordering=id')
+ resp_json = self.response_json(resp)
+ self.assertEqual(resp_json['objects'], [
+ {'id': self.f1.id, 'f_field': 'f1', 'e': {'id': self.e1.id, 'e_field': 'e1'}},
+ {'id': self.f2.id, 'f_field': 'f2'},
+ ])
+
+ resp = self.app.get('/api/fmodel/%s/' % self.f1.id)
+ resp_json = self.response_json(resp)
+ self.assertEqual(resp_json, {
+ 'id': self.f1.id,
+ 'f_field': 'f1',
+ 'e': {'id': self.e1.id, 'e_field': 'e1'},
+ })
+
+ resp = self.app.get('/api/fmodel/%s/' % self.f2.id)
+ resp_json = self.response_json(resp)
+ self.assertEqual(resp_json, {
+ 'id': self.f2.id,
+ 'f_field': 'f2',
+ })
def post_to(self, url, data):
return self.app.post(url, data=json.dumps(data))
def test_resources_create(self):
+ # a model
resp = self.post_to('/api/amodel/', {'a_field': 'ax'})
self.assertEqual(resp.status_code, 200)
@@ -167,6 +198,7 @@ def test_resources_create(self):
'a_field': 'ax',
})
+ # b model
resp = self.post_to('/api/bmodel/', {'b_field': 'by', 'a': {'a_field': 'ay'}})
self.assertEqual(resp.status_code, 200)
@@ -185,6 +217,7 @@ def test_resources_create(self):
},
})
+ # c model
resp = self.post_to('/api/cmodel/', {'c_field': 'cz', 'b': {'b_field': 'bz', 'a': {'a_field': 'az'}}})
self.assertEqual(resp.status_code, 200)
@@ -209,10 +242,43 @@ def test_resources_create(self):
},
},
})
+
+ # f model
+ resp = self.post_to('/api/fmodel/', {'f_field': 'fy', 'e': {'e_field': 'ey'}})
+ self.assertEqual(resp.status_code, 200)
+
+ self.assertEqual(FModel.select().count(), 1)
+ self.assertEqual(EModel.select().count(), 1)
+ f_obj = FModel.get(f_field='fy')
+ e_obj = EModel.get(e_field='ey')
+
+ self.assertEqual(f_obj.e, e_obj)
+ self.assertEqual(json.loads(resp.data), {
+ 'id': f_obj.id,
+ 'f_field': 'fy',
+ 'e': {
+ 'id': e_obj.id,
+ 'e_field': 'ey',
+ },
+ })
+
+ resp = self.post_to('/api/fmodel/', {'f_field': 'fz'})
+ self.assertEqual(resp.status_code, 200)
+
+ self.assertEqual(FModel.select().count(), 2)
+ self.assertEqual(EModel.select().count(), 1)
+ f_obj = FModel.get(f_field='fz')
+
+ self.assertEqual(f_obj.e, None)
+ self.assertEqual(json.loads(resp.data), {
+ 'id': f_obj.id,
+ 'f_field': 'fz',
+ })
def test_resources_edit(self):
self.create_test_models()
+ # a
resp = self.post_to('/api/amodel/%s/' % self.a2.id, {'a_field': 'a2-xxx'})
self.assertEqual(resp.status_code, 200)
@@ -223,6 +289,7 @@ def test_resources_edit(self):
'a_field': 'a2-xxx',
})
+ # b
resp = self.post_to('/api/bmodel/%s/' % self.b2.id, {'b_field': 'b2-yyy', 'a': {'a_field': 'a2-yyy'}})
self.assertEqual(resp.status_code, 200)
@@ -241,6 +308,7 @@ def test_resources_edit(self):
},
})
+ # c
resp = self.post_to('/api/cmodel/%s/' % self.c2.id, {'c_field': 'c2-zzz', 'b': {'b_field': 'b2-zzz', 'a': {'a_field': 'a2-zzz'}}})
self.assertEqual(resp.status_code, 200)
@@ -265,10 +333,44 @@ def test_resources_edit(self):
},
},
})
+
+ # f
+ resp = self.post_to('/api/fmodel/%s/' % self.f1.id, {'f_field': 'f1-yyy', 'e': {'e_field': 'e1-yyy'}})
+ self.assertEqual(resp.status_code, 200)
+
+ self.assertEqual(FModel.select().count(), 2)
+ self.assertEqual(EModel.select().count(), 2)
+ f_obj = FModel.get(id=self.f1.id)
+ e_obj = EModel.get(id=self.e1.id)
+
+ self.assertEqual(f_obj.e, e_obj)
+ self.assertEqual(json.loads(resp.data), {
+ 'id': f_obj.id,
+ 'f_field': 'f1-yyy',
+ 'e': {
+ 'id': e_obj.id,
+ 'e_field': 'e1-yyy',
+ },
+ })
+
+ resp = self.post_to('/api/fmodel/%s/' % self.f2.id, {'f_field': 'f2-yyy'})
+ self.assertEqual(resp.status_code, 200)
+
+ self.assertEqual(FModel.select().count(), 2)
+ self.assertEqual(EModel.select().count(), 2)
+ f_obj = FModel.get(id=self.f2.id)
+
+ self.assertEqual(f_obj.e, None)
+ self.assertEqual(json.loads(resp.data), {
+ 'id': f_obj.id,
+ 'f_field': 'f2-yyy',
+ })
+
def test_resource_edit_partial(self):
self.create_test_models()
+ # b model
resp = self.post_to('/api/bmodel/%s/' % self.b2.id, {'b_field': 'b2-yyy'})
self.assertEqual(resp.status_code, 200)
@@ -286,10 +388,30 @@ def test_resource_edit_partial(self):
'a_field': 'a2',
},
})
+
+ # f model
+ resp = self.post_to('/api/fmodel/%s/' % self.f1.id, {'f_field': 'f1-zzz'})
+ self.assertEqual(resp.status_code, 200)
+
+ self.assertEqual(FModel.select().count(), 2)
+ self.assertEqual(EModel.select().count(), 2)
+ f_obj = FModel.get(id=self.f1.id)
+ e_obj = EModel.get(id=self.e1.id)
+
+ self.assertEqual(f_obj.e, e_obj)
+ self.assertEqual(json.loads(resp.data), {
+ 'id': f_obj.id,
+ 'f_field': 'f1-zzz',
+ 'e': {
+ 'id': e_obj.id,
+ 'e_field': 'e1',
+ },
+ })
def test_resource_edit_by_fk(self):
self.create_test_models()
+ # b model
resp = self.post_to('/api/bmodel/%s/' % self.b2.id, {'a': self.a1.id})
self.assertEqual(resp.status_code, 200)
@@ -307,6 +429,25 @@ def test_resource_edit_by_fk(self):
'a_field': 'a1',
},
})
+
+ # f model
+ resp = self.post_to('/api/fmodel/%s/' % self.f2.id, {'e': self.e2.id})
+ self.assertEqual(resp.status_code, 200)
+
+ self.assertEqual(BModel.select().count(), 2)
+ self.assertEqual(AModel.select().count(), 2)
+ f_obj = FModel.get(id=self.f2.id)
+ e_obj = EModel.get(id=self.e2.id)
+
+ self.assertEqual(f_obj.e, e_obj)
+ self.assertEqual(json.loads(resp.data), {
+ 'id': f_obj.id,
+ 'f_field': 'f2',
+ 'e': {
+ 'id': e_obj.id,
+ 'e_field': 'e2',
+ },
+ })
def test_delete(self):
self.create_test_models()
@@ -325,6 +466,15 @@ def test_delete(self):
self.assertEqual(BModel.select().count(), 1)
self.assertEqual(AModel.select().count(), 1)
+ resp = self.post_to('/api/emodel/%s/delete/' % self.e1.id, {})
+ self.assertEqual(json.loads(resp.data), {'deleted': 1})
+
+ self.assertEqual(EModel.select().count(), 1)
+ self.assertEqual(FModel.select().count(), 2)
+
+ f_obj = FModel.get(id=self.f1.id)
+ self.assertEqual(f_obj.e, None)
+
class RestApiBasicTestCase(RestApiTestCase):
def get_users_and_notes(self):
@@ -86,6 +86,14 @@ class BDetails(db.Model):
b = ForeignKeyField(BModel)
+class EModel(db.Model):
+ e_field = CharField()
+
+class FModel(db.Model):
+ e = ForeignKeyField(EModel, null=True)
+ f_field = CharField()
+
+
class APIKey(db.Model):
key = CharField()
secret = CharField()
@@ -167,6 +175,11 @@ class BResource(RestResource):
class CResource(RestResource):
include_resources = {'b': BResource}
+class EResource(RestResource):
+ pass
+
+class FResource(RestResource):
+ include_resources = {'e': EResource}
# rest api stuff
dummy_auth = Authentication(protected_methods=[])
@@ -184,6 +197,9 @@ class CResource(RestResource):
api.register(BModel, BResource, auth=dummy_auth)
api.register(CModel, CResource, auth=dummy_auth)
+api.register(EModel, EResource, auth=dummy_auth)
+api.register(FModel, FResource, auth=dummy_auth)
+
# views
@app.route('/')
View
@@ -173,6 +173,8 @@ def get_models_from_dictionary(model, field_dict):
rel_obj = getattr(model, field_name)
except field_obj.to.DoesNotExist:
pass
+ if rel_obj is None:
+ rel_obj = field_obj.to
rel_inst, rel_models = get_models_from_dictionary(rel_obj, value)
models.extend(rel_models)
setattr(model_instance, field_name, rel_inst)

0 comments on commit 20fcba9

Please sign in to comment.