ojuso-map/apps/map/models.py

1181 lines
41 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import datetime
from urllib import parse
from django.contrib.auth.models import User
from django.contrib.gis.db import models
from django.db import connection
from django.template.defaultfilters import slugify
from django.utils.translation import ugettext as _
from django_extensions.db.fields import AutoSlugField
from django_countries.fields import CountryField
from multiselectfield import MultiSelectField
from phonenumber_field.modelfields import PhoneNumberField
from . import validators
class CaseStudyDraft(models.Model):
author = models.ForeignKey(
User, on_delete=models.CASCADE
)
created = models.DateTimeField(auto_now_add=True)
data = models.TextField()
def __str__(self):
return "{0.author.username}, {0.created:%Y-%m-%d %H:%M}".format(self)
class SpatialRefSys(connection.ops.spatial_ref_sys()):
def __str__(self):
return self.__unicode__()
def __unicode__(self):
return '{0.auth_name}:{0.auth_srid} {0.name}'.format(self)
class Meta:
proxy = True
verbose_name = "spatial reference system"
class CaseStudyQuerySet(models.QuerySet):
def approved(self):
return self.filter(
approved=True
)
class CaseStudy(models.Model):
"""Model for case studies submitted to the Ojuso Platform"""
approved = models.BooleanField(default=False)
# Choice lists for drop-downs
POSITIVE_NEGATIVE_CHOICES = (
('P', _('There is/was an organising process in favour of the project')),
('N', _('There is/was an organising process against the project')),
('X', _('There is/was no organising process')),
('U', _('Unsure/unknown'))
)
LAND_OWNERSHIP_CHOICES = (
('PRI', _('Private land')),
('PUB', _('Public/state land')),
('COM', _('Community/communal/customary land')),
('CON', _('Contested/in conflict')),
('OTH', _('Other')),
)
LOCATION_CONTEXT_CHOICES = (
('RUR', _('Rural')),
('URB', _('Urban')),
('MIX', _('Mixed')),
)
TYPE_OF_ECOSYSTEM_CHOICES = (
('MARINE', _('Marine (e.g. Ocean, Sea)')),
('FRESH', _('Freshwater (e.g. Freshwater, Lake)')),
('FOREST', _('Forest/Jungle')),
('AGRI', _('Agricultural Land')),
('GRASS', _('Grassland')),
('DESERT', _('Desert (Tundra, Ice or Sand)')),
('WETLND', _('Wetland (Marsh, Mangrove, Peat Soil)')),
('URBAN', _('Urban'))
)
AFFECTED_COMMUNITIES_CHOICES = (
('INDIG', _('Indigenous')),
('AFRO', _('Afro-descendants')),
('MIG', _('Migrants')),
('REF', _('Refugees')),
('OTHER', _('Other communities or identities')),
)
PROJECT_STATUS_CHOICES = (
('INIT', _('Initiation/ideation')),
('PROJCD', _('In planning and design')),
('FAIL', _('Failed')),
('UCONST', _('Under construction')),
('EXSTNG', _('In operation')),
('DECOMM', _('Undergoing decommissioning')),
('END', _('Decommissioned')),
)
FINANCIAL_INSTITUTIONS = (
('AfDB', _('African Development Bank (AfDB)')),
('BADEA', _('Arab Bank for Economic Development in Africa (BADEA)')),
('ADB', _('Asian Development Bank (ADB)')),
('AIIB', _('Asian Infrastructure Investment Bank (AIIB)')),
('BSTDB', _('Black Sea Trade and Development Bank (BSTDB)')),
('CAF', _('Corporacion Andina de Fomento / Development Bank of Latin America (CAF)')),
('CDB', _('Caribbean Development Bank (CDB)')),
('CABEI', _('Central American Bank for Economic Integration (CABEI)')),
('EADB', _('East African Development Bank (EADB)')),
('ETDB', _('Economic Cooperation Organization Trade and Development Bank (ETDB)')),
('EDB', _('Eurasian Development Bank (EDB)')),
('EBRD', _('European Bank for Reconstruction and Development (EBRD)')),
('EC', _('European Commission (EC)')),
('EIB', _('European Investment Bank (EIB)')),
('IADB', _('Inter-American Development Bank Group (IDB, IADB)')),
('IFFIm', _('International Finance Facility for Immunisation (IFFIm)')),
('IFAD', _('International Fund for Agricultural Development (IFAD)')),
('IIB', _('International Investment Bank (IIB)')),
('IsDB', _('Islamic Development Bank (IsDB)')),
('FMO', _('Nederlandse Financieringsmaatschappij voor Ontwikkelingslanden NV (FMO)')),
('NDB', _('New Development Bank (NDB) (formerly BRICS Development Bank)')),
('NDF', _('The Nordic Development Fund')),
('NIB', _('Nordic Investment Bank (NIB)')),
('OFID', _('OPEC Fund for International Development (OFID)')),
('BOAD', _('West African Development Bank (BOAD)')),
('WB', _('World Bank')),
)
SECTOR_CHOICES = (
('RN', _('Renewable energy generation project')),
('PG', _('Energy networks')),
('ST', _('Energy storage facilities')),
('SM', _('Mining related to the renewable energy economy')),
('MA', _('Manufacturing and/or processing of equipment'))
)
GENERATION_TYPE_CHOICES = (
('POW', _('Power')),
('HOT', _('Heat/Cool')),
('CHP', _('Combined Heat/Cool and Power (CHP)')),
)
GENERATION_TECHNOLOGY_CHOICES = (
('BIO', _('Bio-energy')),
('GEOT', _('Geothermal electricity')),
(_('Hydro'), (
('uHYD', _('Micro hydro (<100kW)')),
('SHYD', _('Small-scale hydro (<1MW)')),
('MHYD', _('Medium-scale hydro (1-30MW)')),
('LHYD', _('Large-scale hydro (>30MW - often not considered renewable)')),
)),
(_('Marine'), (
('WAVE', _('Wave')),
('TSTR', _('Tidal stream')),
('TBAR', _('Tidal barrage/lagoon')),
('TOTH', _('Other')),
)),
(_('Solar'), (
('SSPV', _('Small-scale photovoltaic (<500kW)')),
('LSPV', _('Large-scale photovoltaic (>500kW)')),
( 'CSP', _('Concentrated solar power (CSP)')),
('PARA', _('Parabolic trough (open or enclosed)')),
('FRES', _('Fresnel reflector')),
('STIR', _('Dish Stirling')),
)),
(_('Wind'), (
('SSWE', _('Small-scale wind (<500kW)')),
('LSWE', _('Large-scale wind (>500kW)'))
)),
('OTHR', _('Other (tidal, wave etc)'))
)
POWER_TECHNOLOGY_CHOICES = (
('PT', _('Electrical power transmission')),
('HN', _('Heat networks')),
('OT', _('Other')),
)
TYPE_OF_EXTRACTION_CHOICES = (
('SUR', _('Surface (open pit/open cast/open cut mining)')),
('SUB', _('Sub-surface (underground mining)')),
('SEA', _('Seabed mining')),
('URB', _('Urban mining/recycling'))
)
MINERAL_COMMODITY_CHOICES = (
('ALU', _('Aluminium (Bauxite)')),
('ARS', _('Arsenic')),
('BER', _('Beryllium')),
('CAD', _('Cadmium')),
('CHR', _('Chromium')),
('COK', _('Coking')),
('COA', _('Coal (for steel)')),
('COP', _('Copper')),
('GAL', _('Gallium')),
('GER', _('Germanium')),
('GLD', _('Gold')),
('HRE', _('Heavy Rare Earth Elements (Gadolinium, Terbium, Dysprosium, Holmium, Erbium, Thulium, Ytterbium, Lutetium, Yttrium, Scandium)')),
('IRN', _('Iron')),
('LRE', _('Light Rare Earth Elements (Lanthanum, Cerium, Praseodymium, Neodymium, Promethium, Samarium, Europium)')),
('LED', _('Lead')),
('LIT', _('Lithium')),
('MAN', _('Manganese')),
('MER', _('Mercury')),
('MOL', _('Molybdenum')),
('NIC', _('Nickel')),
('NIO', _('Niobium')),
('PGM', _('Platinum group metals (ruthenium, rhodium, palladium, osmium, iridium, and platinum)')),
('RHE', _('Rhenium')),
('SIL', _('Silicon')),
('SIV', _('Silver')),
('TAN', _('Tantalum')),
('TEL', _('Tellurium')),
('THA', _('Thallium')),
('TIN', _('Tin')),
('TIT', _('Titanium')),
('TUN', _('Tungsten')),
('VAN', _('Vanadium')),
('ZNC', _('Zinc')),
('OTR', _('Other'))
)
USE_IN_ENERGY_ECONOMY_CHOICES = (
('CPV', _('Concentrated solar power (CSP)')),
('EPT', _('Electrical power transmission infrastructure')),
('ESS', _('Energy storage')),
('GGM', _('Geothermal')),
('HGM', _('Hydropower')),
('HNT', _('Heat networks')),
('SPM', _('Solar PV')),
('STM', _('Solar thermal systems')),
('WTM', _('Wind power')),
('ESS', _("Don't know")),
('OTR', _('Other'))
)
MANUFACTURING_TYPE_CHOICES = (
('GENERATE', _('Manufacturing of renewable energy generation equipment')),
('TRANSSTORE', _('Manufacturing of energy transmission or storage equipment')),
('RECYCLE', _('Recycling / reusing equipment or raw materials')),
('DISPOSAL', _('Disposal of equipment')),
('OTHER', _('Other')),
)
MANUFACTURING_RELATED_CHOICES = (
('PV', _('Solar PV')),
('CSP', _('CSP')),
('WIND', _('Wind power')),
('HYDRO', _('Hydropower')),
('GEO', _('Geothermal')),
('TRANSMIT', _('Electrical power transmission infrastructure')),
('STORE', _('Energy storage')),
('HEAT', _('Heat networks')),
('OTHER', _('Other')),
('IDK', _('Unknown')),
)
MANUFACTURING_FACTORS_CHOICES = (
('LAND', _('Land use')),
('LABOR', _('Labor rights')),
('ENVIRO', _('Environmental factors')),
('LIFECYCLE', _('Lifecycle management')),
('OWN', _('Ownership')),
('OTHER', _('Other(s)')),
)
POSITIVE_CASE_TYPE_CHOICES = (
('CREP', _('Community project (co-)owned by individuals')),
('EACP', _('Community project owned by not-for-profit organizations and/or serving the public interest')),
('PSEP', _('Public/state (federal, state, municipal) project')),
('CORS', _('Reuse / Recycling / Circular economy project')),
)
NEGATIVE_CASE_REASONS_CHOICES = (
('VOLR', _('Violation of land rights')),
('VOHR', _('Violation of fundamental human rights, indigenous rights and/or other collective rights')),
('EIMP', _('Environmental impacts (severe impacts on ecosystems / violation of laws, plans or programs of \
environmental conservation or territorial governance systems etc.')),
('NCUL', _('Negative cultural impacts (erosion/destruction of bio-cultural heritage, impacts on sacred land \
etc)')),
('AGGR', _('Aggression/threats to community members opposed to the project, collaboration with organized crime \
etc')),
('ALAB', _('Abusive labour practices')),
('CRUP', _('Corruption and/or irregular permitting or contracting, conflicts of interest etc')),
)
# Dynamically generate a list of choices 40 years prior and after the current year.
YEAR_CHOICES = [(r, r) for r in
range((datetime.datetime.now().year - 40),
(datetime.datetime.now().year + 41))]
##
# Meta Fields
##
# User who submitted case study
author = models.ForeignKey(
User,
on_delete=models.SET_NULL,
blank=True,
null=True,
editable=False
)
# Date and time of submission
date_created = models.DateTimeField(auto_now_add=True, null=False)
# Slug derived from entry_name, used in urls for SEO
slug = AutoSlugField(populate_from=['entry_name'], editable=False)
##
# Territory info
##
location = models.PointField(
verbose_name=_("Project location")
)
shapefiles = models.ManyToManyField(
'files.File',
related_name='shapefile_for',
verbose_name=_("Geographic data"),
help_text=_("If you have territory that you would like to show in relation to this project \
- e.g. Bienes Comunales de Ixtepec etc. This is a set of 3 or more (often 5-6) \
files with file extensions like .cpg, .dbf, .prj, .qpj, .shp, .shx. \
\
Hold down Control, or Command on a Mac, to select more than one. \
Let us know (database@ojuso.org) if you have other file types or need help and we \
can work out how to import it. You may have data as GeoPackage (gpkg), GeoJSON, \
KML, GML, etc. or have data in PostGIS or another spatial database management \
system already."),
blank=True
)
coordinate_reference_system = models.ForeignKey(
SpatialRefSys,
null=True,
blank=True,
default=4326,
on_delete=models.PROTECT
)
name_of_territory_or_area = models.CharField(
verbose_name=_("Name of territory or area"),
max_length=512,
blank=True
)
##
# First Screen - Basic information
##
# 1.1
entry_name = models.CharField(
verbose_name=_("Entry Name"),
help_text=_("This should usually be the name of the project. \
If you are writing this case study in a language not used \
in the locale of its project, you should provide its local name \
first, as well as any translated name."),
max_length=128
)
# 1.4
country = CountryField(
verbose_name=_("Country"),
help_text=_("Select the country of the project")
)
# 1.5.1
area_of_land = models.IntegerField(
verbose_name=_("Approximate land area"),
help_text=_("The area of land covered by the project (in km²)")
)
# 1.5.2
land_ownership = models.CharField(
verbose_name=_("Land ownership / tenure"),
help_text=_("What type of ownership does the land fall under?"),
max_length=3,
choices=LAND_OWNERSHIP_CHOICES
)
# 1.5.3
land_ownership_details = models.TextField(
verbose_name=_("Land ownership details"),
help_text=_("<p class='text-muted'>Please specify details about land ownership, including \
conflicting claims, unrecognized customary rights, conflicts \
around land lease or purchase contracts, etc.\
\
<p class='text-muted'>We understand this is a difficult question, so \
please try to provide just the information you know. \
If we have any major questions we will ask them in the moderation process.</p>"),
max_length=256,
blank=True,
)
# 1.5.4
location_context = models.CharField(
verbose_name=_("Location"),
help_text=_("Select the context that is most applicable to this case study."),
max_length=3,
choices=LOCATION_CONTEXT_CHOICES
)
# 1.5.5
type_of_ecosystem = MultiSelectField(
verbose_name=_("Type(s) of ecosystem"),
max_length=56,
choices=TYPE_OF_ECOSYSTEM_CHOICES,
blank=True
)
# 1.5.5.3
describe_ecosystem = models.TextField(
verbose_name=_("Describe the ecosystem"),
)
affected_communities = MultiSelectField(
verbose_name=_("Communities or identities present in the project area"),
max_length=50,
choices=AFFECTED_COMMUNITIES_CHOICES,
blank=True
)
# XXX Delete after migration - merge into affected_communities
people_affected_indigenous = models.TextField(
verbose_name=_("Indigenous people affected"),
help_text=_("What group or groups of indigenous people are affected by this project? \
Please separate by newline."),
blank=True
)
people_affected_other = models.TextField(
verbose_name=_("Communities or identities further detail"),
help_text=_("Please describe further the communities or identities present \
in the project area."),
blank=True
)
# 1.6
project_status = models.CharField(
verbose_name=_("Status of project"),
max_length=6,
choices=PROJECT_STATUS_CHOICES
)
# 1.7
start_year = models.IntegerField(
verbose_name=_("Construction start year"),
help_text=_("Select the year project construction began. If the project is not yet \
in construction, select the assumed start year as detailed in company \
information or media."),
choices=YEAR_CHOICES,
blank=True,
null=True
)
# 1.8
completion_year = models.IntegerField(
verbose_name=_("Operation start year"),
help_text=_("Select the year the project's operation and maintenance (O&M) phase began. \
If the project is not yet in operation, select the year operation is expected \
to begin as detailed in company information or media."),
choices=YEAR_CHOICES,
default=None,
null=True,
blank=True
)
# 1.9
synopsis = models.TextField(
verbose_name=_("Synopsis"),
help_text=_("Briefly describe the project. This will be displayed at\
the top of the case study page. Maximum 500 chars (about \
3½ tweets)")
)
# 1.10
full_description = models.TextField(
verbose_name=_("Full Description"),
help_text=_("Describe the project in full. Separate paragraphs with two\
new lines. Please add as much detail as you feel is necessary\
here.")
)
# 1.11
project_owners = models.TextField(
verbose_name=_("Project and facility owners"),
help_text=_("List companies or organisations that own the project and/or facilities. \
Provide company numbers etc. if available. Separate with a new line."),
blank=True
)
consultants_contractors = models.TextField(
verbose_name=_("Consultants and contractors"),
help_text=_("List consultants, planners or organisations that are doing the planning, \
construction, operation or maintenance work relating to the project \
and/or facilities. Separate each with a new line."),
)
# 1.12
shareholders = models.TextField(
verbose_name=_("Shareholders of the project owners"),
help_text=_("List shareholders of the project owners you've just listed. Separate with a new line."),
blank=True
)
# 1.13.1
financial_institutions = MultiSelectField(
verbose_name=_("Financial institutions"),
help_text=_("Select any financial institutions (public or private) that have, \
or are considering, extending loans or guarantees to the project."),
choices=FINANCIAL_INSTITUTIONS,
blank=True
)
# 1.13.2
financial_institutions_other = models.TextField(
verbose_name=_("Financial institutions other"),
help_text=_("List any other financial institutions not listed above. \
Put each on a new line."),
blank=True
)
# 1.15.1, 1.15.2, 1.15.3
images = models.ManyToManyField(
'files.ImageFile',
related_name='image_for',
verbose_name=_("Images"),
blank=True
)
# 1.16.1
video = models.URLField(
verbose_name=_("Video URL"),
help_text=_("Copy the URL to a YouTube or Vimeo video that relates to the case study."),
max_length=80,
validators=[validators.YouTubeOrVimeoValidator()],
blank=True
)
# 1.16.2
video_caption = models.CharField(
verbose_name=_("Video caption"),
max_length=240,
blank=True,
)
# 1.16.3
video_credit = models.CharField(
verbose_name=_("Video credit(s)"),
max_length=240,
blank=True,
)
# 1.17.1
media_coverage_mainstream = models.TextField(
verbose_name=_("Links to media reports"),
help_text=_("Provide any links to mainstream media coverage."),
blank=True,
)
# 1.17.2
media_coverage_independent = models.TextField(
verbose_name=_("Independent grassroots reports"),
help_text=_("Provide any links to grassroots/independent media coverage."),
blank=True,
)
# 1.18.1
community_voices = models.TextField(
verbose_name=_("Community Voices"),
help_text=_("Add any direct quotes from members of the community that \
relate to this project"),
blank=True,
)
# 1.18.2
direct_comms = models.TextField(
verbose_name=_("Reports of direct communications"),
help_text=_("Add any reports of direct communication between community members and \
representatives of developers/companies/investors. If you have files \
to upload, you can do this in 'other documents' on the 'uploads' tab."),
blank=True,
)
# 1.18.3
social_media_links = models.TextField(
verbose_name=_("Social media links"),
help_text=_("Add any links to social media accounts directly relating to the project."),
max_length=500,
blank=True,
)
##
# Second Screen - Technical and economic analysis
##
sector_of_economy = models.CharField(
verbose_name=_("Sector of economy"),
max_length=3,
choices=SECTOR_CHOICES
)
energy_details = models.CharField(
verbose_name=_("Further details"),
help_text=_("Please give more information about the transmission, network or storage technology."),
max_length=200,
blank=True
)
## Energy generation project
generation_type = models.CharField(
verbose_name=_('What is being generated?'),
max_length=4,
choices=GENERATION_TYPE_CHOICES,
blank=True
)
generation_technology = models.CharField(
verbose_name=_("Generation technology"),
help_text=_("Select the type of renewable energy generation that most applies to this case study."),
max_length=4,
choices=GENERATION_TECHNOLOGY_CHOICES,
blank=True
)
# Should be filled in if generation_technology was answered as bio-energy
biomass_detail = models.CharField(
verbose_name=_("Bio-energy feedstock"),
help_text=_("<div class='text-muted'>\
<p>Please describe the source of the fuel and how it is processed/used. \
Please consider:\
<ul>\
<li>where the fuel came from e.g. corn, forestry, algae, commercial food waste, \
landfill gas, sewage, livestock farm, etc. \
<li>how it is processed e.g. direct-fired, co-firing with other renewable input, \
gasification, bacterial decomposition (anaerobic digestion, AD), pyrolysis, \
small/modular, artificial photosynthesis, fuel cell, etc. \
</ul>\
\
<p>We do not expect users to know this information, but if you do \
it may be useful to give a fuller picture.\
</div>"),
max_length=200,
blank=True
)
# 1.14
energy_customers = models.TextField(
verbose_name=_("Energy service consumers/off-takers"),
help_text=_("List any energy customers/off-takers that take energy from the \
development. E.g. 'national grids' or private energy suppliers. \
Also refer to if carbon markets, credits, blockchain etc. are \
involved in the process. Please separate with a new line."),
blank=True
)
# 2.1.2
total_generation_capacity = models.PositiveIntegerField(
verbose_name=_("Total generation capacity (in kW)"),
help_text=_("Please enter the total generation capacity of the project in kW"),
blank=True,
null=True
)
# XXX Delete after migration - merge into contractor_or_supplier_of_technology
generation_equipment_supplier = models.TextField(
verbose_name=_("Generation equipment supplier(s)"),
help_text=_("Enter the supplier of the generation equipment. (E.g. Siemens Gamesa, GE, Alstom, Vestas, Hanwha Q CELLS, Mitsubishi, First Solar, Jinko Solar, Trina Solar, Suzlon Energy, Statkraft, Shanghai Electric, Ballard Power Systems, Panasonic, etc.)"),
blank=True
)
# 2.1.4
total_investment = models.IntegerField(
verbose_name=_("Total investment (in USD)"),
help_text=_("The approximate total investment for the project in US dollars."),
blank=True,
null=True
)
# XXX Delete after migration - merge into additional_technical_details
technical_or_economic_details = models.TextField(
verbose_name=_("Additional technical or economic details"),
help_text=_("Specify any additional technical or economic details relating to the project."),
blank=True
)
# 2.2 - Power Grids / Energy Storage
# 2.2.1
power_technology = models.CharField(
verbose_name=_("Power technology"),
max_length=2,
choices=POWER_TECHNOLOGY_CHOICES,
blank=True
)
# 2.2.1.4
power_technology_other = models.CharField(
verbose_name=_("Further information about power technology"),
max_length=128,
blank=True
)
energy_storage_capacity = models.DecimalField(
verbose_name=_("Total storage capacity (kWh)"),
max_digits=20,
decimal_places=3,
blank=True,
null=True,
)
energy_transmission_capacity = models.DecimalField(
verbose_name=_("Total transmission capacity (kW)"),
max_digits=20,
decimal_places=3,
blank=True,
null=True,
)
# XXX Delete after migration - no merge
maximum_power_output = models.DecimalField(
verbose_name=_('Maximum power output'),
help_text=_('Enter the maximum power output of the storage system in kilowatts (kW).'),
max_digits=12,
decimal_places=3,
blank=True,
null=True,
)
# XXX Delete after migration - no merge
discharge_time = models.DecimalField(
verbose_name=_('Time for discharge from full capacity'),
help_text=_('Enter the time it takes to discharge from full capacity at maximum power output (in hours).'),
max_digits=6,
decimal_places=3,
blank=True,
null=True
)
# TODO: Auto-completion based on previous entries so we can query case-studies with the same answer.
contractor_or_supplier_of_technology = models.TextField(
verbose_name=_('Contractor and/or supplier of technology'),
help_text=_('List companies that act as contractors or suppliers  e.g. Siemens Gamesa, GE, Alstom, Vestas, Hanwha Q CELLS, Mitsubishi, First Solar, Jinko Solar, Trina Solar, Suzlon Energy, Statkraft, Shanghai Electric, Ballard Power Systems, Panasonic, etc'),
blank=True,
)
# XXX Delete after migration - merge into total_investment
approximate_total_investment = models.PositiveIntegerField(
verbose_name=_('Approximate total investment'),
help_text=_('Enter the approximate total investment in USD ($).'),
blank=True,
default=None,
null=True,
)
# 2.2.5
additional_technical_details = models.TextField(
verbose_name=_("Additional technical or economic details"),
help_text=_("Add any additional details such as: length, from-to, voltage, \
substations, power output, (dis)charge rates, how this technology or \
project interacts with the energy system (e.g. provides reactive power \
to ensure power supply in phase etc.)"),
blank=True
)
##
# Mining
##
minerals_or_commodities = models.CharField(
verbose_name=_("Primary mineral mined"),
help_text=_("What mineral commodity is primarily mined in this project?"),
max_length=3,
choices=MINERAL_COMMODITY_CHOICES,
blank=True
)
minerals_or_commodities_other = models.TextField(
verbose_name=_("Other mineral commodities"),
help_text=_("Enter any mineral commodities not in the list. Separate each with a new line."),
blank=True
)
use_in_energy_economy = MultiSelectField(
verbose_name=_("Potential use in renewable energy economy"),
max_length=128,
choices=USE_IN_ENERGY_ECONOMY_CHOICES,
blank=True
)
use_in_energy_economy_other = models.CharField(
verbose_name=_('Other'),
max_length=128,
blank=True
)
project_life_span = models.CharField(
verbose_name=_("Project life span"),
help_text=_("e.g. 12 years of production, 15 years overall"),
max_length=200,
blank=True
)
size_of_concessions = models.CharField(
verbose_name=_("Size of concessions (land/marine area)"),
help_text=_("Describe the size of concession(s) granted to company/companies (e.g. 'one concession of 2,300 hectares')"),
max_length=200,
blank=True
)
projected_production_of_commodities = models.CharField(
verbose_name=_("Estimated production of key commodities"),
help_text=_('Describe the projected production of commodities per annum and overall.<br>\
For example, "40 million tonnes of iron ore per year", "200 million tonnes over 5 year life of mine"'),
max_length=256,
blank=True
)
type_of_extraction = models.CharField(
verbose_name=_("Type of extraction"),
max_length=3,
choices=TYPE_OF_EXTRACTION_CHOICES,
blank=True
)
associated_infrastructure = models.CharField(
verbose_name=_("Associated infrastructure in the locality"),
help_text=_("List any associated infrastructure in the locality (e.g. tailings dams/mine waste storage and \
treatment facilities; ore processing facilities; smelting facilities; hydroelectric dams/energy infrastructure;\
transport infrastructure e.g. roads or rail."),
max_length=256,
blank=True
)
## Manufacturing
manufacturing_type = models.CharField(
verbose_name=_("Which of the following options best describes this case?"),
max_length=16,
choices=MANUFACTURING_TYPE_CHOICES,
blank=True
)
manufacturing_description = models.TextField(
verbose_name=_("Description"),
help_text=_("Briefly describe manufacturing process and components/outputs.\
(less than 500 characters, about 2 tweets)."),
max_length=500,
blank=True
)
manufacturing_related_tech = MultiSelectField(
verbose_name=_("What technology is this case related to?"),
max_length=128,
choices=MANUFACTURING_RELATED_CHOICES,
blank=True
)
manufacturing_factors = MultiSelectField(
verbose_name=_("Choose the factors that make this case remarkable, in a positive or negative way"),
max_length=128,
choices=MANUFACTURING_FACTORS_CHOICES,
blank=True
)
manufacturing_factors_description = models.TextField(
verbose_name=_("Describe these factors"),
blank=True
)
manufacturing_ownership = models.TextField(
verbose_name=_("Describe the ownership structure of the project and its relation with the local community"),
blank=True
)
##
# Socio-economic analysis
##
positive_or_negative = models.CharField(
verbose_name=_("What is the relationship of local community organization(s) to this project?"),
max_length=1,
choices=POSITIVE_NEGATIVE_CHOICES
)
positive_case_type = MultiSelectField(
verbose_name=_('What kind of case is this entry about?'),
choices=POSITIVE_CASE_TYPE_CHOICES,
max_length=32,
blank=True,
)
negative_case_reasons = MultiSelectField(
verbose_name=("What kind of case is this entry about?"),
choices=NEGATIVE_CASE_REASONS_CHOICES,
blank=True
)
socioeconomic_benefits = models.TextField(
verbose_name=_('Socio-economic impacts'),
blank=True
)
negative_socioenvironmental_impacts = models.TextField(
verbose_name=_("Describe the socio-environmental impacts (positive and negative):"),
help_text=_("Provide a detailed description of the socio-environmental impacts \
(please provide all relevant details, such as type of ecosystem and \
presence of any existing reserve in the area, land to have increased \
biodiversity as a result of the project, new protection of lands/waters, \
specific communities affected by the project, total geographic footprint \
of the project, and tenure system affected in the case of land grabs, \
kind of permits that were irregularly issued if this is the case."),
blank=True
)
isolated_or_widespread = models.TextField(
verbose_name=_("Is the project part of developments which are causing a cumulative effect?"),
help_text=_("Is this an isolated project or are there similar projects in the same \
geographic area? If so, can you describe them? Is there an analysis of \
cumulative or synergetic effects?"),
blank=True
)
key_actors_involved = models.TextField(
verbose_name=_('Key actors involved (individual/organisational)'),
blank=True
)
project_status_detail = models.TextField(
verbose_name=_('Current status of the case'),
help_text=_("Describe the current situation and likely future scenarios."),
blank=True
)
obstacles_and_hindrances = models.TextField(
verbose_name=_('Current status of the organizing process around this case'),
help_text=_('Please describe the status of the organizing process, including the obstacles and hindrances faced.'),
max_length=512,
blank=True
)
identified_partnerships = models.CharField(
verbose_name=_('Identified partnerships'),
help_text=_('Are you, or the organizing process that you represent, looking for partnerships, \
or have any clearly identified need? If so, please describe and we will try \
to connect you to appropriate partners.'),
max_length=256,
blank=True
)
# 3.2.1.9
negative_case_reasons_other = models.CharField(
verbose_name=_("Other reason for negative case"),
help_text=_("Please include other reasons, noting that we aim to focus on projects with substantive negative \
impacts on vulnerable groups."),
max_length=512,
blank=True
)
# 3.2.4.1
when_did_organising_start = models.CharField(
verbose_name=_("When did local organising efforts begin?"),
help_text=_("Before the project started? During project implementation? \
After project implementation? Describe in your own words."),
max_length=512,
blank=True
)
# 3.2.4.2
who_has_been_involved = models.TextField(
verbose_name=_("Which communities, groups and organisations have been involved?"),
blank=True
)
# 3.2.4.3
participation_mechanisms = models.TextField(
verbose_name=_("What mechanisms of participation have been used?"),
help_text=_("e.g. direct action, local referendums, legal cases, letters or petitions etc"),
blank=True
)
# XXX delete after migration - merge with identified_partnerships
potential_partnerships = models.CharField(
verbose_name=_("Describe potential partnerships"),
help_text=_("Are you looking for partnerships or do you have any clearly identified need? If so, please \
describe it here."),
max_length=512,
blank=True
)
# 3.2.7
wants_conversation_with_ojuso = models.BooleanField(
verbose_name=_("Would you like to have a conversation with the ojuso team?"),
help_text=_("This would be a conversation about challenging or engaging related developers, companies and \
investors."),
default=True
)
##
# Contact details
##
contact_email = models.EmailField(
verbose_name=_('Email address'),
blank=True
)
contact_phone = PhoneNumberField(
verbose_name=_('Phone number'),
help_text=_('Please include the international prefix, beginning with "+".'),
blank=True
)
contact_website = models.URLField(
verbose_name=_('Website'),
blank=True
)
contact_twitter = models.CharField(
verbose_name=_('Twitter username'),
max_length=50,
blank=True
)
contact_facebook = models.URLField(
verbose_name=_('Facebook page'),
blank=True
)
contact_other = models.TextField(
verbose_name=_('Other contact details'),
blank=True
)
##
# Uploads
##
# 4.1
official_project_documents = models.ManyToManyField(
'files.File',
related_name='official_project_document_for',
verbose_name=_("Official project documents"),
help_text=_("Attach any legal or official documents that relate to the project. \
Hold down Control, or Command on a Mac, to select more than one."),
blank=True,
)
# 4.2
other_documents = models.ManyToManyField(
'files.File',
related_name='other_document_for',
verbose_name=_("Other documents"),
help_text=_("Attach any other documents that relate to the project. \
Hold down Control, or Command on a Mac, to select more than one."),
blank=True,
)
# 4.4
shown_on_other_platforms = models.BooleanField(
verbose_name=_("Is this case study shown on other platforms?"),
default=True
)
# 4.4.1
shown_on_other_platforms_detail = models.TextField(
verbose_name=_("Shown on other platforms - Detail"),
help_text=_("Please provide links to other places the case study appears."),
blank=True
)
objects = CaseStudyQuerySet.as_manager()
def __str__(self):
"""The String representation of the case study. (Entry name with country name.)"""
return "%s in %s" % (self.entry_name, self.country.name)
def clean(self, *args, **kwargs):
"""Perform validation on the model as a whole and throw a ValidationError if anything isn't how it should be."""
pass
def save(self, *args, **kwargs):
"""Override the save method to create a slug when the model is created. Slug is only created and never modified
as we are basing our URLs on it and don't want it to change - ever."""
if not self.pk:
# Newly created object, so set slug
self.slug = slugify(self.entry_name)
# Continue normal save method by calling original save method.
super(CaseStudy, self).save(*args, **kwargs)
def is_video_youtube(self):
return self.video.count("youtube.com") > 0
def get_youtube_id(self):
"""Gets the 11 character YouTube video ID from the video field."""
return parse.parse_qs(parse.urlparse(self.video).query)["v"][0]
def is_video_vimeo(self):
return self.video.count("vimeo.com") > 0
def get_vimeo_id(self):
"""Gets the 11 number video ID from the video field."""
return parse.urlparse(self.video).path
def get_negative_case_reasons_no_other(self):
"""Return a list of negative case reasons, minus the 'other' choice (if selected)"""
choices = self.get_negative_case_reasons_list()
return choices
def get_renewable_generation_detail(self):
"""Prepend appropriate descriptive text when accessing renewable generation type."""
if self.generation_technology:
if self.generation_technology.endswith('WE'):
return _('Wind energy') + " " + self.get_generation_technology_display()
elif self.generation_technology.endswith('PV'):
return _('Photovoltaic electricity') + " " + self.get_generation_technology_display()
elif self.generation_technology.endswith('HYD'):
return _('Hydroelectric') + " " + self.get_generation_technology_display()
elif self.generation_technology == 'OTHR':
return self.generation_technology_other
else:
return self.get_generation_technology_display()
else:
return ""
class Meta:
verbose_name_plural = 'case studies'
class PointOfInterestQuerySet(models.QuerySet):
def approved(self):
return self.filter(
approved=True
)
class PointOfInterest(models.Model):
class Meta:
verbose_name_plural = 'points of interest'
def __str__(self):
return self.title
objects = PointOfInterestQuerySet.as_manager()
author = models.ForeignKey(
User,
models.SET_NULL,
blank=True,
null=True,
editable=False
)
date_created = models.DateTimeField(auto_now_add=True, null=False)
slug = AutoSlugField(populate_from=['title'], editable=False)
approved = models.BooleanField(default=False)
title = models.CharField(max_length=128)
location = models.PointField()
synopsis = models.TextField()
link = models.URLField()