Skip to content

Platform data model

Adri edited this page Jun 29, 2017 · 14 revisions
  1. Introduction ===============

This document describes the initial data model design for the Cadasta platform. These notes complement the sketch Django models in the Cadasta/data-model-sketches repository.

This design is based around the following principles:

  • We need a data model flexible enough to cover all likely use cases without going overboard on abstraction and without tying the model to details of any individual project.

  • We should not constrain the data model unnecessarily: enumerations should be represented in a way that allows them to be extended easily; entity attributes should likewise not be restricted to a predetermined set of possibilities.

  • We should not be RDBMS zealots. We're using an RDBMS as the persistence layer for the Django ORM. We don't need a perfectly normalised database schema and we can deal with some minor warts in Python (e.g. maintaining constraints on arrays of foreign keys). We should take advantage of the freedom this approach gives us.

  • We shouldn't be afraid to use Postgres-only features. We're tied to Postgres because we're using PostGIS anyway, so we might as well make use of other Postgres features where they're convenient.

  1. Rationale and design =======================

2.1. Cross-cutting concerns

There are several features of the data model that apply to all or most domain entity types: the assignment of identifiers for entities; the recording of historical changes to entities, both real-world changes and administrative database edits; and the handling of attributes attached to entities in a way that allows for easy project-specific customisation.

2.1.1. Entity identifiers

The common approach of using monotonically increasing integer identifiers as primary keys for database entities is a security and privacy fault and should be avoided. Entity identifiers appear in publicly visible API URLs; there should thus be no deterministic way to associate identifiers with entities. This is particularly important for bulk data collection or import: in this case, it's possible to have a long series of entities created one after another.

Instead of using sequential integer identifiers, pseudo-random identifier strings should be used. This is implemented in the cadasta.core.models.RandomIDModel class, which should be used as a base class for all platform models for which deterministic association of identifiers with entities should be avoided (parties, parcels, relationships, resources).

2.1.2. History and auditing: bitemporality

We need to maintain historical information of two kinds: the times at which real-world domain changes occur (births, deaths, transfers of tenure, etc.) and the times at which database changes are recorded. Capturing the first type of historical change is clearly required to record the fundamental temporal aspects of the domain. The second type of change must be recorded to enable auditing of database edits and to allow us to answer questions about historical accumulation of database records (e.g. "How many new tenure relationships were added to the database per month last year for this project?").

This type of setup is relatively common, and is called a bitemporal database, because we record two types of time in every database record: the terminology that people use is varied, but we'll call them model time (real-world time, relating to changes in domain entities) and assert time (recording the period of validity of a particular database record). In our case, there isn't any way of getting around this: these two types of time have to appear in the database whether we like it or not, so we must deal with them correctly.

A properly implemented bitemporal database will allow us to answer more or less any historical query, for points in time and time ranges, both about real-world situations ("Who owned this parcel of land at this point in time?") and about the history of the process of data collection ("On this date, how many individuals had we recorded as parties?"). Even if we don't expose all of this functionality in early releases of the platform, this kind of information will become increasingly interesting as projects collect more data.

The treatment of bitemporal databases is pretty well established but there are some complexities, mostly related to the handling of foreign keys and other relationships between bitemporal tables. We'll follow the recommendations in the book Bitemporal Data: Theory and Practice by Tom Johnston as far as they seem useful. Unfortunately, there is currently no pre-built Django plugin we can use, so we'll need to build one.

The best way to do this seems to be to implement a Bitemporal base class to use for deriving Django models from. This base class will add the necessary time columns to model tables and will override object creation, update and deletion methods to manage these time fields. The Bitemporal class will be supplemented with modified versions of Django's standard ForeignKey, ManyToManyField and other relationship field types. These "bitemporalised" relationship fields will maintain referential integrity between bitemporal tables as models are updated.

In this setup, all edits to the database are recorded with timestamps, allowing comprehensive auditing after the fact. The bitemporal setup also enables clean correction of database errors without any loss of historical information.

Actions: implement django-bitemporal reusable application. (This is quite hard. I'm reading books right now to work out how to do it... However, it's easy enough to write a stub "do nothing" implementation as a placeholder to begin with.)

2.1.3. Entity attributes

In common with many application platforms like ours, we need some kind of dynamic schema extensibility: different projects may have different requirements for the data that they collect and display, meaning that we don't want to tie ourselves to a particular set of database columns for parties, spatial units or relationships. Instead, we should use something like what the Django community calls "dynamic models". (One of the more common implementations of this approach goes by the name of "entity-attribute-value" modelling, or EAV.)

