location.py 4.9 KB
Newer Older
1
from django.db import models
Florent Chehab's avatar
Florent Chehab committed
2
from rest_framework import serializers, viewsets, permissions
3

Florent Chehab's avatar
Florent Chehab committed
4
5
6
7
8
9
10
# Data model based on : https://unstats.un.org/unsd/methodology/m49/overview/


class Region(models.Model):
    name = models.CharField(max_length=200)
    un_code = models.CharField(primary_key=True, max_length=3)
    parent = models.ForeignKey(
Florent Chehab's avatar
Florent Chehab committed
11
        'self', on_delete=models.SET_NULL, null=True, blank=True)
Florent Chehab's avatar
Florent Chehab committed
12

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
    def r_type(self):
        p = 0
        region = self
        while region.parent is not None:
            p += 1
            region = region.parent

        if p is 0:
            return "main"
        elif p is 1:
            return "sub"
        elif p is 2:
            return "inter"
        else:
            raise Exception("Impossible case found")

Florent Chehab's avatar
Florent Chehab committed
29

30
class Country(models.Model):
31
    name = models.CharField(max_length=200)
32
    iso_alpha2_code = models.CharField(primary_key=True, max_length=2)
Florent Chehab's avatar
Florent Chehab committed
33
34
    region = models.ForeignKey(
        Region, on_delete=models.PROTECT, null=True, blank=True)
Florent Chehab's avatar
Florent Chehab committed
35

36
37
38
39
40
41
42
43
    def get_regions(self):
        regions = [None] * 3
        regions.append(self.region)
        while regions[-1] is not None and regions[-1].parent is not None:
            regions.append(regions[-1].parent)
        regions = regions[::-1]
        return regions[0:3]

Florent Chehab's avatar
Florent Chehab committed
44

Florent Chehab's avatar
Florent Chehab committed
45
46
class City(models.Model):
    name = models.CharField(max_length=200)
Florent Chehab's avatar
Florent Chehab committed
47
    local_name = models.CharField(max_length=200, null=True, blank=True)
Florent Chehab's avatar
Florent Chehab committed
48
49
    # We add an area to distinguish similarly named cities
    # in a country
Florent Chehab's avatar
Florent Chehab committed
50
    area = models.CharField(max_length=200, null=True, blank=True)
Florent Chehab's avatar
Florent Chehab committed
51
52
53
    country = models.ForeignKey(Country, on_delete=models.PROTECT)


Florent Chehab's avatar
Florent Chehab committed
54
55
56
"""
API RELATED STUFF BELLOW
"""
Florent Chehab's avatar
Florent Chehab committed
57
58


Florent Chehab's avatar
Florent Chehab committed
59
60
61
62
class CountrySerializer(serializers.ModelSerializer):
    regions = serializers.SerializerMethodField()

    def get_regions(self, obj):
63
64
65
66
67
68
69
70
71
72
73
74
        regions = obj.get_regions()

        def get_info(i):
            r = regions[i]
            r_code = r.un_code if r is not None else None
            return {"code": r_code,
                    "url": self.get_region_url(regions[i])}
        res = {}
        res["main"] = get_info(0)
        res["sub"] = get_info(1)
        res["inter"] = get_info(2)
        return res
Florent Chehab's avatar
Florent Chehab committed
75
76
77
78
79
80
81
82
83
84
85

    def get_region_url(self, region):
        if region is None:
            return None

        return serializers.HyperlinkedRelatedField(
            view_name='country-detail',
            read_only=True) \
            .get_url(region, view_name='region-detail',
                     request=self.context['request'], format=None)

Florent Chehab's avatar
Florent Chehab committed
86
87
    class Meta:
        model = Country
88
        fields = ('name', 'iso_alpha2_code',
89
                  'region', 'regions')
Florent Chehab's avatar
Florent Chehab committed
90
91


Florent Chehab's avatar
Florent Chehab committed
92
93
94
95
96
97
98
class DictModeViewSet(viewsets.ModelViewSet):
    """
    ViewSet that renders data as dict with keys corresponding to the model
    primary key. Instead of list.
    """

    def list(self, request, *args, **kwargs):
Florent Chehab's avatar
Florent Chehab committed
99
        response = super(viewsets.ModelViewSet, self).list(  # pylint: disable=E1003
Florent Chehab's avatar
Florent Chehab committed
100
101
102
103
104
105
106
107
108
            request, *args, **kwargs)  # call the original 'list'
        pk_attr_name = self.serializer_class.Meta.model._meta.pk.name
        response.data = {
            d[pk_attr_name]: d for d in response.data
        }
        return response


class CountryViewSet(DictModeViewSet):
Florent Chehab's avatar
Florent Chehab committed
109
    permission_classes = (permissions.DjangoModelPermissions,)
Florent Chehab's avatar
Florent Chehab committed
110
    queryset = Country.objects.all()  # pylint: disable=E1101
Florent Chehab's avatar
Florent Chehab committed
111
    serializer_class = CountrySerializer
Florent Chehab's avatar
Florent Chehab committed
112
113


Florent Chehab's avatar
Florent Chehab committed
114
115
class RegionSerializer(serializers.ModelSerializer):
    parent_url = serializers.SerializerMethodField()
116
    region_type = serializers.SerializerMethodField()
Florent Chehab's avatar
Florent Chehab committed
117
118
119
120
121
122
123
124
125
126
127

    def get_parent_url(self, obj):
        if obj.parent is None:
            return None

        return serializers.HyperlinkedRelatedField(
            view_name='country-detail',
            read_only=True) \
            .get_url(obj.parent, view_name='region-detail',
                     request=self.context['request'], format=None)

128
129
130
    def get_region_type(self, obj):
        return obj.r_type()

Florent Chehab's avatar
Florent Chehab committed
131
132
    class Meta:
        model = Region
133
        fields = ('name', 'un_code', 'parent', 'parent_url', 'region_type')
Florent Chehab's avatar
Florent Chehab committed
134
135


Florent Chehab's avatar
Florent Chehab committed
136
class RegionViewSet(DictModeViewSet):
Florent Chehab's avatar
Florent Chehab committed
137
    permission_classes = (permissions.DjangoModelPermissions,)
Florent Chehab's avatar
Florent Chehab committed
138
    queryset = Region.objects.all()  # pylint: disable=E1101
Florent Chehab's avatar
Florent Chehab committed
139
    serializer_class = RegionSerializer
Florent Chehab's avatar
Florent Chehab committed
140
141
142
143
144
145
146
147
148


class CitySerializer(serializers.ModelSerializer):
    country_url = serializers.SerializerMethodField()

    def get_country_url(self, obj):
        return serializers.HyperlinkedRelatedField(
            view_name='country-detail',
            read_only=True) \
Florent Chehab's avatar
Florent Chehab committed
149
            .get_url(obj.country, view_name='country-detail',
Florent Chehab's avatar
Florent Chehab committed
150
151
152
153
                     request=self.context['request'], format=None)

    class Meta:
        model = City
Florent Chehab's avatar
Florent Chehab committed
154
        fields = ('name', 'local_name', 'area', 'country', 'country_url', 'id')
Florent Chehab's avatar
Florent Chehab committed
155
156


Florent Chehab's avatar
Florent Chehab committed
157
class CityViewSet(DictModeViewSet):
Florent Chehab's avatar
Florent Chehab committed
158
    permission_classes = (permissions.DjangoModelPermissions,)
Florent Chehab's avatar
Florent Chehab committed
159
    queryset = City.objects.all()  # pylint: disable=E1101
Florent Chehab's avatar
Florent Chehab committed
160
    serializer_class = CitySerializer