Skip to content

Commit 45ed122

Browse files
committed
enhance dining data (unfinished)
1 parent 97c9998 commit 45ed122

4 files changed

Lines changed: 157 additions & 21 deletions

File tree

backend/dining/api_wrapper.py

Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,24 @@
1515

1616
OPEN_DATA_URL = "https://3scale-public-prod-open-data.apps.k8s.upenn.edu/api/v1/dining/"
1717
OPEN_DATA_ENDPOINTS = {"VENUES": OPEN_DATA_URL + "venues", "MENUS": OPEN_DATA_URL + "menus"}
18+
DINING_ICON_IDS = {
19+
"vegetarian": "1",
20+
"vegan": "4",
21+
"kosher": "11",
22+
"jain": "141",
23+
"ask_us": "262",
24+
"peanut": "253",
25+
"tree_nut": "254",
26+
"fish": "255",
27+
"wheat_gluten": "257",
28+
"milk": "258",
29+
"egg": "259",
30+
"soy": "260",
31+
}
32+
# Sesame appears on the website but is absent from the venue cor_icons fixture,
33+
# so we do not have a stable upstream ID for it yet???
34+
# Halal (10) and shellfish (256) are stable upstream IDs but are not tracked here
35+
# because they are also not on the website.
1836

1937

2038
class DiningAPIWrapper:
@@ -44,6 +62,7 @@ def request(self, *args, **kwargs):
4462
self.update_token()
4563

4664
headers = {"Authorization": f"Bearer {self.token}"}
65+
print(headers)
4766

4867
# add authorization headers
4968
if "headers" in kwargs:
@@ -203,23 +222,36 @@ def load_stations(self, station_response, dining_menu):
203222
station.items.add(*items)
204223
station.save()
205224

225+
def _build_dining_item(self, key, value):
226+
icon_ids = value["cor_icon"] or {}
227+
return DiningItem(
228+
item_id=key,
229+
name=value["label"],
230+
description=value["description"],
231+
ingredients=value["ingredients"],
232+
vegetarian=DINING_ICON_IDS["vegetarian"] in icon_ids,
233+
vegan=DINING_ICON_IDS["vegan"] in icon_ids,
234+
kosher=DINING_ICON_IDS["kosher"] in icon_ids,
235+
jain=DINING_ICON_IDS["jain"] in icon_ids,
236+
ask_us=DINING_ICON_IDS["ask_us"] in icon_ids,
237+
peanut=DINING_ICON_IDS["peanut"] in icon_ids,
238+
tree_nut=DINING_ICON_IDS["tree_nut"] in icon_ids,
239+
sesame=False,
240+
fish=DINING_ICON_IDS["fish"] in icon_ids,
241+
wheat_gluten=DINING_ICON_IDS["wheat_gluten"] in icon_ids,
242+
milk=DINING_ICON_IDS["milk"] in icon_ids,
243+
egg=DINING_ICON_IDS["egg"] in icon_ids,
244+
soy=DINING_ICON_IDS["soy"] in icon_ids,
245+
nutrition_info=json.dumps(
246+
{
247+
x["label"]: f"{x['value']}{x['unit']}"
248+
for x in value["nutrition_details"].values()
249+
}
250+
),
251+
)
252+
206253
def load_items(self, item_response):
207-
item_list = [
208-
DiningItem(
209-
item_id=key,
210-
name=value["label"],
211-
description=value["description"],
212-
ingredients=value["ingredients"],
213-
allergens=", ".join(value["cor_icon"].values()) if value["cor_icon"] else "",
214-
nutrition_info=json.dumps(
215-
{
216-
x["label"]: f"{x['value']}{x['unit']}"
217-
for x in value["nutrition_details"].values()
218-
}
219-
),
220-
)
221-
for key, value in item_response.items()
222-
]
254+
item_list = [self._build_dining_item(key, value) for key, value in item_response.items()]
223255
# Ignore conflicts because possibility of duplicate items
224256
DiningItem.objects.bulk_create(
225257
item_list,
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# Generated by Django 5.0.2 on 2026-04-17 00:00
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
("dining", "0006_remove_diningmenu_stations_and_more"),
10+
]
11+
12+
operations = [
13+
migrations.RemoveField(
14+
model_name="diningitem",
15+
name="allergens",
16+
),
17+
migrations.AddField(
18+
model_name="diningitem",
19+
name="ask_us",
20+
field=models.BooleanField(default=False),
21+
),
22+
migrations.AddField(
23+
model_name="diningitem",
24+
name="egg",
25+
field=models.BooleanField(default=False),
26+
),
27+
migrations.AddField(
28+
model_name="diningitem",
29+
name="fish",
30+
field=models.BooleanField(default=False),
31+
),
32+
migrations.AddField(
33+
model_name="diningitem",
34+
name="jain",
35+
field=models.BooleanField(default=False),
36+
),
37+
migrations.AddField(
38+
model_name="diningitem",
39+
name="kosher",
40+
field=models.BooleanField(default=False),
41+
),
42+
migrations.AddField(
43+
model_name="diningitem",
44+
name="milk",
45+
field=models.BooleanField(default=False),
46+
),
47+
migrations.AddField(
48+
model_name="diningitem",
49+
name="peanut",
50+
field=models.BooleanField(default=False),
51+
),
52+
migrations.AddField(
53+
model_name="diningitem",
54+
name="sesame",
55+
field=models.BooleanField(default=False),
56+
),
57+
migrations.AddField(
58+
model_name="diningitem",
59+
name="soy",
60+
field=models.BooleanField(default=False),
61+
),
62+
migrations.AddField(
63+
model_name="diningitem",
64+
name="tree_nut",
65+
field=models.BooleanField(default=False),
66+
),
67+
migrations.AddField(
68+
model_name="diningitem",
69+
name="vegan",
70+
field=models.BooleanField(default=False),
71+
),
72+
migrations.AddField(
73+
model_name="diningitem",
74+
name="vegetarian",
75+
field=models.BooleanField(default=False),
76+
),
77+
migrations.AddField(
78+
model_name="diningitem",
79+
name="wheat_gluten",
80+
field=models.BooleanField(default=False),
81+
),
82+
]