The particular way we've been thinking of implementing this in the database is with a Postgres binary JSON column to store entity attributes. This approach allows for indexing of the JSON data for quick field membership and matching queries. (Postgres supports a couple of different indexing methods, depending on the queries that need to be optimised, so we'll need to think about that.)

Here's a simple concrete example of how this might be used. Some relationships have a seasonality to them, e.g. grazing rights. A seasonality attribute isn't relevant in most cases, so it would be inconvenient to have a column in a database table for this attribute since it will be null most of the time. Instead, by using an attribute for seasonality, we don't need to provide a value unless it's needed for the particular relationship in question.

Another application of this more flexible approach is a better approach to internationalisation of data collection and representation. Good internationalisation involves much more than translation of text labels and changing date or numeric formats. Specifically, many field types have a "local flavour" dimension to them: formats for postcodes, national ID numbers, etc. are all country-dependent. By keeping track of the detailed attribute type information for the attribute fields used in a project, we can give very specific types (e.g. "Indian national ID numbers", "UK postcodes") that will allow for accurate validation and normalisation.

There are some questions about the implementation of this functionality that we need to work out. First, there's a natural relationship between types of entities and the sets of attributes that are relevant for them: for parties, an individual person has different data than a corporate entity or a group. It makes sense to capture this relationship in some way so that, for instance, the platform front-end can determine what data should be provided for a given party depending on the party type. In parallel with this, individual attribute fields will have types, both "coarse" types (e.g. numeric, textual, date/time) and potentially also "detailed" types (e.g. "birth date", "address" or one of the "local flavour" field types described above). We need a clean and simple way to manage this information for use for data validation and normalisation. (Another idea for possible later development is also to use this information to help with survey generation: instead of generating surveys completely manually, some questions and sections could be generated automatically from the data model.)

The implementation of this approach could be based on one of the existing Django dynamic model applications, although we would probably need to adapt it to our needs, since none of the applications I've seen are currently under development, and none of them take advantage of Postgres's JSON column types.

For metadata to describe attributes, we probably need something like:

  • a short name (the JSON field name);

  • a long name;

  • a base type (e.g. text, integer), and;

  • a full type (e.g. gender, occupation, id-phone-number, za-post-code, area, spatial-source, id-government-parcel-id, land-use, free-text, tenure-term).

The idea here is to make it possible to do the kind of "local flavour" validation mentioned above if it's required ("local flavour" to go with django-localflavor).

Actions: adapt existing or implement new Django application for dynamic attribute management. (Unfortunately, none of the existing Django "dynamic models" apps seem to fit with our needs. However, we think that we have a reasonably straightforward plan for how to do this.)

2.2. Domain entities

2.2.1. Users, organisations and projects

A user is a real person or other external entity possessing an account permitted to sign into the Cadasta platform. Users exist orthogonally to organisations and projects.


An organisation is the top-level entity used to manage data stored in the Cadasta platform and represents a real-world entity conducting LTPR data collection activities.


A project is a set of LTPR data collection activities conducted by a single organisation in a particular region and generally associated with an individual community.


Oliver is doing users: just back-document when he's done.

Neither organisations nor projects need bitemporality. Instead, organisations and projects can be archived (making them invisible to normal users) and unarchived (making them visible again). Archiving an organisation implicitly archives all of that organisation's projects. Archived projects can be downloaded as zip files and permanently purged from the system if they are no longer needed. (All of these actions obviously require sufficient permissions to perform.)

Organisations have a name, an optional description, an optional logo, optional URL(s), optional contact email(s) or telephone numbers, and a list of members (users).

Projects have a name, a country, an optional description, optional image(s)/logo(s), optional URL(s), optional contact email(s) or telephone numbers, a private/public flag (which controls whether the project summary page is publicly visible), and optional project extent geometry (handled as a distinguished type of spatial unit). All projects belong to an organisation. Permissions to manage projects are controlled via the permissions system (although we may provide a simple interface to make users "project managers").

All images associated with organisations and projects are managed as resources belonging to the organisation or project.

The models for organisations and projects are relatively simple, not requiring bitemporal management. Not much more needs to be said about these.

2.2.2. Parties

A party is an entity which can potentially engage in tenure relationships. Parties may be individual natural persons, corporate entities, municipalities or other government entities, or groups of any combination of such entities. Parties are associated with an individual project.


