Añadir extensions/functions/ponderar_bim.py
This commit is contained in:
365
extensions/functions/ponderar_bim.py
Normal file
365
extensions/functions/ponderar_bim.py
Normal file
@@ -0,0 +1,365 @@
|
||||
import uuid
|
||||
from arches.app.functions.base import BaseFunction
|
||||
from arches.app.models.system_settings import settings
|
||||
from arches.app.models import models
|
||||
from arches.app.models.tile import Tile
|
||||
from arches.app.models.resource import Resource
|
||||
from django.db import connection, transaction
|
||||
import json
|
||||
import logging
|
||||
from datetime import datetime
|
||||
|
||||
details = {
|
||||
'name': 'Valor patrimonial',
|
||||
'type': 'node',
|
||||
'description': 'Calcula el valor patrimonial en base a ciertos descriptores y valores',
|
||||
'defaultconfig': {
|
||||
"proteccion": {
|
||||
"valor_ndeId": "d385a291-6ed0-11ee-b4c9-911631b3a94c",
|
||||
"interesante_ndeId": "5162187a-f132-11ee-95c6-c93a5afc2c06",
|
||||
"valor_ndegrpId": "d385a293-6ed0-11ee-b4c9-911631b3a94c",
|
||||
"valor_tipo": ["val_proteccion"],
|
||||
"valor_tipo_indice": 0
|
||||
},
|
||||
"niveles": {
|
||||
"valor_ndeId": "c50d84f4-cdea-11ef-bee9-419cfc3bf4ec",
|
||||
"valor_ndegrpId": "9b8c37d8-cdea-11ef-bee9-419cfc3bf4ec",
|
||||
"valor_tipo": ['Urbana','Formal','Tipológico','Integridad'],
|
||||
"valor_tipo_indice": 2
|
||||
},
|
||||
"otros_patrimonio": {
|
||||
"valor_ndeId": "5d841086-7c2f-11ee-b432-e9e27a5b849b",
|
||||
"valor_ndegrpId": "5d841086-7c2f-11ee-b432-e9e27a5b849b",
|
||||
"valor_tipo": ["Inmaterial","Formal","Muebles","Natural"],
|
||||
"valor_tipo_indice": 3
|
||||
},
|
||||
"seccion_exterior": {
|
||||
"valor_ndeId": "0a0451d4-cdee-11ef-bee9-419cfc3bf4ec",
|
||||
"valor_ndegrpId": "f333aeab-7849-11ee-9872-197bdd009cf7",
|
||||
"valor_tipo": ['Artística','Arquitectónica','Tipológico','Integridad'],
|
||||
"valor_tipo_indice": 4
|
||||
},
|
||||
"seccion_interior": {
|
||||
"valor_ndeId": "7349a5b8-cdee-11ef-bee9-419cfc3bf4ec",
|
||||
"valor_ndegrpId": "d98ea571-7c15-11ee-9f9d-13533b0eb7ec",
|
||||
"valor_tipo": ['Artística','Arquitectónica','Tipológico'],
|
||||
"valor_tipo_indice": 5
|
||||
},
|
||||
"circulacion": {
|
||||
"valor_ndeId": "adf46dba-cdee-11ef-bee9-419cfc3bf4ec",
|
||||
"valor_ndegrpId": "1d6bad39-7c1b-11ee-9f9d-13533b0eb7ec",
|
||||
"valor_tipo": ['Artística','Tipológico'],
|
||||
"valor_tipo_indice": 6
|
||||
},
|
||||
"espacios_exteriores": {
|
||||
"valor_ndeId": "e14ac826-cdee-11ef-bee9-419cfc3bf4ec",
|
||||
"valor_ndegrpId": "a1871e49-7c1d-11ee-9f9d-13533b0eb7ec",
|
||||
"valor_tipo": ['Artística',],
|
||||
"valor_tipo_indice": 7
|
||||
},
|
||||
"valorizacion": {
|
||||
"valor_ndeId": "c72dae37-72c7-11ee-b797-2be08bcc2bc6",
|
||||
"valor_ndegrpId": "c72dae37-72c7-11ee-b797-2be08bcc2bc6",
|
||||
"valor_tipo": ['Urbana','Individual','De conjunto','Arquitectónica','Formal','Tipológico','Histórica','Artística','Integridad','Inmaterial','Simbólico','Natural','Muebles'],
|
||||
"valor_tipo_indice": 1
|
||||
},
|
||||
"valor_string_map": "{'val_final': 'Sin valor', 'rango':[1,25,50], 'val_total':0, 'val_proteccion': [0,0,0,0,0,0],"\
|
||||
"'Urbana': [0,0,0,0,0,0,0,0], 'Individual': [0,0,0,0,0,0,0,0],'De conjunto': [0,0,0,0,0,0,0,0],"\
|
||||
"'Arquitectónica': [0,0,0,0,0,0,0,0], 'Formal': [0,0,0,0,0,0,0,0], 'Tipológico': [0,0,0,0,0,0,0,0],"\
|
||||
"'Histórica': [0,0,0,0,0,0,0,0], 'Artística': [0,0,0,0,0,0,0,0], 'Integridad': [0,0,0,0,0,0,0,0],"\
|
||||
"'Inmaterial': [0,0,0,0,0,0,0,0], 'Simbólico': [0,0,0,0,0,0,0,0], 'Natural': [0,0,0,0,0,0,0,0],"\
|
||||
"'Muebles': [0,0,0,0,0,0,0,0]}",
|
||||
"valor_total_id": "1d5b879a-cdec-11ef-bee9-419cfc3bf4ec", # Nodo para valor numérico calculado. Ej. 38
|
||||
"valor_final_id": "0511276c-cdec-11ef-bee9-419cfc3bf4ec", # Nodo para valor literal por categoría. Ej. Valor B
|
||||
"rango_tipo_id": "c2974c7c-cdeb-11ef-bee9-419cfc3bf4ec", # Nodo para el rango, literal. Ej. [1,25,50]
|
||||
"factor_ajuste_id":"da4a038c-cdeb-11ef-bee9-419cfc3bf4ec", # Nodo para introducir un valor numérico de ajuste.
|
||||
"valor_tipo_id": "8747962c-cdeb-11ef-bee9-419cfc3bf4ec", # Nodo para valor_string_map, literal
|
||||
"triggering_nodegroups": []
|
||||
},
|
||||
"classname": "ValoracionPatrimonial",
|
||||
"component": "",
|
||||
"functionid":"d206bc88-1c17-4860-b70c-5db9af5ab603",
|
||||
}
|
||||
|
||||
class ValoracionPatrimonial(BaseFunction):
|
||||
def get(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def valor_nodo_ponderable(self, tile, request, is_function_save_method=True):
|
||||
"""
|
||||
Función que calcula el valor patrimonial en base a descriptores específicos
|
||||
|
||||
Args:
|
||||
self: Objeto código.
|
||||
tile: Tile al que se adjuntará/modificará el código.
|
||||
request: Solicitud WSGI para verificar que la llamada sea acción del usuario. La función finaliza en valor nulo.
|
||||
is_function_save_method: Un valor booleano que indica si la función que lo llama es la función de guardado.
|
||||
|
||||
jbti - 10.4.25
|
||||
"""
|
||||
if request is None and is_function_save_method == True:
|
||||
return
|
||||
|
||||
valorDictMap={}
|
||||
conceptoValorSumar = {'00000000-0000-0000-7585-000000000000': [0, 'ElementoSinValor']} # estructura (ej.): {'id1':[2,'Urbano'],'id2':....}
|
||||
|
||||
def format_string_value(id_string_value):
|
||||
languages = models.Language.objects.all()
|
||||
default_language = languages.get(code=settings.LANGUAGE_CODE)
|
||||
return {default_language.code: {"value": id_string_value, "direction": default_language.default_direction}}
|
||||
|
||||
def limpiar_valores(preValorDictMap,indiceVal):
|
||||
for val in preValorDictMap:
|
||||
match val:
|
||||
case 'val_final' | 'val_total' | 'rango' | 'val_proteccion':
|
||||
pass
|
||||
case _:
|
||||
preValorDictMap[val][indiceVal] = 0
|
||||
return preValorDictMap
|
||||
|
||||
def calcular_valores_parciales(preValorDictMap):
|
||||
sumaParcial = 0
|
||||
promElementos = 0
|
||||
for val in preValorDictMap:
|
||||
match val:
|
||||
case 'val_final' | 'val_total' | 'rango':
|
||||
sumaTotal = 0
|
||||
case 'val_proteccion':
|
||||
sumaTotal = preValorDictMap[val][0]
|
||||
numSecciones = preValorDictMap[val][2]+preValorDictMap[val][3]+preValorDictMap[val][4]+preValorDictMap[val][5]
|
||||
case _:
|
||||
sumaParcial = sumaParcial + preValorDictMap[val][1]+preValorDictMap[val][2]+preValorDictMap[val][3]
|
||||
promElementos = promElementos + preValorDictMap[val][4]+preValorDictMap[val][5]+preValorDictMap[val][6]+preValorDictMap[val][7]
|
||||
sumaTotal = sumaTotal + sumaParcial
|
||||
if numSecciones in (1,2,3,4):
|
||||
sumaTotal = sumaTotal + promElementos//4 #numSecciones
|
||||
preValorDictMap['val_total'] = sumaTotal
|
||||
|
||||
match sumaTotal:
|
||||
case sumaTotal if sumaTotal < preValorDictMap['rango'][0]:
|
||||
valorFinalRango ="Sin valor"
|
||||
case sumaTotal if (sumaTotal >= preValorDictMap['rango'][0] and sumaTotal < preValorDictMap['rango'][1]):
|
||||
valorFinalRango = "Valor C"
|
||||
case sumaTotal if (sumaTotal >= preValorDictMap['rango'][1] and sumaTotal < preValorDictMap['rango'][2]):
|
||||
valorFinalRango ="Valor B"
|
||||
case sumaTotal if sumaTotal >= preValorDictMap['rango'][2]:
|
||||
valorFinalRango = "Valor A"
|
||||
case _:
|
||||
valorFinalRango = "Valor desconocido"
|
||||
|
||||
if preValorDictMap['val_proteccion'][1] == 0: valorFinalRango = "Sin valor"
|
||||
preValorDictMap['val_final'] = valorFinalRango
|
||||
return preValorDictMap
|
||||
|
||||
def escribir_valores(tileValFinal,preValorDictMap):
|
||||
tileValFinal.data[self.config['valor_total_id'] ] = int(preValorDictMap['val_total'])
|
||||
tileValFinal.data[self.config['valor_final_id'] ] = format_string_value(str(preValorDictMap['val_final']))
|
||||
tileValFinal.data[self.config['rango_tipo_id']] = format_string_value(str(preValorDictMap['rango']))
|
||||
tileValFinal.data[self.config['valor_tipo_id']] = format_string_value(str(preValorDictMap))
|
||||
if str(tile.nodegroup_id) != self.config['valorizacion']['valor_ndegrpId'] :
|
||||
tileValFinal.save()
|
||||
|
||||
return
|
||||
|
||||
def extraer_concepto_valor(string_id_concepto,str_tipo_valor):
|
||||
if string_id_concepto is not None:
|
||||
qry = f"""
|
||||
SELECT v.value
|
||||
FROM values v INNER JOIN values vv ON v.conceptid = vv.conceptid
|
||||
WHERE v.valuetype='{str_tipo_valor}' AND vv.valueid='{string_id_concepto}'
|
||||
"""
|
||||
cursor = connection.cursor()
|
||||
cursor.execute(qry)
|
||||
valorConcepto = cursor.fetchone()[0]
|
||||
if valorConcepto is None: valorConcepto = 0
|
||||
cursor.close()
|
||||
else:
|
||||
valorConcepto = 0
|
||||
return valorConcepto
|
||||
|
||||
def ponderar_elem_const(resourceinstanceID, fichaValorMap, idNGrpExterior,
|
||||
idNodoCambio, valoresDistribuidos, indiceValorMap):
|
||||
sumarValor = 0
|
||||
nivelesElemconst = set()
|
||||
|
||||
elemTiles = Tile.objects.filter(nodegroup_id=idNGrpExterior,resourceinstance_id=resourceinstanceID)
|
||||
def calculo_por_tile(valTile):
|
||||
elemValor = 0
|
||||
cambioVal = 0
|
||||
if idNGrpExterior in valTile.data and valTile.data[idNGrpExterior] is not None:
|
||||
if len(valTile.data[idNGrpExterior]) > 0 :
|
||||
elemValorId = valTile.data[idNGrpExterior][0]
|
||||
else:
|
||||
elemValorId = '00000000-0000-0000-7585-000000000000'
|
||||
if elemValorId not in conceptoValorSumar :
|
||||
conceptoValorSumar.update({elemValorId : [int(extraer_concepto_valor(elemValorId,'hiddenLabel')), str(extraer_concepto_valor(elemValorId,'prefLabel'))]})
|
||||
elemValor = conceptoValorSumar[elemValorId][0]
|
||||
if idNodoCambio in valTile.data and valTile.data[idNodoCambio] is not None:
|
||||
cambioValId = valTile.data[idNodoCambio]
|
||||
if cambioValId not in conceptoValorSumar:
|
||||
conceptoValorSumar.update({cambioValId : [int(extraer_concepto_valor(cambioValId,'hiddenLabel')), str(extraer_concepto_valor(cambioValId,'prefLabel'))]})
|
||||
cambioVal = conceptoValorSumar[cambioValId][0]
|
||||
return elemValor * cambioVal
|
||||
|
||||
if len(elemTiles) > 0 :
|
||||
for otroTile in elemTiles:
|
||||
nivelesElemconst.add(otroTile.parenttile.tileid)
|
||||
if str(otroTile.tileid) != str(tile.tileid) :
|
||||
nivelesElemconst.add(otroTile.parenttile.tileid)
|
||||
sumarValor = sumarValor + calculo_por_tile(otroTile)
|
||||
|
||||
sumarValor = sumarValor + calculo_por_tile(tile)
|
||||
if len(nivelesElemconst) > 0 : sumarValor = sumarValor // len(nivelesElemconst)
|
||||
else:
|
||||
sumarValor = calculo_por_tile(tile)
|
||||
if tile is not None:
|
||||
fichaValorMap['val_proteccion'][indiceValorMap - 2] = 1
|
||||
else:
|
||||
fichaValorMap['val_proteccion'][indiceValorMap - 2] = 0
|
||||
|
||||
limpiar_valores(fichaValorMap,indiceValorMap)
|
||||
for valorDistribuido in valoresDistribuidos:
|
||||
if fichaValorMap['val_proteccion'][indiceValorMap -2] == 1:
|
||||
fichaValorMap[valorDistribuido][indiceValorMap] = sumarValor
|
||||
|
||||
return fichaValorMap
|
||||
|
||||
def ponderar_proteccion(proteccionTile,idNodoEsDeInteres,fichaValorMap,idNodoProteccion,indiceVal):
|
||||
|
||||
if idNodoEsDeInteres in proteccionTile.data :
|
||||
match proteccionTile.data[idNodoEsDeInteres] :
|
||||
case True:
|
||||
fichaValorMap['val_proteccion'][1] = 1
|
||||
case _: # False or None
|
||||
fichaValorMap['val_proteccion'][1] = 0
|
||||
sumaValoresProteccion = 0
|
||||
if idNodoProteccion in proteccionTile.data and proteccionTile.data[idNodoProteccion] is not None:
|
||||
listaValoresId = proteccionTile.data[idNodoProteccion]
|
||||
for valId in listaValoresId:
|
||||
if valId not in conceptoValorSumar:
|
||||
conceptoValorSumar.update({valId : [int(extraer_concepto_valor(valId,'hiddenLabel')), str(extraer_concepto_valor(valId,'prefLabel'))]})
|
||||
sumaValoresProteccion = sumaValoresProteccion + conceptoValorSumar[valId][0]
|
||||
fichaValorMap['val_proteccion'][indiceVal] = sumaValoresProteccion
|
||||
|
||||
return fichaValorMap
|
||||
|
||||
def ponderar_niveles(nivelesTile,idNodoValorNiveles,fichaValorMap,valorDistribuido,indiceVal):
|
||||
if idNodoValorNiveles in nivelesTile.data : #and nivelesTile[0].data[idNodoValorNiveles] is not None:
|
||||
valorId = nivelesTile.data[idNodoValorNiveles]
|
||||
if valorId not in conceptoValorSumar:
|
||||
conceptoValorSumar.update({valorId : [int(extraer_concepto_valor(valorId,'hiddenLabel')), str(extraer_concepto_valor(valorId,'prefLabel'))]})
|
||||
for valDistribuido in valorDistribuido:
|
||||
fichaValorMap[valDistribuido][indiceVal] = conceptoValorSumar[valorId][0]
|
||||
return fichaValorMap
|
||||
|
||||
def ponderar_otros(otrosTile,idNGrpValorOtros,fichaValorMap,indiceVal):
|
||||
if idNGrpValorOtros in otrosTile.data and otrosTile.data[idNGrpValorOtros] is not None:
|
||||
listaValoresId = otrosTile.data[idNGrpValorOtros]
|
||||
for valId in listaValoresId :
|
||||
if valId not in conceptoValorSumar :
|
||||
conceptoValorSumar.update({valId : [int(extraer_concepto_valor(valId,'hiddenLabel')), str(extraer_concepto_valor(valId,'prefLabel'))]})
|
||||
fichaValorMap[conceptoValorSumar[valId][1]][indiceVal] = conceptoValorSumar[valId][0]
|
||||
return fichaValorMap
|
||||
|
||||
def ponderar_valorizacion(valorizacionTile,idNGrpValorizacion,fichaValorMap,indiceVal):
|
||||
if idNGrpValorizacion in valorizacionTile.data and valorizacionTile.data[idNGrpValorizacion] is not None:
|
||||
listaValoresId = valorizacionTile.data[idNGrpValorizacion]
|
||||
for valId in listaValoresId :
|
||||
if valId not in conceptoValorSumar :
|
||||
conceptoValorSumar.update({valId : [int(extraer_concepto_valor(valId,'hiddenLabel')), str(extraer_concepto_valor(valId,'prefLabel'))]})
|
||||
if conceptoValorSumar[valId][1] != 'Sin valor patrimonial' :
|
||||
fichaValorMap[conceptoValorSumar[valId][1]][indiceVal] = conceptoValorSumar[valId][0]
|
||||
return fichaValorMap
|
||||
|
||||
try:
|
||||
|
||||
"""Se carga el valor final (valorStrinMap) o se pone un valor predeterminado (0)"""
|
||||
if str(tile.nodegroup_id) != str(self.config['valorizacion']['valor_ndegrpId']):
|
||||
vfinalTiles = Tile.objects.filter(nodegroup_id=str(self.config['valorizacion']['valor_ndegrpId']),
|
||||
resourceinstance_id=tile.resourceinstance_id)
|
||||
if len(vfinalTiles) > 0 :
|
||||
# (Falta) Procedimiento para validar el valor final existente
|
||||
vfinalTile = vfinalTiles[0]
|
||||
if vfinalTile.data[self.config['valor_tipo_id']] is not None:
|
||||
valorDictMap = eval(str(vfinalTile.data[self.config['valor_tipo_id']]['es']['value']))
|
||||
if len(valorDictMap['val_proteccion']) == 2 : valorDictMap = eval(str(self.config['valor_string_map'])) # Reinicio
|
||||
else:
|
||||
valorDictMap = eval(str(self.config['valor_string_map']))
|
||||
else:
|
||||
valorDictMap = eval(str(self.config['valor_string_map']))
|
||||
tilesCarac = Tile.objects.filter(nodegroup_id = 'c72dae1f-72c7-11ee-b797-2be08bcc2bc6',
|
||||
resourceinstance_id = tile.resourceinstance_id)
|
||||
if len(tilesCarac) == 0 :
|
||||
tileCarac = Tile.get_blank_tile_from_nodegroup_id('c72dae1f-72c7-11ee-b797-2be08bcc2bc6', tile.resourceinstance_id, None)
|
||||
tileCarac.save()
|
||||
else:
|
||||
tileCarac = tilesCarac[0]
|
||||
vfinalTile = Tile.get_blank_tile_from_nodegroup_id(self.config['valorizacion']['valor_ndegrpId'],
|
||||
tile.resourceinstance_id, tileCarac)
|
||||
else:
|
||||
vfinalTile = tile
|
||||
if vfinalTile.data[self.config['valor_tipo_id']] is not None:
|
||||
valorDictMap = eval(str(vfinalTile.data[self.config['valor_tipo_id']]['es']['value']))
|
||||
if len(valorDictMap['val_proteccion']) == 2 : valorDictMap = eval(str(self.config['valor_string_map']))
|
||||
else:
|
||||
valorDictMap = eval(str(self.config['valor_string_map']))
|
||||
|
||||
""" Pondera los valores según el nodo actualmente editado """
|
||||
if tile.nodegroup_id == str(self.config['proteccion']['valor_ndegrpId']) :
|
||||
valorDictMap = ponderar_proteccion(tile, self.config['proteccion']['interesante_ndeId'], valorDictMap,
|
||||
self.config['proteccion']['valor_ndeId'], self.config['proteccion']['valor_tipo_indice'])
|
||||
elif tile.nodegroup_id == str(self.config['niveles']['valor_ndegrpId']) :
|
||||
valorDictMap = ponderar_niveles(tile, self.config['niveles']['valor_ndeId'], valorDictMap,
|
||||
self.config['niveles']['valor_tipo'], self.config['niveles']['valor_tipo_indice'])
|
||||
elif tile.nodegroup_id == str(self.config['otros_patrimonio']['valor_ndegrpId']) :
|
||||
valorDictMap = limpiar_valores(valorDictMap,self.config['otros_patrimonio']['valor_tipo_indice'])
|
||||
valorDictMap = ponderar_otros(tile, self.config['otros_patrimonio']['valor_ndeId'], valorDictMap,
|
||||
self.config['otros_patrimonio']['valor_tipo_indice'])
|
||||
elif tile.nodegroup_id == str(self.config['valorizacion']['valor_ndegrpId']) :
|
||||
valorDictMap = limpiar_valores(valorDictMap,self.config['valorizacion']['valor_tipo_indice'])
|
||||
valorDictMap = ponderar_valorizacion(tile, self.config['valorizacion']['valor_ndeId'], valorDictMap,
|
||||
self.config['valorizacion']['valor_tipo_indice'])
|
||||
elif tile.nodegroup_id == str(self.config['seccion_exterior']['valor_ndegrpId']) :
|
||||
valorDictMap = ponderar_elem_const(tile.resourceinstance_id, valorDictMap, self.config['seccion_exterior']['valor_ndegrpId'],
|
||||
self.config['seccion_exterior']['valor_ndeId'], self.config['seccion_exterior']['valor_tipo'],
|
||||
self.config['seccion_exterior']['valor_tipo_indice'])
|
||||
elif tile.nodegroup_id == str(self.config['seccion_interior']['valor_ndegrpId']) :
|
||||
valorDictMap = ponderar_elem_const(tile.resourceinstance_id, valorDictMap, self.config['seccion_interior']['valor_ndegrpId'],
|
||||
self.config['seccion_interior']['valor_ndeId'], self.config['seccion_interior']['valor_tipo'],
|
||||
self.config['seccion_interior']['valor_tipo_indice'])
|
||||
elif tile.nodegroup_id == str(self.config['circulacion']['valor_ndegrpId']) :
|
||||
valorDictMap = ponderar_elem_const(tile.resourceinstance_id, valorDictMap, self.config['circulacion']['valor_ndegrpId'],
|
||||
self.config['circulacion']['valor_ndeId'], self.config['circulacion']['valor_tipo'],
|
||||
self.config['circulacion']['valor_tipo_indice'])
|
||||
elif tile.nodegroup_id == str(self.config['espacios_exteriores']['valor_ndegrpId']) :
|
||||
valorDictMap = ponderar_elem_const(tile.resourceinstance_id, valorDictMap, self.config['espacios_exteriores']['valor_ndegrpId'],
|
||||
self.config['espacios_exteriores']['valor_ndeId'], self.config['espacios_exteriores']['valor_tipo'],
|
||||
self.config['espacios_exteriores']['valor_tipo_indice'])
|
||||
|
||||
valorDictMap = calcular_valores_parciales(valorDictMap)
|
||||
|
||||
escribir_valores(vfinalTile, valorDictMap)
|
||||
|
||||
return
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(e,"\t*** Fallo al actualizar la ponderación")
|
||||
return
|
||||
|
||||
def save(self, tile, request, context=None):
|
||||
self.logger = logging.getLogger(__name__)
|
||||
print("\n\t*** llamado a la función ponderar.save ***")
|
||||
self.valor_nodo_ponderable(tile=tile, request=request, is_function_save_method=True)
|
||||
return
|
||||
|
||||
def post_save(self, *args, **kwargs):
|
||||
raise NotImplementedError
|
||||
|
||||
def delete(self, tile, request):
|
||||
raise NotImplementedError
|
||||
|
||||
def on_import(self, tile):
|
||||
raise NotImplementedError
|
||||
|
||||
def after_function_save(self, tile, request):
|
||||
raise NotImplementedError
|
||||
Reference in New Issue
Block a user