Skip to content

Commit d1e675c

Browse files
committed
feat(locations): add viewsets, serializers, managers and routers for country, state and city models
1 parent 2465685 commit d1e675c

File tree

7 files changed

+230
-21
lines changed

7 files changed

+230
-21
lines changed

apps/locations/managers.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
"""Managers for Locations App."""
2+
3+
from apps.utilities.managers import BaseManager
4+
5+
6+
class CountryManager(BaseManager):
7+
"""Manager for Country Model."""
8+
9+
10+
class StateManager(BaseManager):
11+
"""Manager for State Model."""
12+
13+
14+
class CityManager(BaseManager):
15+
"""Manager for City Model."""

apps/locations/models.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@
33
from django.db import models
44

55
from apps.utilities.models import BaseModel
6+
from .managers import CountryManager, StateManager, CityManager
67

78

89
class Country(BaseModel):
910
"""Model definition for Country."""
1011

1112
name = models.CharField(max_length=100, unique=True)
1213

14+
objects = CountryManager()
15+
1316
class Meta:
1417
ordering = ["pk"]
1518
verbose_name = "country"
@@ -28,6 +31,8 @@ class State(BaseModel):
2831
name = models.CharField(max_length=100, unique=True)
2932
country_id = models.ForeignKey(Country, on_delete=models.CASCADE)
3033

34+
objects = StateManager()
35+
3136
class Meta:
3237
ordering = ["pk"]
3338
verbose_name = "state"
@@ -46,6 +51,8 @@ class City(BaseModel):
4651
name = models.CharField(max_length=100, unique=True)
4752
state_id = models.ForeignKey(State, on_delete=models.CASCADE)
4853

54+
objects = CityManager()
55+
4956
class Meta:
5057
ordering = ["pk"]
5158
verbose_name = "city"

apps/locations/routers.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
"""Routers for Locations App."""
2+
3+
from django.urls import include
4+
from django.urls import path
5+
from rest_framework.routers import DefaultRouter
6+
7+
from .viewsets import CountryViewSet, StateViewSet, CityViewSet
8+
9+
router = DefaultRouter()
10+
router.register(r"countries", CountryViewSet, basename="country")
11+
router.register(r"states", StateViewSet, basename="state")
12+
router.register(r"cities", CityViewSet, basename="city")
13+
14+
urlpatterns = [
15+
path("api/v1/", include(router.urls)),
16+
]

apps/locations/serializers.py

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,54 @@ class Meta:
1818
]
1919

2020

21+
class CountryWriteSerializer(ModelSerializer):
22+
"""Serializer for Country model (Create/update)."""
23+
24+
class Meta:
25+
model = Country
26+
fields = [
27+
"name",
28+
]
29+
30+
31+
class CountryMinimalSerializer(ModelSerializer):
32+
"""Serializer for Country model (Minimal)."""
33+
34+
class Meta:
35+
model = Country
36+
fields = [
37+
"id",
38+
"name",
39+
]
40+
41+
2142
class StateReadSerializer(ModelSerializer):
2243
"""Serializer for State model (List/retrieve)."""
2344

45+
country_id = CountryMinimalSerializer()
46+
2447
class Meta:
2548
model = State
2649
fields = [
2750
"id",
2851
"name",
52+
"country_id",
2953
"created_at",
3054
"updated_at",
3155
]
3256

3357

58+
class StateWriteSerializer(ModelSerializer):
59+
"""Serializer for State model (Create/update)."""
60+
61+
class Meta:
62+
model = State
63+
fields = [
64+
"name",
65+
"country_id",
66+
]
67+
68+
3469
class StateMinimalSerializer(ModelSerializer):
3570
"""Serializer for State model (Minimal)."""
3671

@@ -45,7 +80,7 @@ class Meta:
4580
class CityReadSerializer(ModelSerializer):
4681
"""Serializer for City model (List/retrieve)."""
4782

48-
state_id = StateReadSerializer()
83+
state_id = StateMinimalSerializer()
4984

5085
class Meta:
5186
model = City
@@ -58,6 +93,17 @@ class Meta:
5893
]
5994

6095