Party types We need to represent individuals, groups, corporate entities and possibly other "non-natural persons" (municipalities perhaps?). Each party will thus have a party type and an associated set of attributes, the exact set of attributes depending on the party type (an individual person has a different set of data associated with them than a corporation or a group).

Party attributes Parties have a unique primary key ID, a human-readable name, a type, and any number of attributes (plus versioning/history/bitemporal fields). Party attributes are encoded as a JSON object (in a Postgres jsonb field, using the generic attributes mechanism).

Group parties We need to represent different types of groups, ranging from families (a few members) to cooperatives (tens or hundreds of members) to tribes (potentially thousands of members).

Party relationships As well as tenure relationships associating parties with spatial units in different ways, there also exist relationships of different kinds between parties. Examples include the membership of individual persons within group parties, family relationships and potentially other types of relationships between individuals and corporate entities. Different projects may require the representation of different types of inter-party relationships. All parties may have n:m relationships to other parties (handled via the generic relationship mechanism: see below).

Party history Party entities should be represented with full bitemporal history for domain modelling and auditing purposes.

2.2.3. Spatial units

A spatial unit is a region of space, delimited by a defined boundary (which may represent the real boundary of a building or plot of land, or the legal boundary of a utility corridor or other region). Spatial units are associated with an individual project.


Spatial unit types A number of types of spatial units exist. We need to be able to represent parcels, buildings, compounds, community boundaries, rights of way, utility corridors, plus possibly others (perhaps national park boundaries or logging/mineral rights concessions). Some of the attributes of these different types will be shared, while some will be unique to the particular spatial unit type. Each spatial unit will thus have a spatial unit type and an associated set of attributes, the exact set of attributes depending on the spatial unit type.

Spatial unit attributes Spatial units have a unique primary key ID, a type (managed through the generic attributes mechanism), and any number of attributes (including optional geometry). Spatial unit attributes are encoded as a JSON object (in a Postgres jsonb field, using the generic attributes mechanism).

Geometry All geometrical information in the Cadasta platform is associated with a spatial unit of some type. Note that this means that there is no concept of "relationship geometry" as in the SpatialDev data model -- cases where "extra" geometry is needed are handled by associating extra spatial units with the relationship in question. For example, an easement on a right of way crossing a parcel would be captured by capturing the right of way as a spatial unit (whose type would indicate that it is a right of way), then having an "easement spatial unit" attribute in the relationship recording the association between the right of way and the parcel that it crosses.

Representation of geometry The geometry defining the boundaries of spatial units may be represented at different levels of fidelity, including: polygonal geometry (from accurate or approximate surveys or digitised from satellite or drone imagery), linestring geometry (likely to be used only for rights of way or utility corridors), point-only geometry (from GPS data or digitised from imagery), textual descriptions, etc. Polygonal geometry may be non-contiguous (particularly for community boundaries).

Spatial containment relationships We will need to represent spatial containment relationships involving spatial units explicitly. LADM and STDM don't do this, but they rely on the presence of accurately surveyed geometry to allow for containment relationships to be inferred from geometry. Since we're going to be dealing with different levels of geometrical fidelity, we can't do that, so should represent these relationships explicitly. In cases where we do have polygonal geometry, we can infer the containment relationships, but we need to retain the flexibility to represent cases without good geometry as well. (As an example, suppose that we have a community boundary digitised from satellite imagery containing family compounds represented by single GPS points, with each compound containing one or more buildings, each of which has a textual description instead of surveyed geometry. To represent the relationships between the different spatial units here, we can't rely on geometrical containment relationships.) All spatial units may have m:n relationships with other spatial units (handled via the generic relationship mechanism: see below).

Parcel split/merge tracking In addition to spatial containment relationships, we also need to represent parent-child relationships to deal with splitting and merging of parcels. One option here would be to have a parents field for every spatial unit to record the parcels from which a split or merged parcel is derived. However, because parcel splitting and merging is relatively rare and because not all spatial units require tracking of this information, it seems to make more sense to record parcel splitting and merging as spatial unit-spatial unit relationships between the parent and child parcels.

Spatial unit history Spatial unit entities should be represented with full bitemporal history for domain modelling and auditing purposes.

2.2.4. Relationships

