References/Product Knowledge
More languages
More actions
ProductKnowledge is the reusable definition of a product — its coding, base presentation unit, ingredients and nutrients, drug characteristics, and storage rules. Define it once and every concrete Product points back to it instead of carrying duplicate data. A definition is either instance-wide or scoped to a single facility.
The Django model is only the storage layer: code, names, storage_guidelines, definitional, and base_unit are opaque JSONFields whose real structure lives in the Pydantic resource specs. Every enum, nested JSON shape, validation rule, and read/write difference below comes from those specs.
Source:
- Model: [https://github.com/ohcnetwork/care/blob/develop/care/emr/models/product_knowledge.py
care/emr/models/product_knowledge.py] - Spec: [https://github.com/ohcnetwork/care/blob/develop/care/emr/resources/inventory/product_knowledge/spec.py
care/emr/resources/inventory/product_knowledge/spec.py] - Value sets: [https://github.com/ohcnetwork/care/blob/develop/care/emr/resources/inventory/product_knowledge/valueset.py
care/emr/resources/inventory/product_knowledge/valueset.py]
Models
| Model | Purpose |
|---|---|
ProductKnowledge
|
Foundational, reusable definition of a product (medication, nutritional product, or consumable) |
ProductKnowledge extends SlugBaseModel, which extends EMRBaseModel (the shared base providing external_id, created_date/modified_date, soft-delete via deleted, created_by/updated_by, and history/meta JSON). SlugBaseModel sets FACILITY_SCOPED = True and adds the slug helpers calculate_slug and parse_slug, so a record is addressable by an instance slug (i-<slug>) or a facility slug (f-<facility_external_id>-<slug>).
ProductKnowledge fields
Identity & scope
| Field | Type | Notes |
|---|---|---|
facility |
FK → facility.Facility |
PROTECT, nullable. Null means an instance-level definition; set means facility-scoped. Excluded from the spec base (__exclude__ = ["facility"]); set on write via a facility UUID, surfaced on read as is_instance_level
|
slug |
CharField(255) |
Slug value; combined with facility to form the addressable slug. Set server-side from slug_value on write
|
alternate_identifier |
CharField(255) |
Nullable; secondary external identifier |
status |
CharField(255) |
Lifecycle status. Spec-constrained to ProductKnowledgeStatusOptions (required)
|
product_type |
CharField(255) |
Product category. Spec-constrained to ProductTypeOptions (required)
{{Field|model=ProductKnowledge|section=Identity & scope|name=category|type=FK → emr.ResourceCategory|notes= |
Naming
| Field | Type | Notes |
|---|---|---|
name |
CharField(255) |
Primary display name (required in spec) |
names |
JSONField (list) |
Nullable; list of ProductName { name_type: ProductNameTypes, name: str }. name_type is bound to the ProductNameTypes enum, not a FHIR value set
|
names_cache |
CharField(2048) |
Nullable; denormalized space-joined string of name plus every names entry, rebuilt on each save() to power search. Platform-maintained, absent from every spec — never set it from clients
|
Coding & definition (JSON fields)
The model stores these as bare JSONFields; the spec enforces the shapes below.
| Field | Model type | Spec type / shape | Notes |
|---|---|---|---|
code
|
JSONField (dict)
|
None | Nullable; product code as a [[#coding |
base_unit
|
JSONField (dict)
|
ValueSetBoundCoding[CARE_UCUM_UNITS]
|
Required. A Coding bound to the UCUM units value set (system-ucum-units)
|
names
|
JSONField (list)
|
None | See [[#productname |
storage_guidelines
|
JSONField (list)
|
None | See [[#storageguideline |
definitional
|
JSONField (dict)
|
None | Type-specific definition payload. See [[#productdefinitionspec |
Enums
ProductTypeOptions (product_type)
| Value |
|---|
medication
|
nutritional_product
|
consumable
|
ProductKnowledgeStatusOptions (status)
| Value |
|---|
draft
|
active
|
retired
|
unknown
|
ProductNameTypes (names[].name_type)
| Value |
|---|
trade_name
|
alias
|
original_name
|
preferred
|
DrugCharacteristicCode (definitional.drug_characteristic[].code)
| Value |
|---|
imprint_code
|
size
|
shape
|
color
|
coating
|
scoring
|
logo
|
image
|
Nested spec shapes
These are plain Pydantic BaseModels in spec.py, not value-set bound unless noted.
ProductName
names[] — alternate names for the product.
| Field | Type | Required | Notes |
|---|---|---|---|
name_type |
ProductNameTypes |
yes | |
name |
str |
yes |
StorageGuideline
storage_guidelines[] — a storage note paired with a stability duration.
| Field | Type | Required | Notes |
|---|---|---|---|
note |
str |
yes | |
stability_duration |
DurationSpec { value: int, unit: Coding } |
yes |
ProductDefinitionSpec
definitional — type-specific definition payload.
| Field | Type | Default | Notes |
|---|---|---|---|
dosage_form |
ValueSetBoundCoding[MEDICATION_FORM_CODES] |
required (nullable) | |
intended_routes |
list[Coding] |
[]
| |
ingredients |
list[ProductIngredient] |
[]
| |
nutrients |
list[ProductNutrient] |
[]
| |
drug_characteristic |
list[DrugCharacteristic] |
[]
|
ProductIngredient
definitional.ingredients[].
| Field | Type | Required | Notes |
|---|---|---|---|
is_active |
bool |
yes | |
substance |
ValueSetBoundCoding[CARE_SUBSTANCE_VALUSET] |
yes | |
strength |
ProductStrength |
yes |
ProductNutrient
definitional.nutrients[].
| Field | Type | Required | Notes |
|---|---|---|---|
item |
ValueSetBoundCoding[CARE_NUTRIENTS_VALUESET] |
yes | |
amount |
ProductStrength |
yes |
ProductStrength
Shared by ProductIngredient.strength and ProductNutrient.amount.
| Field | Type | Required | Notes |
|---|---|---|---|
ratio |
Ratio { numerator: Quantity, denominator: Quantity } |
yes | |
quantity |
Quantity |
yes |
DrugCharacteristic
definitional.drug_characteristic[].
| Field | Type | Required | Notes |
|---|---|---|---|
code |
DrugCharacteristicCode |
yes | |
value |
str |
yes |
Shared common types
Coding
From care/emr/resources/common/coding.py (extra="forbid").
| Field | Type | Required |
|---|---|---|
system
|
None | no |
version
|
None | no |
code
|
str
|
yes |
display
|
None | no |
A ValueSetBoundCoding[<slug>] is a Coding subclass that additionally validates code against the named value set on deserialization.
Quantity
From care/emr/resources/common/quantity.py (extra="forbid").
| Field | Type | Notes |
|---|---|---|
value |
Decimal |
max 20 digits, 6 decimal places |
unit |
Coding |
human-readable unit |
code |
Coding |
machine-processable unit |
meta |
dict |
Ratio { numerator: Quantity, denominator: Quantity } — both required.
Resource specs (API schema)
Every spec builds on EMRResource (care/emr/resources/base.py), which provides serialize (DB → Pydantic), de_serialize (Pydantic → DB), and the perform_extra_serialization / perform_extra_deserialization hooks. EMRResource.serialize copies only non-FK database fields that are declared spec fields and not in __exclude__.
| Spec class | Role | Adds / behaviour |
|---|---|---|
BaseProductKnowledgeSpec
|
shared base | __exclude__ = ["facility"]. Fields: id, alternate_identifier, status, product_type, code, base_unit (required, UCUM-bound), name, names, storage_guidelines, definitional
|
ProductKnowledgeUpdateSpec
|
write · update | None (resource-category slug) and slug_value: SlugType (required). On deserialize, resolves category via ResourceCategory.objects.get(slug=...) and sets obj.slug = self.slug_value
|
ProductKnowledgeWriteSpec
|
write · create | None. On deserialize, runs the update-spec logic, then resolves facility via Facility.objects.get(external_id=...) when supplied
|
ProductKnowledgeReadSpec
|
read · detail/list | None, slug_config: dict, slug: str. On serialize, sets id = external_id, is_instance_level = not facility_id, serializes category via ResourceCategoryReadSpec, and sets slug_config = parse_slug(slug)
|
Validation & bound value sets
status∈ProductKnowledgeStatusOptionsandproduct_type∈ProductTypeOptions, both required.base_unitis required and bound toCARE_UCUM_UNITS(system-ucum-units, systemhttp://unitsofmeasure.org).definitional.dosage_formis bound toMEDICATION_FORM_CODES;ingredients[].substancetoCARE_SUBSTANCE_VALUSET;nutrients[].itemtoCARE_NUTRIENTS_VALUESET.codeandintended_routesstay freeCodings.slug_valueusesSlugType: 5–50 chars, URL-safe (^[a-zA-Z0-9][a-zA-Z0-9_-]*[a-zA-Z0-9]$), starting and ending alphanumeric.categoryon write is a slug string; an unknown slug raisesDoesNotExistfrom.get(...).
Server-maintained behaviour
facilitynever flows through the generic field loop (it sits in__exclude__); onlyProductKnowledgeWriteSpec(create) sets it, from thefacilityUUID.slugis set server-side fromslug_value;names_cacheis rebuilt in the model'ssave()(see below).- On read,
is_instance_level,slug_config, and the serializedcategoryare computed inperform_extra_serialization— none are stored columns.
Methods & save behaviour
save() side effects
save() rebuilds names_cache before persisting:
names_cacheis reset to"<name> ".- For each entry in
names, the entry'sname(dict key or attribute) is appended, space-separated. super().save()persists the record, including the slug logic inherited fromSlugBaseModel.
names_cache is platform-maintained — write to name and names instead of setting it directly.
API integration notes
- Exposed through Care's REST API; aligns with the FHIR
MedicationKnowledgeandNutritionProductconcepts. product_typedecides whatdefinitionalmeans (medication,nutritional_product, orconsumable).facilitycontrols scope: omit it for instance-wide, set it for facility-local. Address records by slug (i-<slug>orf-<facility_external_id>-<slug>); the parsed parts come back asslug_config.code,names,storage_guidelines,definitional, andbase_unitcarry their structure and value-set binding in the spec, not the model.base_unitis required.
Related
Pages that link here:
- Reference: References/Base models & conventions