Skip to content

Commit d79ab11

Browse files
replicating changes off of main (#311)
1 parent 23820a3 commit d79ab11

File tree

7 files changed

+61
-38
lines changed

7 files changed

+61
-38
lines changed

backend/app/tests/test_routing.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,5 +77,5 @@ def test_fhir_rest_routes_reverse_without_slash(self):
7777
endpoint_list_path = reverse("fhir-endpoint-list")
7878
self.assertEqual(endpoint_list_path, "/fhir/Endpoint")
7979

80-
endpoint_detail_path = reverse("fhir-endpoint-detail", kwargs={"pk": 12345})
80+
endpoint_detail_path = reverse("fhir-endpoint-detail", kwargs={"id": 12345})
8181
self.assertEqual(endpoint_detail_path, "/fhir/Endpoint/12345")

backend/npdfhir/models.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -645,8 +645,8 @@ class Meta:
645645

646646

647647
class Provider(models.Model):
648-
npi = models.OneToOneField(Npi, models.DO_NOTHING, db_column="npi", primary_key=True)
649-
individual = models.OneToOneField(Individual, models.DO_NOTHING, blank=True, null=True)
648+
npi = models.OneToOneField(Npi, models.DO_NOTHING, db_column="npi")
649+
individual = models.OneToOneField(Individual, models.DO_NOTHING, primary_key=True)
650650

651651
class Meta:
652652
managed = False
@@ -655,7 +655,7 @@ class Meta:
655655

656656
class ProviderEducation(models.Model):
657657
pk = models.CompositePrimaryKey("npi", "school_id")
658-
npi = models.ForeignKey(Provider, models.DO_NOTHING, db_column="npi")
658+
npi = models.ForeignKey(Provider, models.DO_NOTHING, db_column="npi", to_field="npi")
659659
school_id = models.IntegerField()
660660
degree_type = models.ForeignKey(DegreeType, models.DO_NOTHING)
661661
start_date = models.DateField(blank=True, null=True)
@@ -711,7 +711,7 @@ class Meta:
711711

712712

713713
class ProviderToOrganization(models.Model):
714-
individual = models.ForeignKey(Provider, models.DO_NOTHING, to_field="individual_id")
714+
individual = models.ForeignKey(Provider, models.DO_NOTHING)
715715
organization = models.ForeignKey(Organization, models.DO_NOTHING)
716716
relationship_type = models.ForeignKey("RelationshipType", models.DO_NOTHING)
717717
id = models.UUIDField(primary_key=True)
@@ -725,7 +725,7 @@ class Meta:
725725

726726
class ProviderToOtherId(models.Model):
727727
pk = models.CompositePrimaryKey("npi", "other_id", "other_id_type_id", "issuer", "state_code")
728-
npi = models.ForeignKey(Provider, models.DO_NOTHING, db_column="npi")
728+
npi = models.ForeignKey(Provider, models.DO_NOTHING, db_column="npi", to_field="npi")
729729
other_id = models.CharField(max_length=100)
730730
other_id_type = models.ForeignKey(OtherIdType, models.DO_NOTHING)
731731
state_code = models.ForeignKey(FipsState, models.DO_NOTHING, db_column="state_code")
@@ -737,7 +737,7 @@ class Meta:
737737

738738

739739
class ProviderToTaxonomy(models.Model):
740-
npi = models.ForeignKey(Provider, models.DO_NOTHING, db_column="npi")
740+
npi = models.ForeignKey(Provider, models.DO_NOTHING, db_column="npi", to_field="npi")
741741
nucc_code = models.ForeignKey(Nucc, models.DO_NOTHING, db_column="nucc_code")
742742
is_primary = models.BooleanField(blank=True, null=True)
743743
id = models.UUIDField(primary_key=True)

backend/npdfhir/serializers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -705,7 +705,7 @@ def to_representation(self, instance):
705705
resource_type = resource["resourceType"]
706706
id = resource["id"]
707707
url_name = f"fhir-{resource_type.lower()}-detail"
708-
full_url = request.build_absolute_uri(reverse(url_name, kwargs={"pk": id}))
708+
full_url = request.build_absolute_uri(reverse(url_name, kwargs={"id": id}))
709709
# Create an entry for this resource
710710
entry = {
711711
"fullUrl": full_url,

backend/npdfhir/tests/fixtures/practitioner.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import datetime
2+
import random
23
import uuid
34

45
from ...models import (
@@ -81,8 +82,10 @@ def create_practitioner(
8182
individual=individual, address=location.address, address_use=use
8283
)
8384

85+
npi_value = npi_value or random.randint(1000000000, 9999999999)
86+
8487
npi = Npi.objects.create(
85-
npi=npi_value or int(str(uuid.uuid4().int)[:10]),
88+
npi=npi_value,
8689
entity_type_code=1,
8790
enumeration_date=datetime.date(2000, 1, 1),
8891
last_update_date=datetime.date(2020, 1, 1),

backend/npdfhir/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def get_schema_data(request):
2727

2828

2929
def genReference(url_name, identifier, request):
30-
reference = request.build_absolute_uri(reverse(url_name, kwargs={"pk": identifier}))
30+
reference = request.build_absolute_uri(reverse(url_name, kwargs={"id": identifier}))
3131
reference = Reference(reference=reference)
3232
return reference
3333

backend/npdfhir/views.py

Lines changed: 37 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,47 @@
11
from uuid import UUID
22

3-
from django.conf import settings
4-
from django.db.models import CharField, F, Value
3+
from django.db.models import F, Value, CharField
54
from django.db.models.functions import Concat
65
from django.http import HttpResponse
76
from django.shortcuts import get_object_or_404
87
from django.utils.html import escape
98
from django_filters.rest_framework import DjangoFilterBackend
10-
from drf_spectacular.utils import OpenApiResponse, extend_schema
9+
from drf_spectacular.utils import extend_schema, OpenApiResponse
1110
from rest_framework import viewsets
12-
from rest_framework.filters import OrderingFilter, SearchFilter
11+
from rest_framework.views import APIView
1312
from rest_framework.renderers import BrowsableAPIRenderer
1413
from rest_framework.response import Response
15-
from rest_framework.views import APIView
14+
from rest_framework.filters import SearchFilter, OrderingFilter
15+
16+
from .pagination import CustomPaginator
17+
from .renderers import FHIRRenderer
1618

1719
from .filters.endpoint_filter_set import EndpointFilterSet
1820
from .filters.location_filter_set import LocationFilterSet
1921
from .filters.organization_filter_set import OrganizationFilterSet
2022
from .filters.practitioner_filter_set import PractitionerFilterSet
2123
from .filters.practitioner_role_filter_set import PractitionerRoleFilterSet
24+
2225
from .models import (
2326
EndpointInstance,
2427
Location,
2528
Organization,
2629
Provider,
2730
ProviderToLocation,
2831
)
29-
from .pagination import CustomPaginator
30-
from .renderers import FHIRRenderer
32+
3133
from .serializers import (
3234
BundleSerializer,
33-
CapabilityStatementSerializer,
3435
EndpointSerializer,
3536
LocationSerializer,
3637
OrganizationSerializer,
3738
PractitionerRoleSerializer,
3839
PractitionerSerializer,
40+
CapabilityStatementSerializer,
3941
)
4042

43+
from django.conf import settings
44+
4145
DEBUG = settings.DEBUG
4246

4347

@@ -68,6 +72,7 @@ class FHIREndpointViewSet(viewsets.GenericViewSet):
6872
ordering_fields = ["name", "address", "ehr_vendor_name"]
6973
pagination_class = CustomPaginator
7074
pagination_class = CustomPaginator
75+
lookup_url_kwarg = "id"
7176

7277
@extend_schema(
7378
responses={
@@ -113,15 +118,15 @@ def list(self, request):
113118
200: OpenApiResponse(description="Successfully retrieved FHIR Endpoint resource")
114119
}
115120
)
116-
def retrieve(self, request, pk=None):
121+
def retrieve(self, request, id=None):
117122
"""
118123
Query a specific endpoint as a FHIR Endpoint resource
119124
"""
120125

121126
try:
122-
UUID(pk)
127+
UUID(id)
123128
except (ValueError, TypeError):
124-
return HttpResponse(f"Endpoint {escape(pk)} not found", status=404)
129+
return HttpResponse(f"Endpoint {escape(id)} not found", status=404)
125130

126131
endpoint = get_object_or_404(
127132
EndpointInstance.objects.prefetch_related(
@@ -132,7 +137,7 @@ def retrieve(self, request, pk=None):
132137
"endpointinstancetopayload_set__mime_type",
133138
"endpointinstancetootherid_set",
134139
),
135-
pk=pk,
140+
id=id,
136141
)
137142

138143
serialized_endpoint = EndpointSerializer(endpoint, context={"request": request})
@@ -156,6 +161,7 @@ class FHIRPractitionerViewSet(viewsets.GenericViewSet):
156161
filter_backends = [DjangoFilterBackend, SearchFilter, ParamOrderingFilter]
157162
filterset_class = PractitionerFilterSet
158163
pagination_class = CustomPaginator
164+
lookup_url_kwarg = "id"
159165

160166
ordering_fields = [
161167
"individual__individualtoname__last_name",
@@ -213,14 +219,14 @@ def list(self, request):
213219
200: OpenApiResponse(description="Successfully retrieved FHIR Practitioner resource")
214220
}
215221
)
216-
def retrieve(self, request, pk=None):
222+
def retrieve(self, request, id=None):
217223
"""
218224
Query a specific provider as a FHIR Practitioner resource
219225
"""
220226
try:
221-
UUID(pk)
227+
UUID(id)
222228
except (ValueError, TypeError):
223-
return HttpResponse(f"Practitioner {escape(pk)} not found", status=404)
229+
return HttpResponse(f"Practitioner {escape(id)} not found", status=404)
224230

225231
provider = get_object_or_404(
226232
Provider.objects.prefetch_related(
@@ -236,7 +242,7 @@ def retrieve(self, request, pk=None):
236242
"providertootherid_set",
237243
"providertotaxonomy_set",
238244
),
239-
individual_id=pk,
245+
individual_id=id,
240246
)
241247

242248
serialized_practitioner = PractitionerSerializer(provider)
@@ -260,6 +266,7 @@ class FHIRPractitionerRoleViewSet(viewsets.GenericViewSet):
260266
filter_backends = [DjangoFilterBackend, SearchFilter, ParamOrderingFilter]
261267
filterset_class = PractitionerRoleFilterSet
262268
pagination_class = CustomPaginator
269+
lookup_url_kwarg = "id"
263270

264271
ordering_fields = ["location__name", "practitioner_first_name", "practitioner_last_name"]
265272

@@ -304,16 +311,16 @@ def list(self, request):
304311
)
305312
}
306313
)
307-
def retrieve(self, request, pk=None):
314+
def retrieve(self, request, id=None):
308315
"""
309316
Query a specific relationship between providers, healthcare organizations, and practice locations, represented as a FHIR PractitionerRole resource
310317
"""
311318
try:
312-
UUID(pk)
319+
UUID(id)
313320
except (ValueError, TypeError):
314-
return HttpResponse(f"PractitionerRole {escape(pk)} not found", status=404)
321+
return HttpResponse(f"PractitionerRole {escape(id)} not found", status=404)
315322

