508 lines
22 KiB
Python
508 lines
22 KiB
Python
from django.contrib.gis.db import models
|
|
from django.contrib.postgres.fields import ArrayField
|
|
from django.urls import reverse
|
|
from django.conf import settings
|
|
from django.utils import timezone
|
|
from django.utils.translation import gettext_lazy as _
|
|
from datetime import datetime
|
|
|
|
from assets.models import AbstractLocation, AbstractAsset, AbstractGeoAsset, AbstractAssetModel, AssetCategory
|
|
from common.models import Document
|
|
from common.storages import PrivateMediaStorage
|
|
|
|
private_storage = PrivateMediaStorage()
|
|
|
|
|
|
|
|
class NatureLocation(AbstractLocation):
|
|
geom = models.MultiPolygonField(srid=3812, null=True,blank=True)
|
|
parent_location = models.ForeignKey('self', on_delete=models.SET_NULL, null=True, blank=True, related_name="child_locations")
|
|
zone = models.IntegerField(null=True, blank=True)
|
|
is_highway = models.BooleanField(default=False)
|
|
category = models.ForeignKey(AssetCategory, on_delete=models.SET_NULL, null=True, blank=True)
|
|
municipality = models.ForeignKey('common.Municipality', on_delete=models.SET_NULL, null=True, blank=True)
|
|
|
|
def _get_direct_assets(self, active_only=False):
|
|
related_sets = (
|
|
self.nature_green_surfaces,
|
|
self.nature_trees,
|
|
self.nature_shrubs,
|
|
self.nature_benches,
|
|
)
|
|
|
|
assets = []
|
|
for related_manager in related_sets:
|
|
queryset = related_manager.filter(status='active') if active_only else related_manager.all()
|
|
assets.extend(list(queryset))
|
|
return assets
|
|
|
|
def get_active_assets(self):
|
|
def collect_assets(location):
|
|
assets = location._get_direct_assets(active_only=True)
|
|
for child in location.child_locations.all():
|
|
assets += collect_assets(child)
|
|
return assets
|
|
|
|
return collect_assets(self)
|
|
|
|
def get_all_assets(self):
|
|
def collect_assets(location):
|
|
assets = location._get_direct_assets(active_only=False)
|
|
for child in location.child_locations.all():
|
|
assets += collect_assets(child)
|
|
return assets
|
|
|
|
return collect_assets(self)
|
|
|
|
def get_direct_child_assets(self):
|
|
return self._get_direct_assets(active_only=False)
|
|
|
|
def get_absolute_url(self):
|
|
return reverse(
|
|
'assets:nature_locations_detail',
|
|
kwargs={
|
|
# 'asset_model': content_type.model,
|
|
'location_id': self.id
|
|
}
|
|
)
|
|
|
|
|
|
|
|
class NatureAssetModel(AbstractAssetModel):
|
|
color = models.CharField(max_length=200, null=True, blank=True)
|
|
class Meta:
|
|
verbose_name = "Nature Asset Model"
|
|
verbose_name_plural = "Nature Asset Models"
|
|
|
|
|
|
|
|
|
|
BULB_TYPE_CHOICES = [
|
|
('tulipes', _('Tulipes')),
|
|
('jacynthes', _('Jacynthes')),
|
|
('jonquilles', _('Jonquilles')),
|
|
('narcisses', _('Narcisses')),
|
|
('crocus', _('Crocus')),
|
|
('perce_neige', _('Perce-neige')),
|
|
('autres', _('Autres')),
|
|
]
|
|
|
|
class NatureGreenSurface(AbstractGeoAsset):
|
|
geom = models.MultiPolygonField(srid=3812, null=True, blank=True)
|
|
model = models.ForeignKey(NatureAssetModel, on_delete=models.SET_NULL, null=True, blank=True, related_name="nature_green_surfaces")
|
|
location = models.ForeignKey(NatureLocation, related_name="nature_green_surfaces", on_delete=models.SET_NULL, null=True, blank=True)
|
|
surface_area = models.FloatField(null=True, blank=True)
|
|
slope = models.FloatField(null=True, blank=True)
|
|
weighting = models.FloatField(null=True, blank=True)
|
|
density = models.FloatField(null=True, blank=True)
|
|
mower_frenquency = models.IntegerField(null=True, blank=True)
|
|
buffer = models.FloatField(null=True, blank=True)
|
|
width = models.FloatField(null=True, blank=True)
|
|
length = models.FloatField(null=True, blank=True)
|
|
bulb_types = ArrayField(
|
|
models.CharField(max_length=50, choices=BULB_TYPE_CHOICES),
|
|
blank=True,
|
|
default=list,
|
|
verbose_name=_("Types de bulbes")
|
|
)
|
|
|
|
indexes = [
|
|
models.Index(fields=["code"]),
|
|
]
|
|
|
|
def get_absolute_url(self):
|
|
return reverse('assets:nature_assets_detail', kwargs={'asset_model': 'naturegreensurface', 'asset_id':self.id})
|
|
|
|
|
|
class NatureGreenSurfaceDocument(Document):
|
|
green_surface = models.ForeignKey(NatureGreenSurface, on_delete=models.CASCADE, related_name="documents", verbose_name="Associated Surface")
|
|
file = models.FileField(upload_to="assets_documents/nature/surfaces/", storage=private_storage, verbose_name="Fichier", max_length=255)
|
|
thumbnail = models.ImageField(upload_to="assets_documents/nature/surfaces/", storage=private_storage, null=True, blank=True, max_length=255)
|
|
|
|
|
|
class NatureTree(AbstractGeoAsset):
|
|
model = models.ForeignKey(NatureAssetModel, on_delete=models.SET_NULL, null=True, blank=True, related_name="nature_trees")
|
|
location = models.ForeignKey(NatureLocation, related_name="nature_trees", on_delete=models.SET_NULL, null=True, blank=True)
|
|
height = models.FloatField(null=True, blank=True)
|
|
depth = models.FloatField(null=True, blank=True)
|
|
protection_buffer = models.FloatField(null=True, blank=True)
|
|
|
|
indexes = [
|
|
models.Index(fields=["code"]),
|
|
]
|
|
|
|
def get_absolute_url(self):
|
|
return reverse('assets:nature_assets_detail', kwargs={'asset_model': 'naturetree', 'asset_id':self.id})
|
|
|
|
|
|
# Arbustes
|
|
class NatureShrub(AbstractGeoAsset):
|
|
model = models.ForeignKey(NatureAssetModel, on_delete=models.SET_NULL, null=True, blank=True, related_name="nature_shrubs")
|
|
location = models.ForeignKey(NatureLocation, related_name="nature_shrubs", on_delete=models.SET_NULL, null=True, blank=True)
|
|
height = models.FloatField(null=True, blank=True)
|
|
depth = models.FloatField(null=True, blank=True)
|
|
trimmed = models.BooleanField(default=False)
|
|
|
|
indexes = [
|
|
models.Index(fields=["code"]),
|
|
]
|
|
|
|
def get_absolute_url(self):
|
|
return reverse('assets:nature_assets_detail', kwargs={'asset_model': 'natureshrub', 'asset_id':self.id})
|
|
|
|
class Meta:
|
|
verbose_name = "Arbuste"
|
|
verbose_name_plural = "Arbustes"
|
|
|
|
|
|
# Bancs
|
|
class NatureBench(AbstractGeoAsset):
|
|
model = models.ForeignKey(NatureAssetModel, on_delete=models.SET_NULL, null=True, blank=True, related_name="nature_benches")
|
|
location = models.ForeignKey(NatureLocation, related_name="nature_benches", on_delete=models.SET_NULL, null=True, blank=True)
|
|
material = models.CharField(max_length=200, null=True, blank=True)
|
|
length = models.FloatField(null=True, blank=True)
|
|
width = models.FloatField(null=True, blank=True)
|
|
height = models.FloatField(null=True, blank=True)
|
|
|
|
indexes = [
|
|
models.Index(fields=["code"]),
|
|
]
|
|
|
|
def get_absolute_url(self):
|
|
return reverse('assets:nature_assets_detail', kwargs={'asset_model': 'naturebench', 'asset_id':self.id})
|
|
|
|
|
|
|
|
# ============================================================================
|
|
# Geolocated Comments (independent from assets)
|
|
# ============================================================================
|
|
|
|
class GreenSurfacesComment(models.Model):
|
|
"""
|
|
Commentaire géolocalisé indépendant pour l'édition des espaces verts.
|
|
Permet aux utilisateurs d'ajouter des remarques géolocalisées avec photos,
|
|
sans être lié à un asset spécifique.
|
|
"""
|
|
STATUS_CHOICES = [
|
|
('memo', 'Mémo'),
|
|
('attention', 'Point d\'attention'),
|
|
('todo', 'À faire'),
|
|
('ok', 'OK'),
|
|
('problem', 'Problème'),
|
|
]
|
|
|
|
comment = models.TextField(verbose_name="Commentaire", blank=True, default="")
|
|
status = models.CharField(
|
|
max_length=20,
|
|
choices=STATUS_CHOICES,
|
|
default='memo',
|
|
verbose_name="Statut"
|
|
)
|
|
latitude = models.FloatField(verbose_name="Latitude")
|
|
longitude = models.FloatField(verbose_name="Longitude")
|
|
geom = models.PointField(srid=3812, null=True, blank=True, verbose_name="Géométrie")
|
|
address = models.CharField(max_length=1024, null=True, blank=True, verbose_name="Adresse")
|
|
|
|
created_by = models.ForeignKey(
|
|
settings.AUTH_USER_MODEL,
|
|
on_delete=models.SET_NULL,
|
|
related_name='green_surfaces_comments',
|
|
null=True,
|
|
blank=True,
|
|
verbose_name="Créé par"
|
|
)
|
|
created_at = models.DateTimeField(auto_now_add=True, verbose_name="Date de création")
|
|
updated_at = models.DateTimeField(auto_now=True, verbose_name="Date de modification")
|
|
|
|
class Meta:
|
|
verbose_name = "Commentaire (Espaces verts)"
|
|
verbose_name_plural = "Commentaires (Espaces verts)"
|
|
ordering = ['-created_at']
|
|
|
|
def __str__(self):
|
|
return f"Commentaire de {self.created_by} - {self.created_at.strftime('%d/%m/%Y %H:%M')}"
|
|
|
|
|
|
def comment_photo_upload_path(instance, filename):
|
|
"""Chemin de stockage pour les photos de commentaires"""
|
|
now = timezone.now()
|
|
year = now.strftime("%Y")
|
|
month = now.strftime("%m")
|
|
return f"green_surfaces/comments/photos/{year}/{month}/{filename}"
|
|
|
|
|
|
class GreenSurfacesCommentPhoto(models.Model):
|
|
"""
|
|
Photo associée à un commentaire géolocalisé.
|
|
Conserve la direction (azimut) dans laquelle la photo a été prise.
|
|
"""
|
|
comment = models.ForeignKey(
|
|
GreenSurfacesComment,
|
|
related_name='photos',
|
|
on_delete=models.CASCADE,
|
|
verbose_name="Commentaire"
|
|
)
|
|
photo = models.ImageField(
|
|
upload_to=comment_photo_upload_path,
|
|
storage=private_storage,
|
|
verbose_name="Photo"
|
|
)
|
|
heading = models.FloatField(
|
|
null=True,
|
|
blank=True,
|
|
verbose_name="Direction (azimut en degrés)",
|
|
help_text="Direction de la boussole dans laquelle la photo a été prise (0-360°)"
|
|
)
|
|
order = models.PositiveIntegerField(
|
|
default=0,
|
|
verbose_name="Ordre",
|
|
help_text="Ordre d'affichage de la photo"
|
|
)
|
|
created_at = models.DateTimeField(auto_now_add=True, verbose_name="Date de création")
|
|
|
|
class Meta:
|
|
verbose_name = "Photo de commentaire"
|
|
verbose_name_plural = "Photos de commentaires"
|
|
ordering = ['order', 'created_at']
|
|
|
|
def __str__(self):
|
|
direction = f" (direction: {self.heading}°)" if self.heading is not None else ""
|
|
return f"Photo {self.order + 1} du commentaire #{self.comment.id}{direction}"
|
|
|
|
|
|
|
|
|
|
|
|
class NatureRWIZ(AbstractLocation):
|
|
geom = models.MultiPolygonField(srid=3812, null=True,blank=True)
|
|
|
|
def get_active_assets(self):
|
|
return NatureRWIAsset.objects.filter(location=self, status='active')
|
|
|
|
def get_all_assets(self):
|
|
return NatureRWIAsset.objects.filter(location=self)
|
|
|
|
def get_absolute_url(self):
|
|
return reverse(
|
|
'assets:zirw_detail',
|
|
kwargs={
|
|
'location_id': self.id
|
|
}
|
|
)
|
|
|
|
class Meta:
|
|
verbose_name = _("Zone de gestion intégrée des eaux pluviales (ZIEP)")
|
|
verbose_name_plural = _("Zones de gestion intégrée des eaux pluviales (ZIEP)")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CODE_NAME_CHOICES = [
|
|
('AV', _('Stormwater inlet (Avaloir)')),
|
|
('BS', _('Sequenced border (Bordure séquencée)')),
|
|
('BI', _('Injection port (Bouche d\'injection)')),
|
|
('CA', _('Non-return valve (Clapet anti-retour)')),
|
|
('ES', _('Sedimentation (Empierrement sédimentation)')),
|
|
('KC', _('Kerb cell')),
|
|
('PI', _('Infiltration well (Puits d\'infiltration)')),
|
|
('SU', _('Overflow (Surverse)')),
|
|
('VI', _('Isolation valve (Vanne d\'isolation)')),
|
|
('VR', _('Control valve (Vanne de régulation)')),
|
|
('GT', _('Sidewalk gargoyle (Gargouille de trottoir)')),
|
|
('FE', _('Trickle of water (Filet d\'eau)')),
|
|
('AR', _('Rail drain (Avaloir de rail)')),
|
|
('BA', _('Leveled edge (Bordure arasée)')),
|
|
('CI', _('Infiltration channel (Caniveau infiltrant)')),
|
|
('D', _('Drain')),
|
|
('TP', _('Overflowing (Trop plein)')),
|
|
('RES', _('Separate sewer system (Réseau égout séparatif)')),
|
|
('EVC', _('Hollow green space (Espace vert creux)')),
|
|
('OED', _('Decentralized underground structure (Ouvrage enterré décentralisé)')),
|
|
('OSI', _('Work on an impermeable surface (Ouvrage sur surface imperméable)')),
|
|
('TA', _('Alternative technique (Technique alternative)')),
|
|
('OA', _('Supplementary work (Ouvrage annexe)')),
|
|
]
|
|
|
|
STRUCTURE_TYPE_CHOICES = [
|
|
# Points
|
|
('avaloir', _('Stormwater inlet (Avaloir)')),
|
|
('bordure sequencee', _('Sequenced border (Bordure séquencée)')),
|
|
('bouche injection', _('Injection port (Bouche d\'injection)')),
|
|
('clapet anti-retour', _('Non-return valve (Clapet anti-retour)')),
|
|
('empierrement sedimentation', _('Sedimentation (Empierrement sédimentation)')),
|
|
('kerb cell', _('Kerb cell')),
|
|
('puits infiltration', _('Infiltration well (Puits d\'infiltration)')),
|
|
('surverse', _('Overflow (Surverse)')),
|
|
('vanne isolation', _('Isolation valve (Vanne d\'isolation)')),
|
|
('vanne regulation', _('Control valve (Vanne de régulation)')),
|
|
# Lines
|
|
('gargouille de trottoir', _('Sidewalk gargoyle (Gargouille de trottoir)')),
|
|
('filet eau', _('Trickle of water (Filet d\'eau)')),
|
|
('avaloir de rail', _('Rail drain (Avaloir de rail)')),
|
|
('bordure arasee', _('Leveled edge (Bordure arasée)')),
|
|
('caniveau infiltrant', _('Infiltration channel (Caniveau infiltrant)')),
|
|
('drain', _('Drain')),
|
|
('trop plein', _('Overflowing (Trop plein)')),
|
|
('reseau egout separatif', _('Separate sewer system (Réseau égout séparatif)')),
|
|
# Polygons
|
|
('bassin sec/infiltration', _('Dry/infiltration basin (Bassin sec/infiltration)')),
|
|
('bassin en eau', _('Wet basin (Bassin en eau)')),
|
|
('fosse', _('Ditch (Fossé)')),
|
|
('jardin de pluie', _('Rain garden (Jardin de pluie)')),
|
|
('noue', _('Swale (Noue)')),
|
|
('massif drainant', _('Draining structure (Massif drainant)')),
|
|
('tranchee drainante', _('Draining trench (Tranchée drainante)')),
|
|
('toiture stockante', _('Retention roof (Toiture stockante)')),
|
|
('toiture verte', _('Green roof (Toiture verte)')),
|
|
('bassin orage', _('Stormwater basin (Bassin d\'orage)')),
|
|
('SAUL-vide', _('SAUL-empty (SAUL-vide)')),
|
|
('SAUL-terre', _('SAUL-earth (SAUL-terre)')),
|
|
('citerne', _('Cistern (Citerne)')),
|
|
('espace vert sur dalle', _('Green space on slab (Espace vert sur dalle)')),
|
|
('bande filtrante', _('Filter strip (Bande filtrante)')),
|
|
('collecteur en beton poreux', _('Porous concrete collector (Collecteur en béton poreux)')),
|
|
]
|
|
|
|
PROJECT_MANAGER_CHOICES = [
|
|
('DPV', 'DPV'),
|
|
('DITP', 'DITP'),
|
|
('DEN', 'DEN'),
|
|
('DPO', 'DPO'),
|
|
('Beliris', 'Beliris'),
|
|
('Commune', 'Commune'),
|
|
]
|
|
|
|
|
|
|
|
CONSTRUCTION_STATUS_CHOICES = [
|
|
('etude', _('Design (Étude)')),
|
|
('travaux', _('Construction (Travaux)')),
|
|
('reception provisoire', _('Provisional acceptance (Réception provisoire)')),
|
|
('reception definitive', _('Final acceptance (Réception définitive)')),
|
|
]
|
|
|
|
CONDITION_CHOICES = [
|
|
('bon', _('Good (Bon)')),
|
|
('examen a programmer', _('Inspection to schedule (Examen à programmer)')),
|
|
('intervention curative necessaire', _('Curative action needed (Intervention curative nécessaire)')),
|
|
('refection totale necessaire', _('Total rehabilitation needed (Réfection totale nécessaire)')),
|
|
('travaux entretien a realiser', _('Maintenance works to perform (Travaux entretien à réaliser)')),
|
|
('travaux maintenance', _('Maintenance works (Travaux maintenance)')),
|
|
('travaux maintenance a programmer', _('Maintenance works to schedule (Travaux maintenance à programmer)')),
|
|
]
|
|
|
|
CONNECTION_CHOICES = [
|
|
('connecte', _('Connected (Connecté)')),
|
|
('non connecte', _('Not connected (Non connecté)')),
|
|
]
|
|
|
|
COATING_CATEGORY_CHOICES = [
|
|
('Vegetal', _('Vegetal (Végétal)')),
|
|
('Structure enherbee', _('Grassed structure (Structure enherbée)')),
|
|
('Materiau non agrege', _('Unbound material (Matériau non agrégé)')),
|
|
('Structure a remplissage mineral', _('Mineral-filled structure (Structure à remplissage minéral)')),
|
|
('Revetement sureleve', _('Raised coating (Revêtement surélevé)')),
|
|
('Modulaire poreux', _('Porous modular (Modulaire poreux)')),
|
|
('Continu poreux', _('Porous continuous (Continu poreux)')),
|
|
('Impermeable', _('Impermeable (Imperméable)')),
|
|
]
|
|
|
|
COATING_TYPE_CHOICES = [
|
|
('Pleine terre', _('Open soil (Pleine terre)')),
|
|
('Melange terre-pierre', _('Soil-stone mixture (Mélange terre-pierre)')),
|
|
('Paves a joints larges enherbes', _('Grassed wide-joint pavers (Pavés à joints larges enherbés)')),
|
|
('Dalles gazon en beton', _('Concrete grass grids (Dalles gazon en béton)')),
|
|
('Dalles alveolaires vegetalisees', _('Vegetated cellular tiles (Dalles alvéolaires végétalisées)')),
|
|
('Mulch vegetal', _('Woodchips/mulch (Mulch végétal)')),
|
|
('Graviers calcaires', _('Limestone gravel (Graviers calcaires)')),
|
|
('Graviers non calcaires', _('Non-limestone gravel (Graviers non calcaires)')),
|
|
('Terre battue', _('Dirt ground (Terre battue)')),
|
|
('Paves a joints larges engravillonnes', _('Gravel wide-joint pavers (Pavés à joints larges engravillonnés)')),
|
|
('Dalles alveolaires en gravier', _('Gravel cellular tiles (Dalles alvéolaires en gravier)')),
|
|
('Dalles en PEHD remplies de pave', _('HDPE tiles filled with pavers (Dalles en PEHD remplies de pavé)')),
|
|
('Grilles', _('Grates (Grilles)')),
|
|
('Platelages bois', _('Wooden decking (Platelages bois)')),
|
|
('Pave en beton poreux', _('Porous concrete pavers (Pavé en béton poreux)')),
|
|
('Dalle en beton poreux', _('Porous concrete slab (Dalle en béton poreux)')),
|
|
('Enrobes bitumineux poreux', _('Porous asphalt (Enrobés bitumineux poreux)')),
|
|
('Betons poreux', _('Porous concrete (Bétons poreux)')),
|
|
('Graviers lies a la resine', _('Resin-bound gravel (Graviers liés à la résine)')),
|
|
('Graviers concasses lies aux polymeres', _('Polymer-bound crushed gravel (Graviers concassés liés aux polymères)')),
|
|
('Revetements EPDM et ESBR', _('EPDM and SBR rubber coatings (Revêtements EPDM et ESBR)')),
|
|
('Revetements en beton de ciment non permeables', _('Non-porous cement concrete coatings (Revêtements en béton de ciment non perméables)')),
|
|
('Revetements bitumineux non permeables', _('Non-porous asphalt coatings (Revêtements bitumineux non perméables)')),
|
|
('Dallages non permeables', _('Non-porous tiling (Dallages non perméables)')),
|
|
('Pavages non permeables', _('Non-porous paving (Pavages non perméables)')),
|
|
('Autres revetements non permeables', _('Other non-porous coatings (Autres revêtements non perméables)')),
|
|
]
|
|
|
|
|
|
GEOMETRY_TYPE_CHOICES = [
|
|
('point', _('Point')),
|
|
('line', _('Line')),
|
|
('polygon', _('Polygon')),
|
|
]
|
|
|
|
|
|
class NatureRWIAsset(AbstractGeoAsset):
|
|
location = models.ForeignKey(NatureRWIZ, on_delete=models.SET_NULL, null=True, blank=True, related_name="assets", verbose_name=_("Zone GIEP / ZIEP"))
|
|
geom = models.GeometryField(srid=3812, null=True, blank=True)
|
|
|
|
external_id = models.IntegerField(null=True, blank=True, verbose_name=_("External ID"))
|
|
code_name = models.CharField(max_length=50, choices=CODE_NAME_CHOICES, null=True, blank=True, verbose_name=_("Code name"))
|
|
structure_type = models.CharField(max_length=100, choices=STRUCTURE_TYPE_CHOICES, null=True, blank=True, verbose_name=_("Structure type"))
|
|
geometry_type = models.CharField(max_length=50, choices=GEOMETRY_TYPE_CHOICES, null=True, blank=True, verbose_name=_("Geometry type"))
|
|
project_manager = models.CharField(max_length=50, choices=PROJECT_MANAGER_CHOICES, null=True, blank=True, verbose_name=_("Project manager"))
|
|
|
|
construction_status = models.CharField(max_length=100, choices=CONSTRUCTION_STATUS_CHOICES, null=True, blank=True, verbose_name=_("Construction status"))
|
|
commissioning_date = models.DateField(null=True, blank=True, verbose_name=_("Commissioning date"))
|
|
condition = models.CharField(max_length=100, choices=CONDITION_CHOICES, null=True, blank=True, verbose_name=_("Condition"))
|
|
administrator = models.CharField(max_length=500, null=True, blank=True, verbose_name=_("Administrator"))
|
|
monitoring = models.CharField(max_length=500, null=True, blank=True, verbose_name=_("Monitoring"))
|
|
comment = models.TextField(null=True, blank=True, verbose_name=_("Comment"))
|
|
has_filter = models.BooleanField(null=True, blank=True, verbose_name=_("Has filter"))
|
|
|
|
sewer_connection = models.CharField(max_length=50, choices=CONNECTION_CHOICES, null=True, blank=True, verbose_name=_("Sewer connection"))
|
|
separate_network_connection = models.CharField(max_length=50, choices=CONNECTION_CHOICES, null=True, blank=True, verbose_name=_("Separate network connection"))
|
|
hydro_network_connection = models.CharField(max_length=50, choices=CONNECTION_CHOICES, null=True, blank=True, verbose_name=_("Hydro network connection"))
|
|
|
|
surface_area = models.FloatField(null=True, blank=True, verbose_name=_("Surface area (m²)"))
|
|
length = models.FloatField(null=True, blank=True, verbose_name=_("Length (m)"))
|
|
|
|
coating_category = models.CharField(max_length=100, choices=COATING_CATEGORY_CHOICES, null=True, blank=True, verbose_name=_("Coating category"))
|
|
coating_type = models.CharField(max_length=100, choices=COATING_TYPE_CHOICES, null=True, blank=True, verbose_name=_("Coating type"))
|
|
|
|
indexes = [
|
|
models.Index(fields=["code"]),
|
|
]
|
|
|
|
class Meta:
|
|
verbose_name = _("RWI Asset")
|
|
verbose_name_plural = _("RWI Assets")
|
|
|
|
def save(self, *args, **kwargs):
|
|
if not self.location_id and self.geom:
|
|
try:
|
|
matching_rwiz = NatureRWIZ.objects.filter(geom__intersects=self.geom).first()
|
|
if matching_rwiz:
|
|
self.location = matching_rwiz
|
|
except Exception:
|
|
pass
|
|
super().save(*args, **kwargs)
|
|
|
|
def get_absolute_url(self):
|
|
return reverse('assets:water_assets_detail', kwargs={'asset_model': 'naturerwiasset', 'asset_id': self.id})
|
|
|
|
|
|
class NatureRWIAssetDocument(Document):
|
|
rwi_asset = models.ForeignKey(NatureRWIAsset, on_delete=models.CASCADE, related_name="documents", verbose_name=_("RWI Asset"))
|
|
file = models.FileField(upload_to="assets_documents/nature/rwi/", storage=private_storage, verbose_name=_("File"), max_length=255)
|
|
thumbnail = models.ImageField(upload_to="assets_documents/nature/rwi/", storage=private_storage, null=True, blank=True, max_length=255)
|
|
|
|
class Meta:
|
|
verbose_name = _("RWI Asset Document")
|
|
verbose_name_plural = _("RWI Asset Documents")
|
|
|
|
|