538 lines
13 KiB
Python
538 lines
13 KiB
Python
"""Location app views."""
|
||
from django.contrib.postgres.fields.jsonb import KeyTextTransform
|
||
from django.db.models.deletion import ProtectedError
|
||
from rest_framework import generics, status
|
||
from rest_framework.response import Response
|
||
from rest_framework.views import APIView
|
||
|
||
from location import filters
|
||
from location import models, serializers
|
||
from location.filters import RegionFilter
|
||
from location.views import common
|
||
from utils.methods import get_permission_classes
|
||
from utils.models import get_current_locale
|
||
from utils.permissions import (
|
||
IsGuest, IsEstablishmentManager, IsEstablishmentAdministrator
|
||
)
|
||
|
||
|
||
# Address
|
||
class AddressListCreateView(common.AddressViewMixin, generics.ListCreateAPIView):
|
||
"""
|
||
## List/Create view
|
||
### *GET*
|
||
#### Description
|
||
Get paginated list of addresses
|
||
##### Response
|
||
E.g.:
|
||
```
|
||
{
|
||
"count": 58,
|
||
"next": 2,
|
||
"previous": null,
|
||
"results": [
|
||
{
|
||
"id": 1,
|
||
...
|
||
}
|
||
]
|
||
}
|
||
```
|
||
### *POST*
|
||
#### Description
|
||
Create a new address
|
||
##### Request
|
||
Required
|
||
* latitude (`float`) - latitude
|
||
* longitude (`float`) - longitude
|
||
* city_id (`int`) - identifier of city
|
||
|
||
Available
|
||
* district_name (`str`) - city district name
|
||
* street_name_1 (`str`) - street name
|
||
* street_name_2 (`str`) - street name (additional)
|
||
* number (`int`) - city name
|
||
* postal_code (`str`) - city postal code
|
||
##### Response
|
||
E.g.:
|
||
```
|
||
{
|
||
"id": 1,
|
||
...
|
||
}
|
||
```
|
||
"""
|
||
serializer_class = serializers.AddressDetailSerializer
|
||
queryset = models.Address.objects.all()
|
||
permission_classes = get_permission_classes(
|
||
IsEstablishmentManager,
|
||
IsEstablishmentAdministrator,
|
||
IsGuest,
|
||
)
|
||
|
||
|
||
class AddressRUDView(common.AddressViewMixin, generics.RetrieveUpdateDestroyAPIView):
|
||
"""
|
||
## Retrieve/Update/Destroy view
|
||
### *GET*
|
||
#### Description
|
||
Return serialized object of an address by an identifier.
|
||
##### Response
|
||
E.g.:
|
||
```
|
||
{
|
||
"id": 1,
|
||
...
|
||
}
|
||
```
|
||
### *PUT*/*PATCH*
|
||
#### Description
|
||
Completely/Partially update an address object by an identifier.
|
||
##### Request
|
||
Available
|
||
* latitude (`float`) - latitude
|
||
* longitude (`float`) - longitude
|
||
* city_id (`int`) - identifier of city
|
||
* district_name (`str`) - city district name
|
||
* street_name_1 (`str`) - street name
|
||
* street_name_2 (`str`) - street name (additional)
|
||
* number (`int`) - city name
|
||
* postal_code (`str`) - city postal code
|
||
##### Response
|
||
E.g.
|
||
```
|
||
{
|
||
"id": 1,
|
||
...
|
||
}
|
||
```
|
||
### *DELETE*
|
||
#### Description
|
||
Delete an address object by an identifier.
|
||
##### Response
|
||
```
|
||
No content
|
||
```
|
||
"""
|
||
serializer_class = serializers.AddressDetailSerializer
|
||
queryset = models.Address.objects.all()
|
||
permission_classes = get_permission_classes(
|
||
IsEstablishmentManager,
|
||
IsEstablishmentAdministrator,
|
||
IsGuest,
|
||
)
|
||
|
||
|
||
# City
|
||
class CityListCreateView(common.CityViewMixin, generics.ListCreateAPIView):
|
||
"""
|
||
## List/Create view
|
||
### *GET*
|
||
#### Description
|
||
Return paginated list of cities ordered by a locale and filtered by a country code.
|
||
Available filters:
|
||
* search (`str`) - search city by name
|
||
* country_code (`str`) - search city by its country code
|
||
##### Response
|
||
E.g.:
|
||
```
|
||
{
|
||
"count": 58,
|
||
"next": 2,
|
||
"previous": null,
|
||
"results": [
|
||
{
|
||
"id": 1,
|
||
...
|
||
}
|
||
]
|
||
}
|
||
```
|
||
### *POST*
|
||
#### Description
|
||
Create a new city object.
|
||
##### Request
|
||
Required
|
||
* region_id (`int`) - region identifier
|
||
* country_id (`int`) - country identifier
|
||
Non-required:
|
||
* image_id (`int`) - image identifier
|
||
* name (`str`) - city name
|
||
* postal_code (`str`) - city postal code
|
||
* is_island (`boolean`) - flag that responds for is an island is this city
|
||
##### Response
|
||
E.g.:
|
||
```
|
||
{
|
||
"id": 1,
|
||
...
|
||
}
|
||
```
|
||
"""
|
||
serializer_class = serializers.CityBaseSerializer
|
||
filter_class = filters.CityBackFilter
|
||
permission_classes = get_permission_classes(
|
||
IsEstablishmentManager,
|
||
IsEstablishmentAdministrator,
|
||
IsGuest,
|
||
)
|
||
|
||
def get_queryset(self):
|
||
"""Overridden method 'get_queryset'."""
|
||
qs = models.City.objects.all().annotate(locale_name=KeyTextTransform(get_current_locale(), 'name'))\
|
||
.order_by('-modified').with_base_related()
|
||
if self.request.country_code and self.request.query_params.get('country_code') is None:
|
||
qs = qs.by_country_code(self.request.country_code)
|
||
return qs
|
||
|
||
|
||
class CityListSearchView(CityListCreateView):
|
||
"""
|
||
## List/Create view
|
||
### *GET*
|
||
#### Description
|
||
Return list of cities **without pagination**, ordered by a locale and filtered by a country code.
|
||
Available filters:
|
||
* search (`str`) - search city by name
|
||
* country_code (`str`) - search city by its country code
|
||
##### Response
|
||
E.g.:
|
||
```
|
||
{
|
||
"count": 58,
|
||
"next": 2,
|
||
"previous": null,
|
||
"results": [
|
||
{
|
||
"id": 1,
|
||
...
|
||
}
|
||
]
|
||
}
|
||
```
|
||
### *POST*
|
||
#### Description
|
||
Create a new city object.
|
||
##### Request
|
||
Required
|
||
* region_id (`int`) - region identifier
|
||
* country_id (`int`) - country identifier
|
||
Non-required:
|
||
* image_id (`int`) - image identifier
|
||
* name (`str`) - city name
|
||
* postal_code (`str`) - city postal code
|
||
* is_island (`boolean`) - flag that responds for is an island is this city
|
||
##### Response
|
||
E.g.:
|
||
```
|
||
{
|
||
"id": 1,
|
||
...
|
||
}
|
||
```
|
||
"""
|
||
pagination_class = None
|
||
|
||
def get_queryset(self):
|
||
"""An overridden get_queryset method."""
|
||
return (
|
||
models.City.objects.
|
||
annotate(locale_name=KeyTextTransform(get_current_locale(), 'name')).
|
||
order_by('locale_name')
|
||
)
|
||
|
||
|
||
class CityRUDView(common.CityViewMixin, generics.RetrieveUpdateDestroyAPIView):
|
||
"""
|
||
## Retrieve/Update/Destroy view
|
||
### *GET*
|
||
#### Description
|
||
Retrieve serialized instance of city object by an identifier
|
||
##### Response
|
||
E.g.:
|
||
```
|
||
{
|
||
"id": 1,
|
||
...
|
||
}
|
||
```
|
||
|
||
### *PUT*/*PATCH*
|
||
#### Description
|
||
Completely/Partially update a city object by an identifier.
|
||
##### Request
|
||
Available:
|
||
* region_id (`int`) - region identifier
|
||
* country_id (`int`) - country identifier
|
||
* image_id (`int`) - image identifier
|
||
* name (`str`) - city name
|
||
* postal_code (`str`) - city postal code
|
||
* is_island (`boolean`) - flag that responds for is an island is this city
|
||
##### Response
|
||
E.g.:
|
||
```
|
||
{
|
||
"id": 1,
|
||
...
|
||
}
|
||
```
|
||
|
||
### *DELETE*
|
||
#### Description
|
||
Delete an instance of city by identifier
|
||
##### Response
|
||
E.g.:
|
||
```
|
||
{
|
||
"id": 1,
|
||
...
|
||
}
|
||
```
|
||
"""
|
||
serializer_class = serializers.CityDetailSerializer
|
||
permission_classes = get_permission_classes(
|
||
IsEstablishmentManager,
|
||
IsEstablishmentAdministrator,
|
||
IsGuest,
|
||
)
|
||
|
||
def delete(self, request, *args, **kwargs):
|
||
try:
|
||
return self.destroy(request, *args, **kwargs)
|
||
except ProtectedError:
|
||
from rest_framework.serializers import ValidationError
|
||
raise ValidationError({'detail': 'City couldn’t be deleted. Some objects has this city'})
|
||
|
||
|
||
# Region
|
||
class RegionListCreateView(common.RegionViewMixin, generics.ListCreateAPIView):
|
||
"""
|
||
## List/Create view
|
||
### *GET*
|
||
#### Description
|
||
Return non-paginated list of regions.
|
||
Available filters:
|
||
* country_id (`int`) - filter by a country identifier
|
||
* sub_regions_by_region_id (`int`) - filter sub regions by region identifier
|
||
* without_parent_region (`boolean`) - flag that responds for returning regions
|
||
with/without parent region
|
||
##### Responds
|
||
E.g.:
|
||
```
|
||
[
|
||
{
|
||
"id": 1,
|
||
...
|
||
}
|
||
]
|
||
```
|
||
### *POST*
|
||
#### Description
|
||
Create new region/sub region
|
||
##### Request
|
||
Available:
|
||
* name (`str`) - (sub)region name
|
||
* code (`str`) - (sub)region code
|
||
* country_id (`int`) - identifier of `country`
|
||
* parent_region_id (`int`) - identifier of `parent region`
|
||
##### Response
|
||
E.g.:
|
||
```
|
||
{
|
||
"id": 1,
|
||
...
|
||
}
|
||
```
|
||
"""
|
||
pagination_class = None
|
||
serializer_class = serializers.RegionSerializer
|
||
# ordering_fields = 'name'
|
||
filter_class = RegionFilter
|
||
permission_classes = get_permission_classes(
|
||
IsEstablishmentManager,
|
||
IsEstablishmentAdministrator,
|
||
IsGuest,
|
||
)
|
||
|
||
|
||
class RegionRUDView(common.RegionViewMixin, generics.RetrieveUpdateDestroyAPIView):
|
||
"""
|
||
## Retrieve/Update/Destroy view
|
||
### *GET*
|
||
#### Description
|
||
Return serialized object of (sub)region by an identifier.
|
||
##### Responds
|
||
E.g.:
|
||
```
|
||
[
|
||
{
|
||
"id": 1,
|
||
...
|
||
}
|
||
]
|
||
```
|
||
### *PATCH*/*PUT*
|
||
#### Description
|
||
Completely/Partially update a (sub)region object by an identifier.
|
||
##### Request
|
||
Available:
|
||
* name (`str`) - (sub)region name
|
||
* code (`str`) - (sub)region code
|
||
* country_id (`int`) - identifier of `country`
|
||
* parent_region_id (`int`) - identifier of `parent region`
|
||
##### Response
|
||
E.g.:
|
||
```
|
||
{
|
||
"id": 1,
|
||
...
|
||
}
|
||
```
|
||
### *DELETE*
|
||
#### Description
|
||
Delete an instance of (sub)region
|
||
##### Response
|
||
E.g.:
|
||
```
|
||
No content
|
||
```
|
||
"""
|
||
serializer_class = serializers.RegionSerializer
|
||
permission_classes = get_permission_classes(
|
||
IsEstablishmentManager,
|
||
IsEstablishmentAdministrator,
|
||
IsGuest,
|
||
)
|
||
|
||
|
||
# Country
|
||
class CountryBaseViewMixin:
|
||
"""Mixin for Country views."""
|
||
queryset = models.Country.objects.all()
|
||
permission_classes = get_permission_classes(
|
||
IsEstablishmentManager,
|
||
IsEstablishmentAdministrator,
|
||
IsGuest,
|
||
)
|
||
|
||
|
||
class CountryListCreateView(CountryBaseViewMixin, generics.ListCreateAPIView):
|
||
"""
|
||
## List/Create view.
|
||
### *GET*
|
||
#### Description
|
||
Return non-paginated list of countries ordered by a locale.
|
||
##### Response
|
||
E.g.:
|
||
```
|
||
[
|
||
{
|
||
"id": 1,
|
||
...
|
||
}
|
||
]
|
||
```
|
||
### *POST*
|
||
#### Description
|
||
Create new city
|
||
##### Request
|
||
* code (`str`) - country code
|
||
* svg_image (`file`) - svg icon of country flag
|
||
* name (`JSON`) - country name, like - `{"en-GB": "text", "ru-RU": Text}`
|
||
##### Response
|
||
E.g.:
|
||
```
|
||
{
|
||
"id": 1,
|
||
...
|
||
}
|
||
```
|
||
"""
|
||
queryset = (models.Country.objects.annotate(
|
||
locale_name=KeyTextTransform(get_current_locale(), 'name')).order_by('locale_name'))
|
||
serializer_class = serializers.CountryBackSerializer
|
||
pagination_class = None
|
||
|
||
|
||
class CountryRUDView(CountryBaseViewMixin, generics.RetrieveUpdateDestroyAPIView):
|
||
"""
|
||
## Retrieve/Update/Destroy view.
|
||
### *GET*
|
||
#### Description
|
||
Retrieve serialized object of country by identifier
|
||
##### Response
|
||
E.g.:
|
||
```
|
||
{
|
||
"id": 1,
|
||
...
|
||
}
|
||
```
|
||
|
||
### *PUT*/*PATCH*
|
||
#### Description
|
||
Completely/Partially update an address object by an identifier.
|
||
##### Request
|
||
Available:
|
||
* code (`str`) - country code
|
||
* svg_image (`file`) - svg icon of country flag
|
||
* name (`str`) - country name
|
||
##### Response
|
||
E.g.:
|
||
```
|
||
{
|
||
"id": 1,
|
||
...
|
||
}
|
||
```
|
||
|
||
### *DELETE*
|
||
#### Description
|
||
Delete a country object by an identifier.
|
||
##### Response
|
||
E.g.:
|
||
```
|
||
No content
|
||
```
|
||
"""
|
||
serializer_class = serializers.CountryBackSerializer
|
||
|
||
|
||
class CountryCallingCodeListView(APIView):
|
||
"""
|
||
## Country codes view.
|
||
### Response
|
||
```
|
||
[
|
||
"+7",
|
||
"+386",
|
||
"+352"
|
||
]
|
||
```
|
||
### Description
|
||
Return an array of unique country code for all countries in a database.
|
||
"""
|
||
pagination_class = None
|
||
permission_classes = get_permission_classes(
|
||
IsEstablishmentManager,
|
||
IsEstablishmentAdministrator,
|
||
IsGuest,
|
||
)
|
||
|
||
def get(self, request, *args, **kwargs):
|
||
"""
|
||
## Country codes view.
|
||
### Response
|
||
```
|
||
[
|
||
"+7",
|
||
"+386",
|
||
"+352"
|
||
]
|
||
```
|
||
### Description
|
||
Return an array of unique country code for all countries in a database.
|
||
"""
|
||
return Response(data=models.Country.objects.aggregate_country_codes(),
|
||
status=status.HTTP_200_OK)
|