backend/dining/models.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,24 @@ class DiningItem(models.Model):
1616
name = models.CharField(max_length=255)
1717
description = models.CharField(max_length=1000, blank=True)
1818
ingredients = models.CharField(max_length=1000, blank=True) # comma separated list
19-
allergens = models.CharField(max_length=1000, blank=True) # comma separated list
2019
nutrition_info = models.CharField(max_length=1000, blank=True) # json string.
2120
# Technically, postgres supports json fields but that involves local postgres
2221
# instead of sqlite AND we don't need to query on this field
2322

24-
# TODO: New fields to add from allergens:
25-
# vegetarian, vegan, kosher, jain, ask us
26-
# peanut, tree nut, sesame, fish, wheat/gluten, milk, egg, soy
23+
# 23 dietary information fields (stored as cor_icons)
24+
vegetarian = models.BooleanField(default=False)
25+
vegan = models.BooleanField(default=False)
26+
kosher = models.BooleanField(default=False)
27+
jain = models.BooleanField(default=False)
28+
ask_us = models.BooleanField(default=False)
29+
peanut = models.BooleanField(default=False)
30+
tree_nut = models.BooleanField(default=False)
31+
sesame = models.BooleanField(default=False)
32+
fish = models.BooleanField(default=False)
33+
wheat_gluten = models.BooleanField(default=False)
34+
milk = models.BooleanField(default=False)
35+
egg = models.BooleanField(default=False)
36+
soy = models.BooleanField(default=False)
2737

2838
def __str__(self):
2939
return f"{self.name}"

backend/tests/dining/test_views.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,19 @@ def try_structure(self, data):
137137
self.assertIn("name", item)
138138
self.assertIn("description", item)
139139
self.assertIn("ingredients", item)
140-
self.assertIn("allergens", item)
140+
self.assertIn("vegetarian", item)
141+
self.assertIn("vegan", item)
142+
self.assertIn("kosher", item)
143+
self.assertIn("jain", item)
144+
self.assertIn("ask_us", item)
145+
self.assertIn("peanut", item)
146+
self.assertIn("tree_nut", item)
147+
self.assertIn("sesame", item)
148+
self.assertIn("fish", item)
149+
self.assertIn("wheat_gluten", item)
150+
self.assertIn("milk", item)
151+
self.assertIn("egg", item)
152+
self.assertIn("soy", item)
141153
self.assertIn("nutrition_info", item)
142154

143155
def test_get_default(self):

0 commit comments

Comments
 (0)