Favorites
UserResourceFavorites lets a user pin resource IDs into named lists so the owning resource's list endpoint can surface them first. It's a Care-internal personalization feature, not a FHIR resource — you touch it when you add favoriting to a resource's UI.
Each list is scoped by a resource_type and, optionally, a facility. There's no EMRResource serialize/de_serialize spec here. The moving parts are an enum (FavoriteResourceChoices), a default-list constant, a DRF filter backend (FavoritesFilter), and a viewset mixin (EMRFavoritesMixin) that wires up the read/write endpoints.
Source:
- Model:
care/emr/models/favorites.py - Spec (enum + constant):
care/emr/resources/favorites/spec.py - Filter backend:
care/emr/resources/favorites/filters.py - Viewset mixin:
care/emr/api/viewsets/favorites.py
Models
| Model | Purpose |
|---|---|
UserResourceFavorites | Stores a per-user, named list of favorited resource integer PKs, optionally scoped to a facility and constrained to one resource type |
UserResourceFavorites extends EMRBaseModel, which supplies external_id, the audit fields created_by / updated_by / created_date / modified_date, and soft-delete semantics.
UserResourceFavorites fields
| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
user | FK → User | optional | — | Owner of the list. CASCADE, nullable |
favorites | ArrayField(IntegerField) | yes | [] | Favorited resource primary-key integers, not external_ids. Newest-first; capped at settings.MAX_FAVORITES_PER_LIST (default 50) |
favorite_list | CharField(255) | yes | — | List name. A user may keep multiple named lists per (resource_type, facility). Endpoints default it to "default" (DEFAULT_FAVORITE_LIST) |
resource_type | CharField(255) | yes | — | The kind of resource favorited. Always one of the FavoriteResourceChoices values, set server-side from the viewset's FAVORITE_RESOURCE — never accepted from the client |
facility | FK → Facility | optional | — | CASCADE, nullable. null means an instance-wide (cross-facility) list |
The tuple (user, resource_type, facility, favorite_list) addresses a single row: it's what the cache keys and the get_or_create in add_favorite are built from.
resource_type values — FavoriteResourceChoices
The API constrains resource_type to the string values of FavoriteResourceChoices (care/emr/resources/favorites/spec.py). Each viewset binds to exactly one value through its FAVORITE_RESOURCE attribute.
| Value | Bound resource | Wired viewset |
|---|---|---|
activity_definition | Activity definition | ActivityDefinitionViewSet |
charge_item_definition | Charge item definition | ChargeItemDefinitionViewSet |
product_knowledge | Product knowledge | ProductKnowledgeViewSet |
observation_definition | Observation definition | (enum value defined; no viewset wires it yet) |
questionnaire | Questionnaire | QuestionnaireViewSet |
facility_organization | Organization (facility org) | FacilityOrganizationViewSet |
Resource specs (API schema)
Favorites skip the EMRResource Create/Update/List/Retrieve pattern. The spec surface is just:
| Symbol | Kind | Role |
|---|---|---|
FavoriteResourceChoices | str, Enum (spec.py) | Allowed resource_type values (table above). A viewset selects one via FAVORITE_RESOURCE = FavoriteResourceChoices.<x>.value |
DEFAULT_FAVORITE_LIST | constant (spec.py) | "default" — the list name used when the request omits favorite_list |
FavoriteRequest | pydantic.BaseModel (viewset) | Request body for write actions. One field: favorite_list: str = DEFAULT_FAVORITE_LIST |
FavoritesFilter | DRF BaseFilterBackend (filters.py) | Read path. Adds the favorite_list query param to the resource's list endpoint and restricts/orders results to that user's favorites |
EMRFavoritesMixin | viewset mixin (api/viewsets/favorites.py) | Adds the favorite_lists, add_favorite, remove_favorite actions |
FavoriteRequest
| Field | Type | Required | Default |
|---|---|---|---|
favorite_list | str | optional | "default" (DEFAULT_FAVORITE_LIST) |
Favorited objects have no read schema of their own. They come back through the owning resource's list endpoint — for example, the questionnaire list serializer — filtered and ordered by FavoritesFilter. The favorite_lists action returns only {"lists": [<list name>, ...]}.
Related models
User— owner of every favorites row (userFK)Facility— optional scope (facilityFK);null= instance-wide- Each
resource_typebinds to one favoritable resource — see theFavoriteResourceChoicestable
Methods & save behaviour
Every row is mirrored into a Django cache, kept in sync by save() and refresh_cache().
Cache keys
Two module-level helpers build the keys, encoding a missing facility as -:
favorite_lists_cache_key(user, resource_type, facility)
→ "user_favorites_lists:{user.id}:{resource_type}:{facility.id|-}"
favorite_list_object_cache_key(user, resource_type, facility, favorite_list)
→ "user_favorites_list_object:{user.id}:{resource_type}:{facility.id|-}:{favorite_list}"
- The lists key holds the ordered, deduplicated set of
favorite_listnames a user has for a(resource_type, facility). - The list-object key holds the
favoritesinteger array for one named list.
refresh_cache(refresh_list=False)
- Always writes the current
favoritesarray under the list-object key. - With
refresh_list=True, also recomputes the deduplicated,modified_date-descending set offavorite_listnames for the(user, resource_type, facility)and writes it under the lists key.
save() side effects
save() sets refresh_list = not self.pk (true only on insert), calls super().save(), then refresh_cache(refresh_list=refresh_list). So:
- Creating a new list refreshes both the lists cache and the list-object cache.
- Updating an existing list refreshes only the list-object cache — the set of list names hasn't changed.
Treat these keys as platform-maintained. Write through the model or the endpoints so the cache stays consistent.
API integration notes
There's no standalone favorites endpoint. Favorites ride on the owning resource's viewset through EMRFavoritesMixin. A viewset opts in by mixing in EMRFavoritesMixin, setting FAVORITE_RESOURCE, and adding FavoritesFilter to filter_backends:
class QuestionnaireViewSet(EMRModelViewSet, EMRFavoritesMixin):
filter_backends = [filters.DjangoFilterBackend, FavoritesFilter]
FAVORITE_RESOURCE = FavoriteResourceChoices.questionnaire.value
Endpoints (relative to the owning resource)
| Action | Method · route | Body | Behaviour |
|---|---|---|---|
add_favorite | POST {resource}/{id}/add_favorite/ | FavoriteRequest | get_or_create the (user, favorite_list, resource_type, facility) row, insert(0, obj.id) (newest-first), dedupe, trim to MAX_FAVORITES_PER_LIST, save. Returns {} |
remove_favorite | POST {resource}/{id}/remove_favorite/ | FavoriteRequest | Pops obj.id from the list. Emptying the list deletes the row and both cache keys. 404/validation error if the list does not exist. Returns {} |
favorite_lists | GET {resource}/favorite_lists/ | — | Returns {"lists": [<name>, ...]} (cache-first, falls back to DB). Resolves facility from the facility_external_id kwarg or ?facility= query param |
| list (filtered) | GET {resource}/?favorite_list=<name> | — | FavoritesFilter restricts the resource list to id__in=favorites and orders by favorite position (sort_index). Empty/unknown list → empty queryset |
What's server-maintained or validated:
resource_typeis never client-supplied — each viewset fixes it viaFAVORITE_RESOURCE. The client only sendsfavorite_list.facilityis derived server-side viaretrieve_facility_obj(obj)(defaulting toobj.facility), so favorites inherit the favorited object's facility scope. Anullfacilityis an instance-wide list; a set one is facility-scoped.favoritesholds integer primary keys, notexternal_ids. Order is newest-first;add_favoritere-inserts at position 0 and dedupes.- The list is capped at
settings.MAX_FAVORITES_PER_LIST(envMAX_FAVORITES_PER_LIST, default50).add_favoritedrops the oldest entries beyond the cap. - Never set the
user_favorites_lists:*oruser_favorites_list_object:*cache keys from a client.save()/refresh_cache()maintain them, andremove_favoritetears them down when a list empties.
Related
- Reference: User
- Reference: Facility
- Reference: Base model
- Favoritable resources: Activity definition, Charge item definition, Product knowledge, Observation definition, Questionnaire, Organization
- Source: favorites.py (model), spec.py, filters.py, viewset mixin