References/Favorites: Difference between revisions
More languages
More actions
OHC identity seed |
Add Navbox platform (via update-page on MediaWiki MCP Server) |
||
| Line 214: | Line 214: | ||
* The list is capped at <code>settings.MAX_FAVORITES_PER_LIST</code> (env <code>MAX_FAVORITES_PER_LIST</code>, default <code>50</code>). <code>add_favorite</code> drops the oldest entries beyond the cap. |
* The list is capped at <code>settings.MAX_FAVORITES_PER_LIST</code> (env <code>MAX_FAVORITES_PER_LIST</code>, default <code>50</code>). <code>add_favorite</code> drops the oldest entries beyond the cap. |
||
* Never set the <code>user_favorites_lists:*</code> or <code>user_favorites_list_object:*</code> cache keys from a client. <code>save()</code> / <code>refresh_cache()</code> maintain them, and <code>remove_favorite</code> tears them down when a list empties. |
* Never set the <code>user_favorites_lists:*</code> or <code>user_favorites_list_object:*</code> cache keys from a client. <code>save()</code> / <code>refresh_cache()</code> maintain them, and <code>remove_favorite</code> tears them down when a list empties. |
||
{{Navbox platform}} |
|||
{{Related}} |
{{Related}} |
||
Latest revision as of 09:55, 6 July 2026
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: [https://github.com/ohcnetwork/care/blob/develop/care/emr/models/favorites.py
care/emr/models/favorites.py] - Spec (enum + constant): [https://github.com/ohcnetwork/care/blob/develop/care/emr/resources/favorites/spec.py
care/emr/resources/favorites/spec.py] - Filter backend: [https://github.com/ohcnetwork/care/blob/develop/care/emr/resources/favorites/filters.py
care/emr/resources/favorites/filters.py] - Viewset mixin: [https://github.com/ohcnetwork/care/blob/develop/care/emr/api/viewsets/favorites.py
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 | ||
favorites |
ArrayField(IntegerField) |
yes | ||
favorite_list |
CharField(255) |
yes | ||
resource_type |
CharField(255) |
yes | ||
facility |
FK → Facility |
optional |
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
|
[[References/Activity Definition | Activity definition]] |
charge_item_definition
|
[[References/Charge Item Definition | Charge item definition]] |
product_knowledge
|
[[References/Product Knowledge | Product knowledge]] |
observation_definition
|
[[References/Observation Definition | Observation definition]] |
questionnaire
|
References/Questionnaire | QuestionnaireViewSet
|
facility_organization
|
References/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: References/Organization