# 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:
```shell
workon my_geonode
cd /opt/geonode-project/my_geonode/src/
```
- Update the GeoNode `ResourceBase` model
```shell
vim /opt/geonode/geonode/base/models.py
```
```diff
--- /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
```shell
./manage_dev.sh makemigrations
./manage_dev.sh migrate
```
- Add the new field to `templates`
```shell
mkdir my_geonode/templates/layouts/
cp /opt/geonode/geonode/layers/templates/layouts/panels.html my_geonode/templates/layouts/panels.html
```
```shell
vim my_geonode/templates/layouts/panels.html
```
```diff
--- /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 @@
{% endblock thumbnail %}
+
+
+ {{ dataset_form.custom_md }}
+
{% block dataset_title %}
```
- Let's check the changes
```shell
./paver_dev.sh start_django
```

- Update the `custom_md` text field to a `rich HTML` one
```shell
vim /opt/geonode/geonode/base/forms.py
```
```diff
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"),
```

## 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.
```django
{% extends 'geonode-mapstore-client/_geonode_config.html' %}
{% block override_local_config %}
{% 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.

- Modify the GeoNode `base` rest API endpoints to add the new field
```shell
vim /opt/geonode/geonode/base/api/serializers.py
```
```diff
--- /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,
```
- `http://localhost:8000/api/v2/resources?filter{custom_md.isnull}=False`

- More info about `dynamic-rest` filtering options can be found at: [`https://github.com/AltSchool/dynamic-rest#filtering`](https://github.com/AltSchool/dynamic-rest#filtering)
#### [Next Section: Save changes to GitHub](060_GEONODE_PROJ_SAVE_GITHUB.md)