316-
practitionerrole = get_object_or_404(ProviderToLocation, pk=pk)
323+
practitionerrole = get_object_or_404(ProviderToLocation, id=id)
317324

318325
serialized_practitionerrole = PractitionerRoleSerializer(
319326
practitionerrole, context={"request": request}
@@ -338,6 +345,7 @@ class FHIROrganizationViewSet(viewsets.GenericViewSet):
338345
filter_backends = [DjangoFilterBackend, SearchFilter, ParamOrderingFilter]
339346
filterset_class = OrganizationFilterSet
340347
pagination_class = CustomPaginator
348+
lookup_url_kwarg = "id"
341349

342350
ordering_fields = ["organizationtoname__name"]
343351

@@ -399,14 +407,14 @@ def list(self, request):
399407
200: OpenApiResponse(description="Successfully retrieved FHIR Organization resource")
400408
}
401409
)
402-
def retrieve(self, request, pk=None):
410+
def retrieve(self, request, id=None):
403411
"""
404412
Query a specific organization, represented as a FHIR Organization resource
405413
"""
406414
try:
407-
UUID(pk)
415+
UUID(id)
408416
except (ValueError, TypeError):
409-
return HttpResponse(f"Organization {escape(pk)} not found", status=404)
417+
return HttpResponse(f"Organization {escape(id)} not found", status=404)
410418

