Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
fafb375
First test tabular dataset
mattiagiupponi Jan 21, 2026
649b0ee
First test tabular dataset
mattiagiupponi Jan 21, 2026
eef368a
First test tabular dataset
mattiagiupponi Jan 21, 2026
3fa2c96
Switching strategy from ogr.open to gdal.Open
mattiagiupponi Jan 22, 2026
d1be44d
Merge branch 'master' of github.com:GeoNode/geonode into tabulardata
mattiagiupponi Jan 22, 2026
0d503cf
merge with master
mattiagiupponi Jan 22, 2026
5bf9829
Add support for replace tabular data
mattiagiupponi Jan 22, 2026
9f6d104
Add support for replace, upsert for tabular data
mattiagiupponi Jan 23, 2026
6ae7a65
Add support for copy for tabular dataset
mattiagiupponi Jan 23, 2026
f90e202
fix tests
mattiagiupponi Jan 23, 2026
6b78d5a
add docstring
mattiagiupponi Jan 23, 2026
77dac63
fix tests
mattiagiupponi Jan 23, 2026
2ebb8de
fix tests
mattiagiupponi Jan 23, 2026
c922571
Merge branch 'master' into tabulardata
giohappy Feb 5, 2026
68bdd7c
aligned identify_autothority with master
giohappy Feb 5, 2026
fcf383c
Merge branch 'master' into tabulardata
mattiagiupponi Feb 18, 2026
6f2c0b7
[Fixes #13939] Add support for non-spatial datasets in CSV format in …
mattiagiupponi Mar 27, 2026
df65487
Merge branch 'tabulardata' of github.com:GeoNode/geonode into tabular…
mattiagiupponi Mar 27, 2026
3b65ec5
[Fixes #13939] Add support for non-spatial datasets in CSV format in …
mattiagiupponi Mar 27, 2026
60d9225
Merge branch 'master' of github.com:GeoNode/geonode into tabulardata
mattiagiupponi Apr 3, 2026
73ead0d
Fix replace functionality and upsert on tabular dataset
mattiagiupponi Apr 3, 2026
5542a28
Fix replace functionality and upsert on tabular dataset
mattiagiupponi Apr 3, 2026
d155209
Fix replace functionality and upsert on tabular dataset
mattiagiupponi Apr 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions geonode/base/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -955,23 +955,27 @@ def raw_abstract(self):

@property
def can_be_downloaded(self):
return self.subtype in {"vector", "raster", "vector_time"}
return self.subtype in {"vector", "raster", "vector_time", "tabular"}

@property
def can_have_wfs_links(self):
return self.subtype == "vector"

@property
def can_have_wps_links(self):
return self.subtype in {"vector", "tileStore", "remote", "wmsStore", "vector_time"}
return self.subtype in {"vector", "tileStore", "remote", "wmsStore", "vector_time", "tabular"}

@property
def should_create_style(self):
return self.subtype != "tabular"

@property
def can_have_style(self):
return self.subtype not in {"tileStore", "remote"}
return self.subtype not in {"tabular", "tileStore", "remote", "tabular"}

@property
def can_have_thumbnail(self):
return self.subtype not in {"3dtiles", "cog", "flatgeobuf"}
return self.subtype not in {"tabular", "3dtiles", "cog", "flatgeobuf"}

@property
def raw_purpose(self):
Expand All @@ -993,6 +997,15 @@ def raw_data_quality_statement(self):
def detail_url(self):
return self.get_absolute_url()

def fixup_store_type(self, keys, values):
from geonode.geoserver.helpers import get_dataset_storetype

if self.subtype == "tabular":
return self
for key in keys:
setattr(self, key, get_dataset_storetype(values[key]))
return self

def clean(self):
if self.title:
self.title = self.title.replace(",", "_")
Expand Down
8 changes: 3 additions & 5 deletions geonode/geoserver/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
("application/wfs-collection-1.1", "vector"),
("application/zip", "vector"),
("text/csv", "vector"),
("text/csv", "tabular"),
]

DEFAULT_STYLE_NAME = ["generic", "line", "point", "polygon", "raster"]
Expand Down Expand Up @@ -1974,10 +1975,7 @@ def sync_instance_with_geoserver(instance_id, *args, **kwargs):
instance.gs_resource = gs_resource

# Iterate over values from geoserver.
for key in ["alternate", "store", "subtype"]:
# attr_name = key if 'typename' not in key else 'alternate'
# print attr_name
setattr(instance, key, get_dataset_storetype(values[key]))
instance = instance.fixup_store_type(["alternate", "store", "subtype"], values)

if updatemetadata:
_sync_geoserver_keywords_to_instance(instance, gs_resource.keywords)
Expand Down Expand Up @@ -2077,7 +2075,7 @@ def sync_instance_with_geoserver(instance_id, *args, **kwargs):
# Refresh from DB
instance.refresh_from_db()

if updatemetadata:
if updatemetadata and instance.should_create_style:
# Save dataset styles
logger.debug(f"... Refresh Legend links for Dataset {instance.title}")
try:
Expand Down
3 changes: 3 additions & 0 deletions geonode/geoserver/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,9 @@ def geoserver_create_style(self, instance_id, name, sld_file, tempdir):
logger.debug(f"Dataset id {instance_id} does not exist yet!")
raise

if not instance.should_create_style:
return

lock_id = f"{self.request.id}" if self.request.id else instance.name
log_lock.debug(f"geoserver_create_style: Creating lock {lock_id} for {instance.name}")
with AcquireLock(lock_id) as lock:
Expand Down
1 change: 1 addition & 0 deletions geonode/layers/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ class Meta:
"store",
"subtype",
"ptype",
"is_tabular",
)
)
)
Expand Down
4 changes: 4 additions & 0 deletions geonode/layers/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,10 @@ def is_vector(self):
def is_raster(self):
return self.subtype == "raster"