A relationship is a link between two or more domain entities. Relationships may exist between two parties (is-spouse-of, is-member-of, etc.), between two spatial units (is-contained-in, is-split-of, etc.) or between a parties and a spatial unit (freehold-right, tenancy-right, easement-restriction, etc.). Relationships are associated with an individual project.


A tenure relationship is a relationship that associates a party with a spatial unit and represents a particular kind of land tenure or property right, responsibility or restriction. (Some tenure relationships may involve more than one party and/or more than one spatial unit.) Tenure relationships are associated with an individual project.


Relationship types Relationships record connections between pairs of parties, pairs of spatial units or party/spatial unit pairs. In some cases, additional parties or spatial units may be attached to the relationship as attributes of the relationship. Relationships are handled using many-to-many relations between the models representing the entities involved (this means that there is one relationship table in the database for each of the three relationship types: party/party, spatial unit/spatial unit and party/spatial unit).

Party relationships Party/party relationship types are things like is-spouse-of, is-child-of, etc. (between pairs of individuals) and is-member-of (between an individual and a group party).

Spatial unit relationships Spatial unit/spatial unit relationship types are things like is-a-building-in, is-contained-in, etc., for representing spatial containment, or for handling parcel splits and merges, is-a-split-of and is-a-merge-of.

Tenure relationship types Tenure relationships involve a party and a spatial unit. Their types are composed of a relationship type (right, restriction, responsibility) and a sub-type (tenure type for rights, other cases for restriction and responsibility). The set of possible tenure relationship types is project-dependent; there is a set of standard predefined right, responsibility and restriction types, but this list can be extended with project-specific custom types available only for the project for which they have been defined. Each tenure relationship will have a tenure relationship type and an associated set of attributes, the exact set of attributes depending on the tenure relationship type.

Relationship attributes All relationships have a project with which they are associated, plus any number of additional attributes, encoded as a JSON object (in a Postgres jsonb field, using the generic attributes mechanism).

Shared tenure relationships For some cases, it is necessary to record fractional shares of relationships. In these cases, there is no need to maintain 100% coverage as a database invariant. There may also be relationships shared between large groups of individuals (e.g. tribes) without explicit numerical shares.

Relationship geometry Some types of tenure relationship involve two spatial units and one or more parties. For example, a right of way or utility corridor crossing an individually-owned parcel involves: the spatial unit defining the right of way, the spatial unit defining the parcel, the individual owner of the parcel, the municipality or corporation owning the right of way. In these cases, there is likely to be a "primary spatial unit" (e.g., the individually-owned parcel) recorded as the spatial unit for the tenure relationship and a "secondary spatial unit" (e.g., the right of way) recorded as an attribute of the tenure relationship. The exact details of how this works will depend on what kinds of tenure relationship types a project uses.

Relationship history Tenure relationships for a spatial unit before and after a change of ownership are "different but related". We need to be able to capture that relatedness and to pull out the historical record of relationships for a particular spatial unit (or location) or party. All relationship entities should be represented with full bitemporal history for domain modelling and auditing purposes.

2.2.5. Resources

A resource is a binary file associated with a database entity.


Resource types Arbitrary binary files (e.g. PDF documents, images, audio or video clips) can be uploaded and associated with platform entities.

Entity-resource associations Resources can be associated with: organisations, projects, parties, spatial units, relationships or potentially questionnaires or individual questionnaire questions. Resources can be associated with more than one database entity at a time. The link between resources and the objects they are attached is modelled using a Django generic relation, meaning that there only needs to be a single resource table, instead of one resource table per entity type.

Resource attributes Resources will be stored in an S3 bucket. Resources have a unique ID, an associated object type (e.g. project, parcel, etc.) and object ID, a filename and MIME type, an S3 key for the location where the resource is stored (managed using the Django stores mechanism), and any number of additional attributes, encoded as a JSON object (in a Postgres jsonb field, using the generic attributes mechanism).

2.2.6. Questionnaire data

Questionnaire data represents survey responses collected from field workers.


Mostly just copied this from the SpatialDev database schema for now, but we need to think about some things: in particular, abstracting a little from the very ODK-centric setup that SpatialDev used, thinking about other data types (especially geometry) and thinking about how we're going to make the link between questionnaire data and the party/spatial-unit/relationship view of things when we generate domain entities from ingested questionnaires.

Questionnaire data storage Not too much to say about this. The schema from the SpatialDev code seems simple enough and should cover most of the possibilities. The only thing that may need to be changed is the identifiers used to represent respondents, since they're currently tied to ONA.

