Skip to content

Commit 21c2175

Browse files
[NDH-692] Updating provider pk (#308)
* Updating provider pk * cleaning up models.py * one more cleanup * update retrieve param naming for clarity
1 parent db1d1b2 commit 21c2175

7 files changed

Lines changed: 48 additions & 30 deletions

File tree

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
@@ -707,7 +707,7 @@ def to_representation(self, instance):
707707
resource_type = resource["resourceType"]
708708
id = resource["id"]
709709
url_name = f"fhir-{resource_type.lower()}-detail"
710-
full_url = request.build_absolute_uri(reverse(url_name, kwargs={"pk": id}))
710+
full_url = request.build_absolute_uri(reverse(url_name, kwargs={"id": id}))
711711
# Create an entry for this resource
712712
entry = {
713713
"fullUrl": full_url,

backend/npdfhir/tests/fixtures.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,10 @@ def create_practitioner(
7575
individual=individual, address=location.address, address_use=use
7676
)
7777

78+
npi_value = npi_value or random.randint(1000000000, 9999999999)
79+
7880
npi = Npi.objects.create(
79-
npi=npi_value or int(str(uuid.uuid4().int)[:10]),
81+
npi=npi_value,
8082
entity_type_code=1,
8183
enumeration_date=datetime.date(2000, 1, 1),
8284
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: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ class FHIREndpointViewSet(viewsets.GenericViewSet):
7272
ordering_fields = ["name", "address", "ehr_vendor_name"]
7373
pagination_class = CustomPaginator
7474
pagination_class = CustomPaginator
75+
lookup_url_kwarg = "id"
7576

7677
@extend_schema(
7778
responses={
@@ -117,15 +118,15 @@ def list(self, request):
117118
200: OpenApiResponse(description="Successfully retrieved FHIR Endpoint resource")
118119
}
119120
)
120-
def retrieve(self, request, pk=None):
121+
def retrieve(self, request, id=None):
121122
"""
122123
Query a specific endpoint as a FHIR Endpoint resource
123124
"""
124125

125126
try:
126-
UUID(pk)
127+
UUID(id)
127128
except (ValueError, TypeError):
128-
return HttpResponse(f"Endpoint {escape(pk)} not found", status=404)
129+
return HttpResponse(f"Endpoint {escape(id)} not found", status=404)
129130

130131
endpoint = get_object_or_404(
131132
EndpointInstance.objects.prefetch_related(
@@ -136,7 +137,7 @@ def retrieve(self, request, pk=None):
136137
"endpointinstancetopayload_set__mime_type",
137138
"endpointinstancetootherid_set",
138139
),
139-
pk=pk,
140+
id=id,
140141
)
141142

142143
serialized_endpoint = EndpointSerializer(endpoint, context={"request": request})
@@ -160,6 +161,7 @@ class FHIRPractitionerViewSet(viewsets.GenericViewSet):
160161
filter_backends = [DjangoFilterBackend, SearchFilter, ParamOrderingFilter]
161162
filterset_class = PractitionerFilterSet
162163
pagination_class = CustomPaginator
164+
lookup_url_kwarg = "id"
163165

164166
ordering_fields = [
165167
"individual__individualtoname__last_name",
@@ -217,14 +219,14 @@ def list(self, request):
217219
200: OpenApiResponse(description="Successfully retrieved FHIR Practitioner resource")
218220
}
219221
)
220-
def retrieve(self, request, pk=None):
222+
def retrieve(self, request, id=None):
221223
"""
222224
Query a specific provider as a FHIR Practitioner resource
223225
"""
224226
try:
225-
UUID(pk)
227+
UUID(id)
226228
except (ValueError, TypeError):
227-
return HttpResponse(f"Practitioner {escape(pk)} not found", status=404)
229+
return HttpResponse(f"Practitioner {escape(id)} not found", status=404)
228230

229231
provider = get_object_or_404(
230232
Provider.objects.prefetch_related(
@@ -240,7 +242,7 @@ def retrieve(self, request, pk=None):
240242
"providertootherid_set",
241243
"providertotaxonomy_set",
242244
),
243-
individual_id=pk,
245+
individual_id=id,
244246
)
245247

246248
serialized_practitioner = PractitionerSerializer(provider)
@@ -264,6 +266,7 @@ class FHIRPractitionerRoleViewSet(viewsets.GenericViewSet):
264266
filter_backends = [DjangoFilterBackend, SearchFilter, ParamOrderingFilter]
265267
filterset_class = PractitionerRoleFilterSet
266268
pagination_class = CustomPaginator
269+
lookup_url_kwarg = "id"
267270

268271
ordering_fields = ["location__name", "practitioner_first_name", "practitioner_last_name"]
269272

@@ -308,16 +311,16 @@ def list(self, request):
308311
)
309312
}
310313
)
311-
def retrieve(self, request, pk=None):
314+
def retrieve(self, request, id=None):
312315
"""
313316
Query a specific relationship between providers, healthcare organizations, and practice locations, represented as a FHIR PractitionerRole resource
314317
"""
315318
try:
316-
UUID(pk)
319+
UUID(id)
317320
except (ValueError, TypeError):
318-
return HttpResponse(f"PractitionerRole {escape(pk)} not found", status=404)
321+
return HttpResponse(f"PractitionerRole {escape(id)} not found", status=404)
319322