96+
class CityWriteSerializer(ModelSerializer):
97+
"""Serializer for City model (Create/update)."""
98+
99+
class Meta:
100+
model = City
101+
fields = [
102+
"name",
103+
"state_id",
104+
]
105+
106+
61107
class CityMinimalSerializer(ModelSerializer):
62108
"""Serializer for City model (Minimal)."""
63109

apps/locations/viewsets.py

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
"""ViewSets for Promotions App."""
2+
3+
from rest_framework.viewsets import ModelViewSet
4+
from rest_framework.permissions import AllowAny
5+
6+
from apps.users.permissions import IsAdministrator
7+
from apps.utilities.mixins import ListCacheMixin, LogicalDeleteMixin
8+
from .models import Country, State, City
9+
from .serializers import (
10+
CountryReadSerializer,
11+
CountryWriteSerializer,
12+
CountryMinimalSerializer,
13+
StateReadSerializer,
14+
StateWriteSerializer,
15+
StateMinimalSerializer,
16+
CityReadSerializer,
17+
CityWriteSerializer,
18+
CityMinimalSerializer,
19+
)
20+
21+
22+
class CountryViewSet(ListCacheMixin, LogicalDeleteMixin, ModelViewSet):
23+
"""
24+
ViewSet for managing Country instances.
25+
26+
Endpoints:
27+
- GET /api/v1/countries/
28+
- POST /api/v1/countries/
29+
- GET /api/v1/countries/{id}/
30+
- PUT /api/v1/countries/{id}/
31+
- PATCH /api/v1/countries/{id}/
32+
- DELETE /api/v1/countries/{id}/
33+
"""
34+
35+
permission_classes = [IsAdministrator]
36+
serializer_class = CountryWriteSerializer
37+
search_fields = ["name"]
38+
39+
def get_queryset(self):
40+
return Country.objects.get_available()
41+
42+
def get_serializer_class(self):
43+
if self.action == "list":
44+
return CountryMinimalSerializer
45+
elif self.action == "retrieve":
46+
return CountryReadSerializer
47+
return super().get_serializer_class()
48+
49+
def get_permissions(self):
50+
if self.action in ["list", "retrieve"]:
51+
return [AllowAny()]
52+
return super().get_permissions()
53+
54+
55+
class StateViewSet(ListCacheMixin, LogicalDeleteMixin, ModelViewSet):
56+
"""
57+
ViewSet for managing State instances.
58+
59+
Endpoints:
60+
- GET /api/v1/states/
61+
- POST /api/v1/states/
62+
- GET /api/v1/states/{id}/
63+
- PUT /api/v1/states/{id}/
64+
- PATCH /api/v1/states/{id}/
65+
- DELETE /api/v1/states/{id}/
66+
"""
67+
68+
permission_classes = [IsAdministrator]
69+
serializer_class = StateWriteSerializer
70+
search_fields = ["name"]
71+
# filterset_class = StateFilter # TODO: Add filter
72+
73+
def get_queryset(self):
74+
return State.objects.get_available().select_related(
75+
"country_id"
76+
) # TODO: Add manager
77+
78+
def get_serializer_class(self):
79+
if self.action == "list":
80+
return StateMinimalSerializer
81+
elif self.action == "retrieve":
82+
return StateReadSerializer
83+
return super().get_serializer_class()
84+
85+
def get_permissions(self):
86+
if self.action in ["list", "retrieve"]:
87+
return [AllowAny()]
88+
return super().get_permissions()
89+
90+
91+
class CityViewSet(ListCacheMixin, LogicalDeleteMixin, ModelViewSet):
92+
"""
93+
ViewSet for managing City instances.
94+
95+
Endpoints:
96+
- GET /api/v1/cities/
97+
- POST /api/v1/cities/
98+
- GET /api/v1/cities/{id}/
99+
- PUT /api/v1/cities/{id}/
100+
- PATCH /api/v1/cities/{id}/
101+
- DELETE /api/v1/cities/{id}/
102+
"""
103+
104+
permission_classes = [IsAdministrator]
105+
serializer_class = CityWriteSerializer
106+
search_fields = ["name"]
107+
# filterset_class = CityFilter # TODO: Add filter
108+
109+
def get_queryset(self):
110+
return City.objects.select_related(
111+
"state_id"
112+
).get_available() # TODO: Add manager
113+
114+
def get_serializer_class(self):
115+
if self.action == "list":
116+
return CityMinimalSerializer
117+
elif self.action == "retrieve":
118+
return CityReadSerializer
119+
return super().get_serializer_class()
120+
121+
def get_permissions(self):
122+
if self.action in ["list", "retrieve"]:
123+
return [AllowAny()]
124+
return super().get_permissions()

