= Field Selectors = Field selectors are a string syntax to specify fields in an S3Resource. == Basic Syntax == The fundamental syntax of a field selector is: {{{ }}} The path specifies the table that contains the field. === Fields in the Master Table === In the simplest case, the path is just the master table of the resource which is represented by the tilde followed by a period: {{{ ~. }}} The master table path is mandatory only in URLs but can otherwise be omitted, i.e. the simplest field selector is simply the field name. It is also possible to use the name of the master table without module prefix (e.g. "organisation" for org_organisation) instead of the tilde to refer to the master table. === Fields in Components === If the field is in a component resource, then the path is the alias of that component followed by a period: {{{ . }}} By default, the alias is the name of the component table without its module prefix (e.g. "contact" for pr_contact). The alias can also be set explicitly in add_component (e.g. for filtered components). If the alias can not be resolved, an AttributeError will be raised. === Fields in Referenced Tables === If the field is in a table that is referenced by a foreign key in the master table, then this can be expressed like: {{{ ~.$ }}} The $ sign indicates that the field is in the table referenced by this foreign key field. The foreign key field must have a real foreign key constraint, i.e. it must not be a list:reference or an integer pseudo-reference. Similar, if the foreign key is in a component: {{{ .$ }}} === Fields in Linked Tables === If the field is in a table that references the master table, but is not a component of it, this can be expressed like: {{{ ~.:. }}} In this case, the is the field in that references the master table (i.e. the so-called "left key"). Similar, if the linked table references a component instead of the master table: {{{ .:. }}} === Combinations === It is possible to chain path expressions. Every part of the path is relative to the table specified by any previous parts: {{{ ~.$. }}} ...specifies that the field is in a component of the table referenced by {{{ .$$ }}} ...specifies a field in table that is referenced by in a table that is referenced by in a component of the master resource. One should though keep in mind that using multi-table paths requires multi-table joins or multiple sub-queries when filtering data. It should therefore be avoided (e.g. through better modelling) where performance is critical, or generally where it is possible. === Context Paths === Context paths allow to use the same filter expression for multiple resources even if they have different relationships to the target field. Consider the following case: For project_project, the location reference is in a component project_location: {{{ location.location_id$name }}} For org_office, the location reference is in the master table: {{{ ~.location_id$name }}} Obviously, the field specified by both selectors is the same - just the path to the field is specific for each resource. Due to these different paths, though, filter queries with either selector can not be re-used for the other resource: {{{#!python # Filter query specific for project_project query = S3FieldSelector("location.location_id$name") == "Example" # Filter query specific for org_office query = S3FieldSelector("~.location_id$name") == "Example" }}} To overcome this, we can configure the resource-specific part of the path as "context" path, using s3db.configure: {{{#!python # Configure the "location" context for project_project: s3db.configure("project_project", context={"location": "location.location_id"}, ) # Configure the "location" context for org_office: s3db.configure("org_office", context={"location": "~.location_id"}, ) }}} Now we can use this "location" context to replace the resource-specific part of the path: {{{ (location)$name }}} Through this, we can re-use the filter query for both resources: {{{#!python # Filter expression valid for both project_project and org_office: query = S3FieldSelector("(location)$name") == "Example }}} Only when the field selector gets resolved against each resource (e.g. during add_filter), the "(location)" part is translated according to the respective "context" configuration.