411419
organization = get_object_or_404(
412420
Organization.objects.prefetch_related(
@@ -431,7 +439,7 @@ def retrieve(self, request, pk=None):
431439
"clinicalorganization__organizationtotaxonomy_set",
432440
"clinicalorganization__organizationtotaxonomy_set__nucc_code",
433441
),
434-
pk=pk,
442+
id=id,
435443
)
436444

437445
serialized_organization = OrganizationSerializer(organization, context={"request": request})
@@ -455,6 +463,7 @@ class FHIRLocationViewSet(viewsets.GenericViewSet):
455463
filter_backends = [DjangoFilterBackend, SearchFilter, ParamOrderingFilter]
456464
filterset_class = LocationFilterSet
457465
pagination_class = CustomPaginator
466+
lookup_url_kwarg = "id"
458467

459468
ordering_fields = ["organization_name", "address_full", "name"]
460469

@@ -512,16 +521,16 @@ def list(self, request):
512521
200: OpenApiResponse(description="Successfully retrieved FHIR Location resource")
513522
}
514523
)
515-
def retrieve(self, request, pk=None):
524+
def retrieve(self, request, id=None):
516525
"""
517526
Query a specific healthcare practice location as a FHIR Location resource
518527
"""
519528
try:
520-
UUID(pk)
529+
UUID(id)
521530
except (ValueError, TypeError):
522-
return HttpResponse(f"Location {escape(pk)} not found", status=404)
531+
return HttpResponse(f"Location {escape(id)} not found", status=404)
523532