Data ingestion and transformation The main issue with questionnaire data handling is the transformation from the raw data collected in the field to database entities. Eventually we're going to need a mechanism that allows us (or ideally users) to define the mapping between questionnaire responses and database entities. In the short term, we should do something similar to the existing SpatialDev code, i.e. have a simple mapping from questionnaire data fields to domain entities (we could either write custom code for each questionnaire type or, preferentially, write some simple parameterisable mapping code). If we make the full questionnaire data more easily accessible from views of parties, parcels and relationships, this won't be so bad. Eventually though, we'll want a system for defining surveys within the Cadasta platform in conjunction with defining the fields to be used for the different domain entities. (For example, you might say that parties who are individuals have an address in a particular format and an optional telephone number in a particular format, then you would be able to specify questions to elicit these fields when defining a household survey questionnaire.) Once you've defined a data collection instrument within the platform, the platform would generate representations of the instrument in formats usable by GeoODK and other tools.

  1. Examples ===========

In all of the following examples, the "assert time" dimension of all tables is elided, and in all examples except that of Section 3.3, the "effective time" dimension is also elided. Attribute columns are also elided from all tables.

3.1. Shared rented house with landlord living on-site

  • Individual party A owns a house freehold.

  • Party A rents rooms in their house to parties B and C via informal tenancy agreements, one between A and B and one between A and C.

3.1.1. Entities

  • Individual party A;

  • Individual parties B and C;

  • Parcel H representing house;

  • Freehold tenure relationship F representing ownership of H by A;

  • Tenancy tenure relationship RB representing rental of room in H to B;

  • Tenancy tenure relationship RC representing rental of room in H to C.

3.1.2. Party table

ID Type Name
A Individual Andrew Arbor
B Individual Betty Boothroyd
C Individual Charles Chaplin

3.1.3. Spatial unit table

ID Type Geometry
H Parcel <polygon>

3.1.4. Tenure relationship table

ID Party Type S/U
F A Right: freehold H
RB B Right: tenancy H
RC C Right: tenancy H

3.2. Informal settlement: "structure owners" and "tenants"

  • An informal settlement in a large city has existed for around 40 years on land nominally owned by the state.

  • Structures have been built in the informal settlement by "structure owners", some of whom live in their structures, but more who live elsewhere in the city.

  • The structure owners rent rooms in their structures to "tenants", mostly without any formal tenancy agreement.

3.2.1. Entities

  • Community boundary spatial unit CB representing overall boundary of settlement;

  • Parties S1, S2, ...: "structure owners";

  • Parcel spatial units P1, P2, ...: plots within settlement claimed by structure owners;

  • Building spatial units B1, B2, ...: structures constructed and owned by "structure owners";

  • Parties T1, T2, ...: "tenants";

  • Spatial unit relationships C1, C2, ...: containment of parcels Pi within boundary CB and buildings Bj within parcels;

  • Tenure relationships I1, I2, ...: informal ownership claims of structure owners to parcels;

  • Tenure relationships O1, O2, ...: ownership of structures by structure owners;

  • Tenure relationships R1, R2, ...: rental of structures by tenants.

3.2.2. Party table

ID Type Name
S1 Individual Steve Structure-Owner
S2 Individual Sally Structure-Owner
... ... ...
T1 Individual Terri Tenant
T2 Individual Tony Tenant
... ... ...

3.2.3. Spatial unit table

ID Type Geometry Description
CB Community boundary <polygon> Informalville
P1 Parcel <point> n/a
P2 Parcel <point> n/a
... ... ... ...
B1 Building n/a Red roof, unit no. 2
B2 Building n/a SW corner, near pump
... ... ... ...

3.2.4. Spatial unit relationship table

ID S/U 1 Type S/U 2
C1 P1 is-contained-in CB
C2 P2 is-contained-in CB
... ... ... ...
C3 B1 is-contained-in P1
C4 B2 is-contained-in P2
... ... ... ...

3.2.5. Tenure relationship table

ID Party Type S/U
I1 S1 Right: ownership-claim P1
I2 S2 Right: ownership-claim P2
... ... ... ...
I3 S1 Right: structure-ownership B1
I4 S2 Right: structure-ownership B2
... ... ... ...
I5 T1 Right: tenancy B1
I6 T2 Right: tenancy B2
I7 T2 Right: tenancy B2
... ... ... ...