320-
practitionerrole = get_object_or_404(ProviderToLocation, pk=pk)
323+
practitionerrole = get_object_or_404(ProviderToLocation, id=id)
321324

322325
serialized_practitionerrole = PractitionerRoleSerializer(
323326
practitionerrole, context={"request": request}
@@ -342,6 +345,7 @@ class FHIROrganizationViewSet(viewsets.GenericViewSet):
342345
filter_backends = [DjangoFilterBackend, SearchFilter, ParamOrderingFilter]
343346
filterset_class = OrganizationFilterSet
344347
pagination_class = CustomPaginator
348+
lookup_url_kwarg = "id"
345349

346350
ordering_fields = ["organizationtoname__name"]
347351

@@ -403,14 +407,14 @@ def list(self, request):
403407
200: OpenApiResponse(description="Successfully retrieved FHIR Organization resource")
404408
}
405409
)
406-
def retrieve(self, request, pk=None):
410+
def retrieve(self, request, id=None):
407411
"""
408412
Query a specific organization, represented as a FHIR Organization resource
409413
"""
410414
try:
411-
UUID(pk)
415+
UUID(id)
412416
except (ValueError, TypeError):
413-
return HttpResponse(f"Organization {escape(pk)} not found", status=404)
417+
return HttpResponse(f"Organization {escape(id)} not found", status=404)
414418

415419
organization = get_object_or_404(
416420
Organization.objects.prefetch_related(
@@ -435,7 +439,7 @@ def retrieve(self, request, pk=None):
435439
"clinicalorganization__organizationtotaxonomy_set",
436440
"clinicalorganization__organizationtotaxonomy_set__nucc_code",
437441
),
438-
pk=pk,
442+
id=id,
439443
)
440444

441445
serialized_organization = OrganizationSerializer(organization, context={"request": request})
@@ -459,6 +463,7 @@ class FHIRLocationViewSet(viewsets.GenericViewSet):
459463
filter_backends = [DjangoFilterBackend, SearchFilter, ParamOrderingFilter]
460464
filterset_class = LocationFilterSet
461465
pagination_class = CustomPaginator
466+
lookup_url_kwarg = "id"
462467

463468
ordering_fields = ["organization_name", "address_full", "name"]
464469

@@ -516,16 +521,16 @@ def list(self, request):
516521
200: OpenApiResponse(description="Successfully retrieved FHIR Location resource")
517522
}
518523
)
519-
def retrieve(self, request, pk=None):
524+
def retrieve(self, request, id=None):
520525
"""
521526
Query a specific healthcare practice location as a FHIR Location resource
522527
"""
523528
try:
524-
UUID(pk)
529+
UUID(id)
525530
except (ValueError, TypeError):
526-
return HttpResponse(f"Location {escape(pk)} not found", status=404)
531+
return HttpResponse(f"Location {escape(id)} not found", status=404)
527532

528-
location = get_object_or_404(Location, pk=pk)
533+
location = get_object_or_404(Location, id=id)
529534

530535
serialized_location = LocationSerializer(location, context={"request": request})
531536

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)