config/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
# Apps urls
3636
path("", include("apps.restaurants.routers")),
3737
path("", include("apps.promotions.routers")),
38+
path("", include("apps.locations.routers")),
3839
path("", include("apps.drivers.urls")),
3940
path("", include("apps.orders.urls")),
4041
path("", include("apps.blogs.urls")),

roadmap.md

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -131,29 +131,29 @@ TODO: Agregar permiso para Recursos humanos
131131

132132
## Locations [OK]
133133

134-
- [ ] `GET /countries` Obtener la lista de todos los países.
135-
- [ ] `POST /countries` Registrar un nuevo país.
136-
- [ ] `GET /countries/{id}` Obtener los detalles de un país específico.
137-
- [ ] `PUT /countries/{id}` Actualizar los detalles de un país específico.
138-
- [ ] `DELETE /countries/{id}` Eliminar un país específico.
139-
140-
- [ ] `GET /states` Obtener la lista de todos los estados.
141-
- [ ] `POST /states` Registrar un nuevo estado.
142-
- [ ] `GET /states/{id}` Obtener los detalles de un estado específico.
143-
- [ ] `PUT /states/{id}` Actualizar los detalles de un estado específico.
144-
- [ ] `DELETE /states/{id}` Eliminar un estado específico.
145-
146-
- [ ] `GET /cities` Obtener la lista de todas las ciudades.
147-
- [ ] `POST /cities` Registrar una nueva ciudad.
148-
- [ ] `GET /cities/{id}` Obtener los detalles de una ciudad específica.
149-
- [ ] `PUT /cities/{id}` Actualizar los detalles de una ciudad específica.
150-
- [ ] `DELETE /api/v1/cities/{id}` Eliminar una ciudad específica.
134+
- [x] `GET /countries` Obtener la lista de todos los países.
135+
- [x] `POST /countries` Registrar un nuevo país.
136+
- [x] `GET /countries/{id}` Obtener los detalles de un país específico.
137+
- [x] `PUT /countries/{id}` Actualizar los detalles de un país específico.
138+
- [x] `DELETE /countries/{id}` Eliminar un país específico.
139+
140+
- [x] `GET /states` Obtener la lista de todos los estados.
141+
- [x] `POST /states` Registrar un nuevo estado.
142+
- [x] `GET /states/{id}` Obtener los detalles de un estado específico.
143+
- [x] `PUT /states/{id}` Actualizar los detalles de un estado específico.
144+
- [x] `DELETE /states/{id}` Eliminar un estado específico.
145+
146+
- [x] `GET /cities` Obtener la lista de todas las ciudades.
147+
- [x] `POST /cities` Registrar una nueva ciudad.
148+
- [x] `GET /cities/{id}` Obtener los detalles de una ciudad específica.
149+
- [x] `PUT /cities/{id}` Actualizar los detalles de una ciudad específica.
150+
- [x] `DELETE /api/v1/cities/{id}` Eliminar una ciudad específica.
151151

152152
## Users [OK]
153153

154-
- [ ] `GET /users/reviews` Obtener todas las reseñas escritas por un usuario específico (IsClient).
155-
- [ ] `GET /users/orders` Obtener todas las reseñas escritas por un usuario específico (IsClient).
156-
- [ ] `GET /users/{id}/historical` Obtener el historial de cambios de un usuario específico (IsAdministrator).
154+
- [x] `GET /accounts/reviews` Obtener todas las reseñas escritas por un usuario específico (IsClient).
155+
- [x] `GET /accounts/orders` Obtener todas las reseñas escritas por un usuario específico (IsClient).
156+
- [x] `GET /accounts/{id}/historical` Obtener el historial de cambios de un usuario específico (IsAdministrator).
157157

158158
TODO: Agregar reviews a restaurants y posts, limitar modelo de Review
159159

0 commit comments

Comments
 (0)