3.3. Inheritance use case

  • Party A (father), married to party B (mother), with children C (son) and D (daughter) owns a parcel P (let's say fee simple to make it concrete and use the name F to denote the relationship between A and P).

  • A dies. Local custom dictates that C inherits the parcel P.

  • C elects to split the parcel P into two parcels P1 and P2, retaining ownership of P1 for himself (intending to use the parcel to support himself and B) and giving P2 to D.

3.3.1. Entities

  • Parties: A, father; B, mother; C, son; D, daughter;

  • Spatial units: initially, single parcel P, later split into parcels P1 and P2;

  • Party relationships between family members;

  • Freehold tenure relationship, initially between A and P, later between C and P, finally between C and P1 and between D and P2.

3.3.2. Initial situation

Party table:

ID Type Name From To
A Individual Albert 1945-12-24 9999-12-31
B Individual Brenda 1950-06-10 9999-12-31
C Individual Charlie 1968-11-06 9999-12-31
D Individual Doris 1972-05-24 9999-12-31

Spatial unit table:

ID Type Geometry From To
P Parcel <polygon> 0001-01-01 9999-12-31

Party relationship table:

ID Party 1 Type Party 2 From To
PR1 A spouse-of B 1966-08-13 9999-12-31
PR2 B spouse-of A 1966-08-13 9999-12-31
PR3 C child-of A 1968-11-06 9999-12-31
PR4 C child-of B 1968-11-06 9999-12-31
PR5 D child-of A 1975-05-24 9999-12-31
PR6 D child-of B 1975-05-24 9999-12-31

Tenure relationship table:

ID Party Type S/U From To
F A Right: freehold P 1966-07-23 9999-12-31

3.3.3. A dies, C inherits

Party table:

ID Type Name From To
A Individual Albert 1945-12-24 2015-01-21
B Individual Brenda 1950-06-10 9999-12-31
C Individual Charlie 1968-11-06 9999-12-31
D Individual Doris 1972-05-24 9999-12-31

Spatial unit table:

ID Type Geometry From To
P Parcel <polygon> 0001-01-01 9999-12-31

Party relationship table:

ID Party 1 Type Party 2 From To
PR1 A spouse-of B 1966-08-13 2015-01-21
PR2 B spouse-of A 1966-08-13 2015-01-21
PR3 C child-of A 1968-11-06 2015-01-21
PR4 C child-of B 1968-11-06 9999-12-31
PR5 D child-of A 1975-05-24 2015-01-21
PR6 D child-of B 1975-05-24 9999-12-31

Tenure relationship table:

ID Party Type S/U From To
F A Right: freehold P 1966-07-23 2015-01-21
G C Right: freehold P 2015-01-21 9999-12-31

(Relationship G has an attribute "parent=F" to mark its relationship to the original F tenure relationship.)

3.3.4. C splits parcel

Party table:

ID Type Name From To
B Individual Brenda 1950-06-10 9999-12-31
C Individual Charlie 1968-11-06 9999-12-31
D Individual Doris 1972-05-24 9999-12-31

Spatial unit table:

ID Type Geometry From To
P Parcel <polygon> 0001-01-01 2015-03-05
P1 Parcel <polygon> 2015-03-05 9999-12-31
P2 Parcel <polygon> 2015-03-05 9999-12-31

Party relationship table:

ID Party 1 Type Party 2 From To
PR4 C child-of B 1968-11-06 9999-12-31
PR6 D child-of B 1975-05-24 9999-12-31

Spatial unit relationship table:

ID S/U 1 Type S/U 2 From To
S1 P1 is-split-of P 2015-03-05 9999-12-31
S2 P2 is-split-of P 2015-03-05 9999-12-31

Tenure relationship table:

ID Party Type S/U From To
G C Right: freehold P 2015-01-21 2015-03-05
H1 C Right: freehold P1 2015-03-05 9999-12-31
H2 D Right: freehold P2 2015-03-05 9999-12-31

(Relationship G has an attribute "parent=F" to mark its relationship to the original F tenure relationship; relationships H1 and H2 have "parent=G" attributes.)

  1. Organisation into Django apps ================================

The following separation of model entities into Django apps is proposed.

The model entities are grouped into six Django apps. Two apps provide generic models (Spatial, Attributes). Then there are apps grouping together domain models (Organization, Tenures, Questionnaires) and one app concerning Resources.

By organizing models that way, we ensure that dependencies are one directional only, avoiding conflicting circular dependencies.

Division Into Django Apps

Clone this wiki locally