From 599663cebe71609b99c8d0679421809ac381a4aa Mon Sep 17 00:00:00 2001 From: KicksTV Date: Tue, 4 Aug 2026 09:03:46 +0000 Subject: [PATCH] feat: demonstrate natural-key DELETE in example scripts The natural-key detail endpoints now support DELETE, so the example scripts no longer need to fall back to the generic /api/events/ endpoint: - update_competitor.py: creates a throwaway competitor, DELETEs it via the natural-key URL, verifies 404 - update_events.py: DELETEs via the natural-key URL instead of the generic endpoint (the event is re-created afterwards as before) - update_units.py: creates a throwaway event/unit, DELETEs the unit via the natural-key URL, verifies 404 Each DELETE example only ever removes the resource it just created, so the scripts remain repeatable. --- update_competitor.py | 35 +++++++++++++++++++++++++++++++++++ update_events.py | 12 +++++------- update_units.py | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 7 deletions(-) diff --git a/update_competitor.py b/update_competitor.py index 7f72bd6..f9cca16 100644 --- a/update_competitor.py +++ b/update_competitor.py @@ -7,6 +7,8 @@ https://test-data.opentrack.run/en-gb/x/2026/GBR/lac-open-2/ To manipulate any competition, you will need to pick one that you have meeting director access to. + +Also demonstrates DELETE of a throwaway competitor via the natural-key URL. """ import requests @@ -83,6 +85,39 @@ def run(): print(resp) print(resp.text) + # DELETE example: create a throwaway competitor, then remove it via the + # natural-key URL so the script stays repeatable (it only ever deletes + # the competitor it just created, never real data). + import uuid + temp_bib = "9%s" % uuid.uuid4().hex[:5].upper() + create_payload = { + "competitor_id": temp_bib, + "first_name": "Throwaway", + "last_name": "Delete", + "gender": "M", + "competition": target["competition"], + "team_id": "KACPH", + "nationality": "GBR", + } + resp = requests.post(f"{BASE_URL}/api/competitors/", json=create_payload, headers=headers) + print(f" POST throwaway competitor ({temp_bib}): {resp.status_code}") + if resp.status_code != 201: + raise ValueError(f"Status code not 201: {resp.text[:300]}") + + temp_url = f"{comp_url}competitors/{temp_bib}/" + resp = requests.get(temp_url, headers=headers) + print(f" GET throwaway competitor: {resp.status_code}") + + resp = requests.delete(temp_url, headers=headers) + print(f" DELETE competitor (natural key): {resp.status_code}") + if resp.status_code != 204: + raise ValueError(f"Status code not 204: {resp.text[:300]}") + + resp = requests.get(temp_url, headers=headers) + print(f" GET deleted competitor: {resp.status_code} (expect 404)") + if resp.status_code != 404: + raise ValueError("Status code not 404") + if __name__ == '__main__': diff --git a/update_events.py b/update_events.py index e943e79..082a938 100644 --- a/update_events.py +++ b/update_events.py @@ -70,16 +70,14 @@ def run(): if resp.status_code != 200: raise ValueError("Status code not 200") - # Delete - there is no natural-key DELETE route, so fall back to the - # generic /api/events/ endpoint with the SQL id from the listing. - sql_id = original_event['id'] - generic_url = f"{BASE_URL}/api/events/{sql_id}/" - print(f" DELETE to {generic_url}") - resp = requests.delete(generic_url, headers=headers) + # Delete - the natural-key URL supports DELETE too; it removes the + # event and its units and returns 204. + print(f" DELETE to {event_url}") + resp = requests.delete(event_url, headers=headers) if resp.status_code != 204: raise ValueError("Status code not 204") - # Create - there is no natural-key POST route either, so use the generic + # Create - there is no natural-key POST route, so use the generic # endpoint. The competition field still needs the UUID here. original_event['parent'] = '' print(f" POST to {BASE_URL}/api/events/") diff --git a/update_units.py b/update_units.py index 0447f10..ba26606 100644 --- a/update_units.py +++ b/update_units.py @@ -112,6 +112,43 @@ def run(): print("Response..") print(resp.json()) + # DELETE example: create a throwaway event (which auto-creates an empty + # unit at .../1/1/), then remove the unit via the natural-key URL so the + # script stays repeatable (it only ever deletes what it just created). + import uuid + temp_event_id = "TMP%s" % uuid.uuid4().hex[:6].upper() + create_event_payload = { + "competition": unit["competition"], + "event_id": temp_event_id, + "event_code": "150", + "age_groups": "SEN", + "genders": "MF", + "category": "SM,SW", + "limit": 32, + "name": "Throwaway Delete Unit", + "rounds": "1", + "day": 1, + "r1_time": "10:00", + } + resp = requests.post(f"{BASE_URL}/api/events/", json=create_event_payload, headers=headers) + print(f" POST throwaway event ({temp_event_id}): {resp.status_code}") + if resp.status_code != 201: + raise ValueError(f"Status code not 201: {resp.text[:300]}") + + temp_unit_url = f"{comp_url}events/{temp_event_id}/1/1/" + resp = requests.get(temp_unit_url, headers=headers) + print(f" GET throwaway unit: {resp.status_code}") + + resp = requests.delete(temp_unit_url, headers=headers) + print(f" DELETE unit (natural key): {resp.status_code}") + if resp.status_code != 204: + raise ValueError(f"Status code not 204: {resp.text[:300]}") + + resp = requests.get(temp_unit_url, headers=headers) + print(f" GET deleted unit: {resp.status_code} (expect 404)") + if resp.status_code != 404: + raise ValueError("Status code not 404") + if __name__ == '__main__': run()