@property
def is_tabular(self):
return self.subtype == "tabular"

@property
def supports_time(self):
valid_attributes = self.get_choices
Expand Down
3 changes: 3 additions & 0 deletions geonode/upload/celery_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -1046,6 +1046,9 @@ def upsert_data(self, execution_id, /, handler_module_path, action, **kwargs):

_datastore.pre_processing(**kwargs)

if not _datastore.input_is_valid():
raise Exception("dataset is invalid")

is_valid, errors = _datastore.upsert_validation(execution_id, **kwargs)
if not is_valid:
raise UpsertException(errors)
Expand Down
2 changes: 1 addition & 1 deletion geonode/upload/handlers/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ class BaseVectorFileHandler(BaseHandler):
return

def create_geonode_resource(
self, layer_name: str, alternate: str, execution_id: str, resource_type: Dataset = Dataset, files=None
self, layer_name: str, alternate: str, execution_id: str, resource_type: Dataset = Dataset, files=None, **kwargs
):
"""
Base function to create the resource into geonode. Each handler can specify
Expand Down
35 changes: 16 additions & 19 deletions geonode/upload/handlers/common/raster.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
from typing import List

from django.conf import settings
from django.db.models import Q
from geonode.base.models import ResourceBase
from geonode.layers.models import Dataset
from geonode.resource.enumerator import ExecutionRequestAction as exa
Expand Down Expand Up @@ -238,11 +237,7 @@ def extract_resource_to_publish(self, files, action, layer_name, alternate, **kw
return [
{
"name": alternate,
"crs": ResourceBase.objects.filter(
Q(alternate__icontains=layer_name) | Q(title__icontains=layer_name)
)
.first()
.srid,
"crs": ResourceBase.objects.filter(alternate=kwargs.get("original_dataset_alternate")).first().srid,
"raster_path": raster_path,
}
]
Expand Down Expand Up @@ -328,12 +323,7 @@ def import_resource(self, files: dict, execution_id: str, **kwargs) -> str:
return

def create_geonode_resource(
self,
layer_name: str,
alternate: str,
execution_id: str,
resource_type: Dataset = Dataset,
asset=None,
self, layer_name: str, alternate: str, execution_id: str, resource_type: Dataset = Dataset, asset=None, **kwargs
):
"""
Base function to create the resource into geonode. Each handler can specify
Expand Down Expand Up @@ -385,12 +375,7 @@ def create_geonode_resource(
return saved_dataset

def overwrite_geonode_resource(
self,
layer_name: str,
alternate: str,
execution_id: str,
resource_type: Dataset = Dataset,
asset=None,
self, layer_name: str, alternate: str, execution_id: str, resource_type: Dataset = Dataset, asset=None, **kwargs
):

_exec = self._get_execution_request_object(execution_id)
Expand All @@ -404,7 +389,19 @@ def overwrite_geonode_resource(
if dataset.exists() and _overwrite:
dataset = dataset.first()

dataset = resource_manager.update(dataset.uuid, instance=dataset)
dataset = resource_manager.update(
dataset.uuid,
instance=dataset,
vals=dict(
name=alternate,
workspace=dataset.workspace,
subtype="raster",
alternate=f"{dataset.workspace}:{alternate}",
dirty_state=True,
title=layer_name,
owner=_exec.user,
),
)

self.handle_xml_file(dataset, _exec)
self.handle_sld_file(dataset, _exec)
Expand Down
1 change: 1 addition & 0 deletions geonode/upload/handlers/common/remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ def create_geonode_resource(
execution_id: str,
resource_type: ResourceBase = ResourceBase,
asset=None,
**kwargs,
):
"""
Creating geonode base resource
Expand Down
7 changes: 5 additions & 2 deletions geonode/upload/handlers/common/tests_vector.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,9 @@ def test_import_resource_should_not_be_imported(self, celery_chord, ogr2ogr_driv
If the resource exists and should be skept, the celery task
is not going to be called and the layer is skipped
"""
mocked_obj = MagicMock()
mocked_obj.name = "CSV"
ogr2ogr_driver.return_value = mocked_obj
exec_id = None
try:
# create the executionId
Expand All @@ -312,9 +315,9 @@ def test_import_resource_should_not_be_imported(self, celery_chord, ogr2ogr_driv
# start the resource import
self.handler.import_resource(files=self.valid_files, execution_id=str(exec_id))
self.assertIn(
"No valid layers found",
"not recognized as a supported file format.",
exception.exception.args[0],
"No valid layers found.",
"not recognized as a supported file format.",
)

celery_chord.assert_not_called()
Expand Down
Loading
Loading