Customize a GeoNode project model

In this section, we will patch the ResourceBase of GeoNode and update the templates to add one more field to the Metadata Schema.

We will add a custom_md field to the ResourceBase model and modify the templates to show the new field in the Metadata Wizard and the Layer Details page.

Activate the virtualenv

We should already be working in the right directory, and have the proper virtualenv (virtual environment) activated. If not, run:

workon my_geonode
cd /opt/geonode-project/my_geonode/src/
  • Update the GeoNode ResourceBase model

vim /opt/geonode/geonode/base/models.py
--- /opt/geonode/geonode/base/models.py.org	2022-03-18 10:03:35.403505308 +0000
+++ /opt/geonode/geonode/base/models.py	2022-03-18 10:05:23.985766322 +0000
@@ -1081,6 +1081,13 @@
         blank=True,
         help_text=extra_metadata_help_text)
 
+    custom_md_help_text = _('a custom metadata field')
+    custom_md = models.TextField(
+        _("Custom Md"),
+        blank=True,
+        null=True,
+        help_text=custom_md_help_text)
+
     objects = ResourceBaseManager()
 
     class Meta:
  • Add the new field to the DB

./manage_dev.sh makemigrations
./manage_dev.sh migrate
  • Add the new field to templates

mkdir my_geonode/templates/layouts/
cp /opt/geonode/geonode/layers/templates/layouts/panels.html my_geonode/templates/layouts/panels.html
vim my_geonode/templates/layouts/panels.html
--- /opt/geonode/geonode/layers/templates/layouts/panels.html	2022-03-03 15:30:15.670185376 +0000
+++ my_geonode/templates/layouts/panels.html	2022-03-18 10:08:33.660551116 +0000
@@ -322,6 +322,10 @@
                                 </div>
                                 {% endblock thumbnail %}
                                 <div class="col-lg-4">
+                                    <div id="req_item">
+                                      <span><label for="{{ dataset_form.custom_md|id }}">{{ dataset_form.custom_md.label }}</label></span>
+                                      {{ dataset_form.custom_md }}
+                                    </div>
                                     {% block dataset_title %}
                                     <div id="req_item">
                                       <span><label for="{{ dataset_form.title|id }}">{{ dataset_form.title.label }}</label></span>
  • Let’s check the changes

./paver_dev.sh start_django

image

  • Update the custom_md text field to a rich HTML one

vim /opt/geonode/geonode/base/forms.py
diff --git a/geonode/base/forms.py b/geonode/base/forms.py
index 48a0ef7f1..e0284988c 100644
--- a/geonode/base/forms.py
+++ b/geonode/base/forms.py
@@ -416,6 +416,10 @@ class ResourceBaseForm(TranslationModelForm):
         label=_("Data quality statement"),
         required=False,
         widget=TinyMCE())
+    custom_md = forms.CharField(
+        label=_("Custom Md"),
+        required=True,
+        widget=TinyMCE())
 
     owner = forms.ModelChoiceField(
         empty_label=_("Owner"),

image

Detail Panel Update

The detail panel configuration could be updated by editing the json configuration (localConfig) of two plugins inside the GeoNode MapStore client: DetailViewer and ResourcesGrid. It’s possible to update the configuration with the html template _geonode_config.html.

The project should provide the config template called _geonode_config.html in the following location:

/opt/geonode-project/my_geonode/src/my_geonode/
|-- ...
|-- templates/
|    |-- ...
|    +-- geonode-mapstore-client/
|         +-- _geonode_config.html
|-- ...

Update the Detail Panel Info box

The following snippet shows how to loop through all the pages in the GeoNode MapStore client and how to change the details tabs configuration for DetailViewer and ResourcesGrid plugins.

<!-- _geonode_config.html file in the my_geonode project -->
{% extends 'geonode-mapstore-client/_geonode_config.html' %}
{% block override_local_config %}
<script>
    window.__GEONODE_CONFIG__.overrideLocalConfig = function(localConfig) {
        // example: How to change configuration of visible properties in all DetailViewer panels including the one in the catalog (ResourcesGrid)
        Object.keys(localConfig.plugins).forEach((pageName) => {
            localConfig.plugins[pageName].forEach((plugin) => {
                if (['DetailViewer', 'ResourcesGrid'].includes(plugin.name) && plugin.cfg && (plugin.cfg.tabs || plugin.cfg.detailsTabs)) {
                    (plugin.cfg.tabs || plugin.cfg.detailsTabs).forEach((tab) => {
                        if (Array.isArray(tab.items)) {
                            // add the new field in the detail panel
                            tab.items.push({
                              "type": "html",
                              "label": "Custom Metadata",
                              "value": "{context.get(state('gnResourceData'), 'custom_md')}"
                            });
                        }
                    });
                }
            });
        });
        return localConfig;
    };
</script>
{% endblock %}
  • Go to the datastet details (upload a new one if none is present); you most probably won’t see any value for the custom_md field even if you provided a value. This is because the json configuration leverage on the REST APIs in order to get the values

API REST (v2)

  • Let’s add the new custom_md field to the REST API of GeoNode

    The APIs are reachable through the endpoint: http://localhost:8000/api/v2/

    Looking at the http://localhost:8000/api/v2/resources, you will notice that the new field we just added is not visible.

    image

  • Modify the GeoNode base rest API endpoints to add the new field

vim /opt/geonode/geonode/base/api/serializers.py
--- /opt/geonode/geonode/base/api/serializers.py.org	2022-03-18 10:41:19.663006942 +0000
+++ /opt/geonode/geonode/base/api/serializers.py	2022-03-18 10:42:07.590957618 +0000
@@ -471,6 +471,7 @@
         self.fields['processed'] = serializers.BooleanField(read_only=True)
         self.fields['state'] = serializers.CharField(read_only=True)
         self.fields['sourcetype'] = serializers.CharField(read_only=True)
+        self.fields['custom_md'] = serializers.CharField()
 
         self.fields['embed_url'] = EmbedUrlField(required=False)
         self.fields['thumbnail_url'] = ThumbnailUrlField(read_only=True)
@@ -513,7 +514,7 @@
             'raw_abstract', 'raw_purpose', 'raw_constraints_other',
             'raw_supplemental_information', 'raw_data_quality_statement', 'metadata_only', 'processed', 'state',
             'data', 'subtype', 'sourcetype', 'is_copyable',
-            'blob', "metadata", 'executions'
+            'blob', "metadata", 'executions', 'custom_md'
             # TODO
             # csw_typename, csw_schema, csw_mdsource, csw_insert_date, csw_type, csw_anytext, csw_wkt_geometry,
             # metadata_uploaded, metadata_uploaded_preserve, metadata_xml,

Next Section: Save changes to GitHub