524-
location = get_object_or_404(Location, pk=pk)
533+
location = get_object_or_404(Location, id=id)
525534

526535
serialized_location = LocationSerializer(location, context={"request": request})
527536

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
-- DRF Spectacular documentation was reading from the model definition and not the API construction (indicating that Practitioners could be retrieved by NPI), so these migrations update the database to reflect the querying pattern in the API (Practitioners retrieved by individual_id)
2+
alter table npd.provider_education drop constraint fk_provider_education_npi;
3+
alter table npd.provider_to_other_id drop constraint fk_provider_to_other_id_npi;
4+
alter table npd.provider_to_taxonomy drop constraint fk_provider_to_taxonomy_npi;
5+
alter table npd.provider drop constraint pk_provider;
6+
alter table npd.provider alter column individual_id set not null;
7+
alter table npd.provider add constraint pk_provider primary key (individual_id);
8+
alter table npd.provider add constraint uc_provider_npi UNIQUE (npi);
9+
alter table npd.provider_education add constraint fk_provider_education_npi foreign key (npi) references npd.provider(npi);
10+
alter table npd.provider_to_other_id add constraint fk_provider_to_other_id_npi foreign key (npi) references npd.provider(npi);
11+
alter table npd.provider_to_taxonomy add constraint fk_provider_to_taxonomy_npi foreign key (npi) references npd.provider(npi);

0 commit comments

Comments
 (0)