📕 Core Models Reference

This page documents the ADL core data models. Understanding these models is useful whether you are writing a plugin, building on the API, or diagnosing data issues.

For the plugin-specific base classes (NetworkConnection and StationLink) see Plugin Developer Reference.


Data model overview

        erDiagram
    Network ||--o{ Station : contains
    Network ||--o{ NetworkConnection : has
    Station ||--o{ StationLink : linked_via
    NetworkConnection ||--o{ StationLink : linked_via
    StationLink ||--o{ ObservationRecord : produces
    DataParameter ||--o{ ObservationRecord : describes
    Unit ||--o{ DataParameter : unit_of
    

Network

class adl.core.models.Network(*args, **kwargs)

Bases: Model

An organisational grouping of stations sharing the same vendor type or collection method.

A network carries no ingestion logic itself — it exists to scope station lists in the admin and to group NetworkConnection instances. Examples: “National AWS Network”, “TAHMO Stations”, “Manual Synoptic Stations”.

Parameters:

Reverse relationships:

Parameters:
  • stations (Reverse ForeignKey from Station) – All stations of this Network (related name of network)

  • networkconnection (Reverse ForeignKey from NetworkConnection) – All Network Connections of this Network (related name of network)

exception DoesNotExist

Bases: ObjectDoesNotExist

exception MultipleObjectsReturned

Bases: MultipleObjectsReturned

exception NotUpdated

Bases: ObjectNotUpdated, DatabaseError

A Network is a purely organisational grouping of stations — for example, “National AWS Network” or “TAHMO Stations”. It carries no ingestion logic itself. Networks are used to scope station lists in the admin and to group connections.


Station

class adl.core.models.Station(*args, **kwargs)

Bases: Model

A physical observing point with full WMO WIGOS identification metadata.

Each station belongs to one Network and is identified by a four-component WIGOS Station Identifier (WSI). The wigos_id property returns the formatted WSI string. Stations are linked to upstream data sources via StationLink instances, and observations are stored in ObservationRecord keyed by station.

Location is stored as a PostGIS PointField (longitude, latitude). Sensor height fields (thermometer, anemometer, rain gauge, barometer) are used when encoding observations into WMO formats such as BUFR.

Parameters:
  • id (BigAutoField) – Primary key: ID

  • station_id (CharField) – Station ID. Unique Station Identifier

  • name (CharField) – Name. Name of the station

  • wsi_series (PositiveIntegerField) – WSI Series. WIGOS identifier series

  • wsi_issuer (PositiveIntegerField) – WSI Issuer. WIGOS issuer of identifier

  • wsi_issue_number (PositiveIntegerField) – WSI Issue Number. WIGOS issue number

  • wsi_local (CharField) – WSI Local. WIGOS local identifier

  • wmo_block_number (PositiveIntegerField) – WMO Block Number. WMO block number

  • wmo_station_number (CharField) – WMO Station Number. WMO station number

  • station_type (PositiveIntegerField) – Station Type. Type of observing station, encoding using code table 0 02 001 (set to 0, automatic)

  • location (PointField) – Location. Location of the station

  • station_height_above_msl (FloatField) – Station Height Above MSL. Height of the station ground above mean sea level (to 1 decimal place)

  • thermometer_height (FloatField) – Thermometer Height. Height of thermometer or temperature sensor above the local ground to 2 decimal places

  • barometer_height_above_msl (FloatField) – Barometer Height Above MSL. Height of the barometer above mean sea level (to 1 decimal place), typically height of station ground plus the height of the sensor above local ground

  • anemometer_height (FloatField) – Anemometer Height. Height of the anemometer above local ground to 2 decimal places

  • rain_sensor_height (FloatField) – Rain Sensor Height. Height of the rain gauge above local ground to 2 decimal place

  • method_of_ground_state_measurement (PositiveIntegerField) – Method of Ground State Measurement. Method of observing the snow depth encoded using code table 0 02 177

  • method_of_snow_depth_measurement (PositiveIntegerField) – Method of Snow Depth Measurement. Method of observing the snow depth encoded using code table 0 02 177

  • time_period_of_wind (PositiveIntegerField) – Time Period of Wind. Time period over which the wind speed and direction have been averaged. 10 minutes in normal cases or the number of minutes since a significant change occuring in the preceeding 10 minutes.

Relationship fields:

Parameters:

network (ForeignKey to Network) – Network (related name: stations)

Reverse relationships:

Parameters:
  • stationlink (Reverse ForeignKey from StationLink) – All station links of this Station (related name of station)

  • observationrecord (Reverse ForeignKey from ObservationRecord) – All Observation Records of this Station (related name of station)

  • hourlyobsagg (Reverse ForeignKey from HourlyObsAgg) – All hourly obs aggs of this Station (related name of station)

  • stationchanneldispatchstatus (Reverse ForeignKey from StationChannelDispatchStatus) – All Station Channel Dispatch Status of this Station (related name of station)

A Station represents one physical observing point. It carries full WMO WIGOS identification metadata alongside location and sensor height fields.


Unit

class adl.core.models.Unit(*args, **kwargs)

Bases: Model

A unit of measurement backed by the pint unit registry.

The symbol field must be a valid pint symbol. ADL uses pint to drive automatic unit conversion when observations arrive in a unit that differs from a DataParameter’s canonical unit. Common valid symbols: degC, K, m/s, km/h, mm, hPa, Pa, %, W/m^2.

Important

If a unit conversion fails silently during ingestion, verify that the symbol is recognised by pint before looking elsewhere.

Parameters:
  • id (BigAutoField) – Primary key: ID

  • name (CharField) – Name. Name of the unit

  • symbol (CharField) – Symbol. Symbol of the unit

  • description (TextField) – Description. Description of the unit

Reverse relationships:

Parameters:
  • dataparameter (Reverse ForeignKey from DataParameter) – All Data Parameters of this Unit (related name of unit)

  • dispatchchannelparametermapping (Reverse ForeignKey from DispatchChannelParameterMapping) – All dispatch channel parameter mappings of this Unit (related name of channel_unit)

A Unit defines a unit of measurement backed by the pint unit registry. The symbol field must be a valid pint symbol (e.g. degC, K, m/s, mm, hPa).

Important

When configuring variable mappings in a plugin, the symbol must match exactly what pint recognises. If a unit conversion fails silently, verify the symbol here first. Common valid symbols: degC, K, m/s, km/h, mm, hPa, Pa, %, W/m^2.


DataParameter

class adl.core.models.DataParameter(*args, **kwargs)

Bases: ClusterableModel

ADL’s canonical representation of a measurable meteorological or environmental variable.

A DataParameter names a variable (e.g. air_temperature), declares the Unit in which values are stored, and drives automatic unit conversion when observations arrive in a different unit. It also holds the QC check configuration that is applied to every incoming value for this parameter.

Unit conversion is performed by convert_value_from_units() and convert_value_to_units() using pint. For conversions that are not dimensionally straightforward (e.g. precipitation mmkg/m²), set custom_unit_context to the appropriate pint context name.

Aggregation of stored observations into hourly summaries uses aggregation_method. Use circular for angular variables like wind direction to avoid wrap-around errors (e.g. averaging 350° and 10° should give 0°, not 180°).

Warning

Changing the unit of a parameter that already has ObservationRecord rows will raise a ValidationError. Create a new parameter instead, or delete the existing records first.

Parameters:
  • id (BigAutoField) – Primary key: ID

  • name (CharField) – Name. Name of the variable

  • description (TextField) – Description. Description of the variable

  • icon (CharField) – Icon. Icon displayed alongside this parameter in dashboards and widgets

  • category (CharField) – Category. Type of parameter

  • custom_unit_context (CharField) – Custom Unit Conversion Context. Context of the unit

  • aggregation_method (CharField) – Aggregation Method. How to aggregate this parameter in hourly/daily summaries. Use ‘Circular Mean’ for angular measurements like wind direction.

  • is_coded (BooleanField) – Is Coded Value. Check if values are WMO integer lookup-table codes rather than physical measurements (e.g. cloud cover in oktas, cloud type, present weather code). Pint unit conversion is skipped for coded parameters. The manual entry form renders a dropdown instead of a number input.

  • wmo_code_table (CharField) – WMO Code Table. WMO code table identifier used to render dropdown choices in the entry form (e.g. ‘2700’ for cloud cover in oktas, ‘0513’ for low cloud type CL). Leave blank for physical-quantity parameters.

  • modified_at (DateTimeField) – Modified at

  • qc_checks (StreamField) – Quality Control Checks. Configure automatic data quality validation rules for this parameter.

Relationship fields:

Parameters:

unit (ForeignKey to Unit) – Unit. Unit of the variable (related name: dataparameter)

Reverse relationships:

Parameters:
  • observationrecord (Reverse ForeignKey from ObservationRecord) – All Observation Records of this Data Parameter (related name of parameter)

  • hourlyobsagg (Reverse ForeignKey from HourlyObsAgg) – All hourly obs aggs of this Data Parameter (related name of parameter)

  • dispatchchannelparametermapping (Reverse ForeignKey from DispatchChannelParameterMapping) – All dispatch channel parameter mappings of this Data Parameter (related name of parameter)

Extend the standard model constructor to allow child object lists to be passed in via kwargs

Parameters:
  • id (BigAutoField) – Primary key: ID

  • name (CharField) – Name. Name of the variable

  • description (TextField) – Description. Description of the variable

  • icon (CharField) – Icon. Icon displayed alongside this parameter in dashboards and widgets

  • category (CharField) – Category. Type of parameter

  • custom_unit_context (CharField) – Custom Unit Conversion Context. Context of the unit

  • aggregation_method (CharField) – Aggregation Method. How to aggregate this parameter in hourly/daily summaries. Use ‘Circular Mean’ for angular measurements like wind direction.

  • is_coded (BooleanField) – Is Coded Value. Check if values are WMO integer lookup-table codes rather than physical measurements (e.g. cloud cover in oktas, cloud type, present weather code). Pint unit conversion is skipped for coded parameters. The manual entry form renders a dropdown instead of a number input.

  • wmo_code_table (CharField) – WMO Code Table. WMO code table identifier used to render dropdown choices in the entry form (e.g. ‘2700’ for cloud cover in oktas, ‘0513’ for low cloud type CL). Leave blank for physical-quantity parameters.

  • modified_at (DateTimeField) – Modified at

  • qc_checks (StreamField) – Quality Control Checks. Configure automatic data quality validation rules for this parameter.

Relationship fields:

Parameters:

unit (ForeignKey to Unit) – Unit. Unit of the variable (related name: dataparameter)

Reverse relationships:

Parameters:
  • observationrecord (Reverse ForeignKey from ObservationRecord) – All Observation Records of this Data Parameter (related name of parameter)

  • hourlyobsagg (Reverse ForeignKey from HourlyObsAgg) – All hourly obs aggs of this Data Parameter (related name of parameter)

  • dispatchchannelparametermapping (Reverse ForeignKey from DispatchChannelParameterMapping) – All dispatch channel parameter mappings of this Data Parameter (related name of parameter)

A DataParameter is ADL’s canonical representation of a measurable variable (e.g. air_temperature). It defines the canonical Unit in which values are stored, and drives automatic unit conversion when observations arrive in a different unit.

Unit conversion

convert_value_from_units() converts a value from a given source unit to the parameter’s canonical unit. convert_value_to_units() does the reverse. Both use pint internally and apply custom_unit_context if set.

# Example: convert 293.15 K to the parameter's canonical unit (degC)
converted = air_temp_parameter.convert_value_from_units(293.15, kelvin_unit)
# → 20.0

Warning

Changing the unit of a DataParameter that already has ObservationRecord rows will raise a ValidationError. Delete the existing records first, or create a new parameter instead.


ObservationRecord

class adl.core.models.ObservationRecord(*args, **kwargs)

Bases: TimescaleModel, ClusterableModel

The atomic unit of stored observation data in ADL.

Backed by TimescaleDB for efficient time-series queries. The time field (inherited from TimescaleModel) is always stored as UTC. Use the utc_time property to retrieve it as a timezone-aware UTC datetime.

Each row is uniquely identified by (time, station, connection, parameter). ADL’s ingestion pipeline uses bulk_create(update_conflicts=True) against this constraint, so re-ingesting an already-stored window updates the existing value rather than raising an error.

QC results are stored as a bitmask (QCBits) and a status code (QCStatus). A qc_status of NOT_EVALUATED means no QC checks are configured for the parameter, not that the value failed. Failure messages are stored in related QCMessage rows.`

Parameters:

Relationship fields:

Parameters:

Extend the standard model constructor to allow child object lists to be passed in via kwargs

Parameters:

Relationship fields:

Parameters:

ObservationRecord is the atomic unit of stored data in ADL. It is backed by TimescaleDB for efficient time-series queries.

Uniqueness constraint

Each row is uniquely identified by (time, station, connection, parameter). ADL’s save_records uses bulk_create(update_conflicts=True) against this constraint, so re-ingesting an already-stored window updates the value rather than raising an error.


QCStatus

class adl.core.models.QCStatus(*values)

Integer enumeration of quality control outcomes stored on each ObservationRecord.

NOT_EVALUATED is the default and means no QC checks are configured for the parameter. SUSPECT means one or more checks failed but the value was retained. Failure details are stored in QCMessage.

An IntegerChoices enum stored on each ObservationRecord.

Value

Name

Meaning

0

PASS

All configured QC checks passed.

1

SUSPECT

One or more QC checks failed; value retained but flagged.

2

FAIL

Record failed hard validation.

3

MISSING

No value available for this time step.

4

ESTIMATED

Value was estimated or gap-filled.

5

CORRECTED

Value was manually corrected.

6

NOT_EVALUATED

No QC checks configured for this parameter. Default.


QCBits

class adl.core.models.QCBits(*values)

Bitmask flags indicating which QC checks failed for an ObservationRecord.

Multiple bits can be set simultaneously when more than one check fails. The bitmask is stored alongside QCStatus — a non-zero qc_bits value always corresponds to a qc_status of SUSPECT. Detailed failure messages for each set bit are stored in QCMessage.

An IntFlag bitmask stored alongside QCStatus on each ObservationRecord. Multiple bits can be set simultaneously if more than one check failed.

Bit

Name

Check type

RANGE

Range check

Value outside configured min/max bounds.

STEP

Step check

Change between consecutive observations exceeds threshold.

PERSISTENCE

Persistence check

Value unchanged for too many consecutive time steps.

SPIKE

Spike check

Value is an isolated outlier relative to neighbours.


HourlyObsAgg

class adl.core.models.HourlyObsAgg(*args, **kwargs)

Bases: Model

Read-only TimescaleDB continuous aggregate view providing pre-computed hourly summaries of ObservationRecord data.

Backed by the database view obs_agg_1h_v. Not a managed Django model — ADL does not create or migrate it directly; TimescaleDB maintains it incrementally from the underlying ObservationRecord hypertable.

Use this model instead of querying ObservationRecord directly whenever you need hourly aggregates over large time ranges — it is significantly faster because the aggregates are pre-computed.

The time property aliases bucket for API consistency with ObservationRecord.

Parameters:

Relationship fields:

Parameters:

A read-only TimescaleDB continuous aggregate view (database table obs_agg_1h_v) that provides pre-computed hourly summaries of ObservationRecord data. It is not a managed Django model — ADL does not create or migrate it directly.

Note

Query this model instead of ObservationRecord whenever you need hourly summaries — it is significantly faster for large time ranges because TimescaleDB maintains the aggregates incrementally.