Skip to content

Commit a6fbee8

Browse files
committed
refactor: CrudAPI _crud_add_obj _crud_patch_obj
1 parent d275cd2 commit a6fbee8

File tree

5 files changed

+44
-39
lines changed

5 files changed

+44
-39
lines changed

easy/controller/meta.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,11 @@ async def add_obj( # type: ignore
149149
PUT /
150150
Create a single Object
151151
"""
152-
return await self.service.add_obj(**data.dict())
152+
obj_id = await self.service.add_obj(**data.dict())
153+
if obj_id:
154+
return BaseApiResponse({"id": obj_id}, errno=201)
155+
else:
156+
return BaseApiResponse("Update failed", errno=204)
153157

154158
async def patch_obj( # type: ignore
155159
self, request: HttpRequest, id: int, data: DataSchema
@@ -158,7 +162,10 @@ async def patch_obj( # type: ignore
158162
PATCH /{id}
159163
Update a single field for a Object
160164
"""
161-
return await self.service.patch_obj(id=id, payload=data.dict())
165+
if await self.service.patch_obj(id=id, payload=data.dict()):
166+
return BaseApiResponse("Updated.")
167+
else:
168+
return BaseApiResponse("Update Failed", errno=400)
162169

163170
DataSchema.__name__ = (
164171
f"{opts_model.__name__}__AutoSchema({str(uuid.uuid4())[:4]})"

easy/domain/orm.py

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import logging
22
from typing import Any, Dict, List, Tuple, Type
33

4-
from django.db import models
4+
from django.db import models, transaction
55
from django.db.models.query import QuerySet
66
from ninja_extra.shortcuts import get_object_or_none
77

8+
from easy.exception import BaseAPIException
89
from easy.response import BaseApiResponse
910

1011
logger = logging.getLogger(__name__)
@@ -19,7 +20,7 @@ def __init__(self, model: Type[models.Model]):
1920
if isinstance(_field, models.ManyToManyField)
2021
)
2122

22-
def __separate_payload(self, payload: Dict) -> Tuple[Dict, Dict]:
23+
def _separate_payload(self, payload: Dict) -> Tuple[Dict, Dict]:
2324
m2m_fields = {}
2425
local_fields = {}
2526
for _field in payload.keys():
@@ -35,22 +36,30 @@ def __separate_payload(self, payload: Dict) -> Tuple[Dict, Dict]:
3536
local_fields.update({_field: payload[_field]})
3637
return local_fields, m2m_fields
3738

39+
@staticmethod
40+
def _crud_set_m2m_obj(obj: models.Model, m2m_fields: Dict) -> bool:
41+
if obj and m2m_fields:
42+
for _field, _value in m2m_fields.items():
43+
if _value and isinstance(_value, List):
44+
m2m_f = getattr(obj, _field)
45+
m2m_f.set(_value)
46+
return True
47+
3848
# Define BASE CRUD
49+
@transaction.atomic()
3950
def _crud_add_obj(self, **payload: Dict) -> Any:
40-
local_f_payload, m2m_f_payload = self.__separate_payload(payload)
51+
local_f_payload, m2m_f_payload = self._separate_payload(payload)
52+
4153
# Create obj with local_fields payload
42-
try:
43-
obj = self.model.objects.create(**local_f_payload)
44-
except Exception as e: # pragma: no cover
45-
logger.error(f"Crud_add Error - {e}", exc_info=True)
46-
return BaseApiResponse(str(e), message="Add failed", errno=500)
54+
obj = self.model.objects.create(**local_f_payload)
55+
4756
# Save obj with m2m_fields payload
48-
if m2m_f_payload:
49-
for _field, _value in m2m_f_payload.items():
50-
if _value and isinstance(_value, List):
51-
m2m_f = getattr(obj, _field)
52-
m2m_f.set(_value)
53-
return BaseApiResponse({"id": obj.pk}, errno=201)
57+
set_m2m_status = self._crud_set_m2m_obj(obj, m2m_f_payload)
58+
59+
if obj and set_m2m_status:
60+
return obj.id
61+
else:
62+
return None
5463

5564
def _crud_del_obj(self, pk: int) -> "BaseApiResponse":
5665
obj = get_object_or_none(self.model, pk=pk)
@@ -60,27 +69,18 @@ def _crud_del_obj(self, pk: int) -> "BaseApiResponse":
6069
else:
6170
return BaseApiResponse("Not Found.", errno=404)
6271

63-
def _crud_update_obj(self, pk: int, payload: Dict) -> "BaseApiResponse":
64-
local_fields, m2m_fields = self.__separate_payload(payload)
72+
@transaction.atomic()
73+
def _crud_update_obj(self, pk: int, payload: Dict) -> bool:
74+
local_fields, m2m_fields = self._separate_payload(payload)
6575
if not self.model.objects.filter(pk=pk).exists():
66-
return BaseApiResponse("Not Found.", errno=404)
76+
return False
6777
try:
6878
obj, _ = self.model.objects.update_or_create(pk=pk, defaults=local_fields)
6979
except Exception as e: # pragma: no cover
70-
logger.error(f"Crud_update Error - {e}", exc_info=True)
71-
return BaseApiResponse(str(e), message="Update Failed", errno=500)
72-
if obj and m2m_fields:
73-
for _field, _value in m2m_fields.items():
74-
if _value:
75-
m2m_f = getattr(obj, _field)
76-
try:
77-
m2m_f.set(_value)
78-
except Exception as e: # pragma: no cover
79-
logger.error(f"Crud_update Error - {e}", exc_info=True)
80-
return BaseApiResponse(
81-
str(e), message="Update Failed", errno=500
82-
)
83-
return BaseApiResponse({"pk": pk}, message="Updated.")
80+
raise BaseAPIException(f"Update Error - {e}")
81+
82+
set_m2m_status = self._crud_set_m2m_obj(obj, m2m_fields)
83+
return bool(set_m2m_status and obj)
8484

8585
def _crud_get_obj(self, pk: int) -> Any:
8686
if self.m2m_fields_list:

tests/demo_app/controllers.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,7 @@ async def must_be_super_user(self, word: str):
110110

111111
@http_get("/test_perm_only_super/", permissions=[BaseApiPermission])
112112
async def test_perm_only_super(self, request):
113-
response = await self.service.add_obj(title="test_event_title")
114-
event_id = response.json_data.get("data")["id"]
113+
event_id = await self.service.add_obj(title="test_event_title")
115114
# return await self.service.get_obj(id=note.id)
116115
return await sync_to_async(self.get_object_or_none)(Event, id=event_id)
117116

tests/demo_app/test_async_api_permissions.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ async def test_demo(self, easy_api_client):
2323
"/must_be_authenticated/?word=authenticated",
2424
content_type="application/json",
2525
)
26-
print(f"{response.__dict__.items()}")
2726
assert response.status_code == 200
2827
assert response.json().get("data")["says"] == "authenticated"
2928

@@ -187,7 +186,7 @@ async def test_perm_auto_apis_patch(self, transactional_db, easy_api_client):
187186
response = await client.patch(
188187
f"/{event.id}", json=new_data, content_type="application/json"
189188
)
190-
assert response.json().get("data")["pk"] == event.id
189+
assert response.json().get("data")
191190

192191
response = await client.get(
193192
f"/{event.id}",

tests/demo_app/test_async_auto_crud_apis.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,14 +192,14 @@ async def test_crud_default_patch(self, transactional_db, easy_api_client):
192192
)
193193

194194
assert response.status_code == 200
195-
assert response.json()["code"] == 404
195+
assert response.json()["code"] == 400
196196

197197
response = await client.patch(
198198
f"/{event.pk}", json=new_data, content_type="application/json"
199199
)
200200

201201
assert response.status_code == 200
202-
assert response.json().get("data")["pk"] == event.pk
202+
assert response.json().get("data")
203203

204204
response = await client.get(
205205
f"/{event.pk}",

0 commit comments

Comments
 (0)