Skip to content

Commit fa8b61d

Browse files
Merge pull request #44 from CodeForPhilly/ts/add-location-endpoints
Add location endpoints
2 parents 2b03df7 + 15f97a9 commit fa8b61d

8 files changed

Lines changed: 185 additions & 16 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
- Added initial REST endpoints for Users [#23](https://github.com/CodeForPhilly/third-places/pull/23)
1313
- Added buttons at bottom of Map [#40](https://github.com/CodeForPhilly/third-places/pull/40)
14+
- Add location endpoints [#44](https://github.com/CodeForPhilly/third-places/pull/44)
1415

1516
### Changed
1617

src/django/api/admin.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,20 @@
11
from django.contrib import admin
2-
from .models import ThirdPlaceUser
2+
from .models import BusinessHours, Location, LocationType, Tag, TagType, ThirdPlaceUser
33

44
admin.site.register(ThirdPlaceUser)
5+
admin.site.register(BusinessHours)
6+
admin.site.register(LocationType)
7+
admin.site.register(Tag)
8+
admin.site.register(TagType)
9+
10+
@admin.register(Location)
11+
class LocationAdmin(admin.ModelAdmin):
12+
fields = (
13+
'name',
14+
'address',
15+
'hours',
16+
'location_type',
17+
'price_category',
18+
'tags',
19+
'location'
20+
)
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Generated by Django 4.2 on 2023-05-09 14:41
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('api', '0001_initial'),
10+
]
11+
12+
operations = [
13+
migrations.RemoveField(
14+
model_name='tag',
15+
name='locations',
16+
),
17+
migrations.AddField(
18+
model_name='location',
19+
name='tags',
20+
field=models.ManyToManyField(related_name='tags', to='api.tag'),
21+
),
22+
migrations.RemoveField(
23+
model_name='location',
24+
name='hours',
25+
),
26+
migrations.AddField(
27+
model_name='location',
28+
name='hours',
29+
field=models.ManyToManyField(blank=True, related_name='locations', to='api.businesshours'),
30+
),
31+
]

src/django/api/models.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -46,31 +46,31 @@ def __str__(self):
4646
return self.code
4747

4848

49-
class Location(models.Model):
50-
location = gis_models.PointField()
49+
class Tag(models.Model):
5150
name = models.TextField()
52-
address = models.TextField()
53-
hours = models.ForeignKey(BusinessHours, on_delete=models.CASCADE)
54-
location_type = models.ForeignKey(LocationType, on_delete=models.CASCADE)
55-
price_category = models.CharField(max_length=5)
51+
tag_type = models.ForeignKey(TagType, on_delete=models.CASCADE)
52+
value = models.DecimalField(decimal_places=1, max_digits=2)
5653
created_datetime = models.DateTimeField(auto_now_add=True)
5754
modified_datetime = models.DateTimeField(auto_now=True)
5855

59-
REQUIRED_FIELDS = ["location", "location_type", "created_datetime", "modified_datetime"]
56+
REQUIRED_FIELDS = ["name", "tag_type", "value", "created_datetime", "modified_datetime"]
6057

6158
def __str__(self):
6259
return self.name
6360

6461

65-
class Tag(models.Model):
62+
class Location(models.Model):
63+
location = gis_models.PointField(srid=4326)
6664
name = models.TextField()
67-
locations = models.ManyToManyField(Location, related_name='tags')
68-
tag_type = models.ForeignKey(TagType, on_delete=models.CASCADE)
69-
value = models.DecimalField(decimal_places=1, max_digits=2)
65+
address = models.TextField()
66+
hours = models.ManyToManyField(BusinessHours, related_name='locations', blank=True)
67+
location_type = models.ForeignKey(LocationType, on_delete=models.CASCADE)
68+
tags = models.ManyToManyField(Tag, related_name='tags')
69+
price_category = models.CharField(max_length=5)
7070
created_datetime = models.DateTimeField(auto_now_add=True)
7171
modified_datetime = models.DateTimeField(auto_now=True)
7272

73-
REQUIRED_FIELDS = ["name", "tag_type", "value", "created_datetime", "modified_datetime"]
73+
REQUIRED_FIELDS = ["location", "location_type", "created_datetime", "modified_datetime"]
7474

7575
def __str__(self):
7676
return self.name

src/django/api/serializers.py

Lines changed: 98 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,106 @@
11
import datetime
22

33
from rest_framework import serializers
4-
from .models import ThirdPlaceUser
4+
from rest_framework_gis import serializers as gis_serializers
5+
from .models import BusinessHours, Location, LocationType, ThirdPlaceUser, Tag, TagType
56

67

8+
class BusinessHoursSerializer(serializers.ModelSerializer):
9+
day = serializers.CharField()
10+
open_time = serializers.TimeField(required=False)
11+
close_time = serializers.TimeField(required=False)
12+
13+
class Meta:
14+
model = BusinessHours
15+
fields = (
16+
"day",
17+
"open_time",
18+
"close_time"
19+
)
20+
21+
22+
class LocationTypeSerializer(serializers.ModelSerializer):
23+
code = serializers.CharField()
24+
name = serializers.CharField()
25+
26+
class Meta:
27+
model = LocationType
28+
fields = (
29+
"code",
30+
"name"
31+
)
32+
33+
34+
class TagTypeSerializer(serializers.ModelSerializer):
35+
code = serializers.CharField()
36+
name = serializers.CharField()
37+
38+
class Meta:
39+
model = TagType
40+
fields = (
41+
"code",
42+
"name"
43+
)
44+
45+
46+
class TagSerializer(serializers.ModelSerializer):
47+
name = serializers.CharField()
48+
tag_type = TagTypeSerializer()
49+
value = serializers.DecimalField(decimal_places=1, max_digits=2)
50+
created_datetime = serializers.DateTimeField(read_only=True, initial=datetime.datetime)
51+
modified_datetime = serializers.DateTimeField(read_only=True, initial=datetime.datetime)
52+
53+
class Meta:
54+
model = Tag
55+
fields = (
56+
"name",
57+
"tag_type",
58+
"value",
59+
"created_datetime",
60+
"modified_datetime"
61+
)
62+
63+
def create(self, validated_data):
64+
tag_type_data = validated_data.pop("tag_type")
65+
tag_types = TagType.objects.create(**tag_type_data)
66+
return Tag.objects.create(tag_types, **validated_data)
67+
68+
69+
class LocationSerializer(gis_serializers.GeoFeatureModelSerializer):
70+
name = serializers.CharField()
71+
address = serializers.CharField()
72+
hours = BusinessHoursSerializer(many=True)
73+
location_type = LocationTypeSerializer()
74+
tags = TagSerializer(many=True)
75+
created_datetime = serializers.DateTimeField(read_only=True, initial=datetime.datetime)
76+
modified_datetime = serializers.DateTimeField(read_only=True, initial=datetime.datetime)
77+
78+
class Meta:
79+
model = Location
80+
geo_field="location"
81+
fields = (
82+
"name",
83+
"address",
84+
"hours",
85+
"location_type",
86+
"price_category",
87+
"tags",
88+
"created_datetime",
89+
"modified_datetime"
90+
)
91+
92+
def create(self, validated_data):
93+
hours_data = validated_data.pop("hours")
94+
location_type_data = validated_data.pop("location_type")
95+
tags_data = validated_data.pop("tags")
96+
location_type = LocationType.objects.create(**location_type_data)
97+
location = Location.objects.create(location_type=location_type, **validated_data)
98+
for hours_datum in hours_data:
99+
BusinessHoursSerializer(hours_datum)
100+
for tag_data in tags_data:
101+
TagSerializer(tag_data)
102+
return location
103+
7104
class ThirdPlaceUserSerializer(serializers.ModelSerializer):
8105
password = serializers.CharField(write_only=True)
9106
display_name = serializers.CharField(required=False)

src/django/api/urls.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
urlpatterns = [
66
path("", views.index, name="index"),
7+
path("locations/", views.location_list),
8+
path("locations/<int:pk>", views.location_detail),
79
path("users/", views.third_place_user_list),
810
path("users/<int:pk>", views.third_place_user_detail)
911
]

src/django/api/views.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,34 @@
22
from rest_framework import status
33
from rest_framework.decorators import api_view
44
from rest_framework.response import Response
5-
from .serializers import ThirdPlaceUserSerializer, ThirdPlaceUserPutSerializer
6-
from .models import ThirdPlaceUser
5+
from .serializers import LocationSerializer, ThirdPlaceUserSerializer, ThirdPlaceUserPutSerializer
6+
from .models import Location, ThirdPlaceUser
77

88

99
def index(request):
1010
return HttpResponse("Hello, world!")
1111

1212

13+
@api_view(['GET'])
14+
def location_list(request):
15+
if request.method == 'GET':
16+
locations = Location.objects.all()
17+
serializer = LocationSerializer(locations, many=True)
18+
return Response(serializer.data)
19+
20+
21+
@api_view(['GET'])
22+
def location_detail(request, pk):
23+
try:
24+
user = Location.objects.get(pk=pk)
25+
except Location.DoesNotExist:
26+
return Response(status=status.HTTP_404_NOT_FOUND)
27+
28+
if request.method == 'GET':
29+
serializer = LocationSerializer(user)
30+
return Response(serializer.data)
31+
32+
1333
@api_view(['GET', 'POST'])
1434
def third_place_user_list(request):
1535
if request.method == 'GET':

src/django/thirdplaces/settings.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,12 @@
3535
"django.contrib.admin",
3636
"django.contrib.auth",
3737
"django.contrib.contenttypes",
38+
"django.contrib.gis",
3839
"django.contrib.sessions",
3940
"django.contrib.messages",
4041
"django.contrib.staticfiles",
4142
"rest_framework",
43+
"rest_framework_gis",
4244
"api"
4345
]
4446

0 commit comments

Comments
 (0)