Create a geonode project

The geonode-project repository contains a Django project template allowing us to create a brand new web project which has GeoNode core as a dependency.

In simple words, through this project template we are able to customize somehow our GeoNode instance without actually touching the GeoNode core code.

Thanks to the power of Django, we are able to override html templates, views and, within certain limits, the models.

We’ll be calling a geonode project (or geonode-project instance) a Django project created using the geonode-project template.

In this section we will learn how to:

  • Create a new virtual environment for our geonode-project instance

  • Initialize a new geonode project my_geonode

  • Modify the look-and-feel of the my_geonode project

Create my_geonode Django project

First of all we need to create a new virtualenv based on Python 3.8:

mkvirtualenv -p $(which python3.8) my_geonode
command output
created virtual environment CPython3.8.10.final.0-64 in 385ms
  creator CPython3Posix(dest=/home/geonode-vm-321/.virtualenvs/my_geonode, clear=False, global=False)
  seeder FromAppData(download=False, pip=latest, setuptools=latest, wheel=latest, pkg_resources=latest, via=copy, app_data_dir=/home/geonode-vm-321/.local/share/virtualenv/seed-app-data/v1.0.1.debian.1)
  activators BashActivator,CShellActivator,FishActivator,PowerShellActivator,PythonActivator,XonshActivator
virtualenvwrapper.user_scripts creating /home/geonode-vm-321/.virtualenvs/my_geonode/bin/predeactivate
virtualenvwrapper.user_scripts creating /home/geonode-vm-321/.virtualenvs/my_geonode/bin/postdeactivate
virtualenvwrapper.user_scripts creating /home/geonode-vm-321/.virtualenvs/my_geonode/bin/preactivate
virtualenvwrapper.user_scripts creating /home/geonode-vm-321/.virtualenvs/my_geonode/bin/postactivate
virtualenvwrapper.user_scripts creating /home/geonode-vm-321/.virtualenvs/my_geonode/bin/get_env_details
(my_geonode) geonode-vm-321@geonodevm-3:~$

Install the correct version of Django

pip install Django==2.2.20
command output
Collecting Django==2.2.20
  Downloading Django-2.2.20-py3-none-any.whl (7.5 MB)
     |████████████████████████████████| 7.5 MB 3.5 MB/s 
Collecting sqlparse>=0.2.2
  Downloading sqlparse-0.4.1-py3-none-any.whl (42 kB)
     |████████████████████████████████| 42 kB 508 kB/s 
Collecting pytz
  Downloading pytz-2021.1-py2.py3-none-any.whl (510 kB)
     |████████████████████████████████| 510 kB 3.3 MB/s 
Installing collected packages: sqlparse, pytz, Django
Successfully installed Django-2.2.20 pytz-2021.1 sqlparse-0.4.1

The new VirtualEnv called my_geonode is now ready to be used.

Let’s create the target folder with the right permissions for the geonode project:

cd /opt
sudo mkdir geonode-project
sudo chown -Rf geonode: geonode-project/
cd geonode-project/

Now clone the geonode-project template from the repository:

git clone https://github.com/GeoNode/geonode-project.git -b 3.3.x

Create the my_django project by using the geonode-project as a template:

django-admin startproject --template=./geonode-project -e py,sh,md,rst,json,yml,ini,env,sample,properties -n monitoring-cron -n Dockerfile my_geonode

The previous command line should create a new folder called my_geonode containing a Django project instance

Content of "my_geonode/" directory
/opt/geonode-project/my_geonode$ ll
total 220
drwxrwxr-x 7 geonode geonode  4096 Sep  9 15:43 ./
drwxr-xr-x 3 geonode geonode  4096 Sep  9 15:43 ../
-rwxr-xr-x 1 geonode geonode  1261 Sep  9 15:43 celery-cmd*
-rw-rw-r-- 1 geonode geonode   524 Sep  9 15:43 celery.sh
-rw-rw-r-- 1 geonode geonode   644 Sep  9 15:43 dev_config.yml
drwxrwxr-x 6 geonode geonode  4096 Sep  9 15:43 docker/
-rwxr-xr-x 1 geonode geonode    98 Sep  9 15:43 docker-build.sh*
-rw-rw-r-- 1 geonode geonode  6887 Sep  9 15:43 docker-compose.development.yml
-rw-rw-r-- 1 geonode geonode   685 Sep  9 15:43 docker-compose.override.yml
-rw-rw-r-- 1 geonode geonode  4720 Sep  9 15:43 docker-compose.yml
-rw-rw-r-- 1 geonode geonode  3000 Sep  9 15:43 Dockerfile
-rwxr-xr-x 1 geonode geonode   177 Sep  9 15:43 docker-purge.sh*
-rwxr-xr-x 1 geonode geonode  3121 Sep  9 15:43 entrypoint.sh*
-rw-rw-r-- 1 geonode geonode  7138 Sep  9 15:43 .env
drwxrwxr-x 2 geonode geonode  4096 Sep  9 15:43 fixtures/
-rw-rw-r-- 1 geonode geonode   829 Sep  9 15:43 .gitignore
-rw-rw-r-- 1 geonode geonode   506 Sep  9 15:43 jetty-runner.xml
-rw-rw-r-- 1 geonode geonode   559 Sep  9 15:43 Makefile
-rw-rw-r-- 1 geonode geonode    52 Sep  9 15:43 manage_dev.sh.sample
-rwxr-xr-x 1 geonode geonode  1092 Sep  9 15:43 manage.py*
-rwxr-xr-x 1 geonode geonode    77 Sep  9 15:43 manage.sh*
-rw-rw-r-- 1 geonode geonode   256 Sep  9 15:43 monitoring-cron
drwxrwxr-x 5 geonode geonode  4096 Sep  9 15:43 my_geonode/           <------- Django main app folder
-rw-rw-r-- 1 geonode geonode  3308 Sep  9 15:43 .override_dev_env.sample
drwxrwxr-x 3 geonode geonode  4096 Sep  9 15:43 package/
-rw-rw-r-- 1 geonode geonode 41964 Sep  9 15:43 pavement.py
-rw-rw-r-- 1 geonode geonode    40 Sep  9 15:43 paver_dev.sh.sample
-rwxr-xr-x 1 geonode geonode    31 Sep  9 15:43 paver.sh*
-rw-rw-r-- 1 geonode geonode  1566 Sep  9 15:43 playbook.yml
-rw-rw-r-- 1 geonode geonode  6173 Sep  9 15:43 README.md
-rw-rw-r-- 1 geonode geonode    80 Sep  9 15:43 requirements.txt       <------- Django dependencies
drwxrwxr-x 3 geonode geonode  4096 Sep  9 15:43 scripts/
-rw-rw-r-- 1 geonode geonode  1648 Sep  9 15:43 setup.py
-rw-rw-r-- 1 geonode geonode 22993 Sep  9 15:43 tasks.py
-rw-rw-r-- 1 geonode geonode  2445 Sep  9 15:43 uwsgi.ini
-rwxr-xr-x 1 geonode geonode   691 Sep  9 15:43 wait-for-databases.sh*

By taking a look into the /opt/geonode-project/my_geonode/my_geonode you should be able to recognize a standard Django app structure

drwxrwxr-x 5 geonode geonode 4096 Sep  9 15:43 ./
drwxrwxr-x 7 geonode geonode 4096 Sep  9 15:43 ../
-rw-rw-r-- 1 geonode geonode 1279 Sep  9 15:43 apps.py
drwxrwxr-x 2 geonode geonode 4096 Sep  9 15:43 br/
-rw-rw-r-- 1 geonode geonode 1356 Sep  9 15:43 celeryapp.py
-rw-rw-r-- 1 geonode geonode 1042 Sep  9 15:43 __init__.py
-rw-rw-r-- 1 geonode geonode 5000 Sep  9 15:43 settings.py   <------- Django settings
drwxrwxr-x 6 geonode geonode 4096 Sep  9 15:43 static/
drwxrwxr-x 2 geonode geonode 4096 Sep  9 15:43 templates/    <------- HTML templates
-rw-rw-r-- 1 geonode geonode 1234 Sep  9 15:43 urls.py       <------- main URL patterns
-rw-rw-r-- 1 geonode geonode 1779 Sep  9 15:43 version.py
-rw-rw-r-- 1 geonode geonode 1980 Sep  9 15:43 wsgi.py

Some files are still missing, like the views, models and migrations, since they are not needed by default.

Install dependencies

We need to install the geonode project dependencies first.

The default requirements.txt file contains two dependencies, that is

  • core GeoNode

  • geonode_mapstore_client: the adapter for using mapstore in GeoNode

Performing a pip install -r requirements.txt would install these sources inside the virtual environment hidden directory, but we need our copy of the sources to be installed (remember, we need a setup for developers!)

Edit the file requirements.txt and comment out the line

#-e git+https://github.com/GeoNode/geonode.git@3.3.x#egg=GeoNode

then install the other listed requirements:

pip install -r requirements.txt

Then install the local GeoNode in development mode

pip install -e /opt/geonode

As part of the GeoNode setup, you need to install manually some requirements bound to locally installed binary packages:

pip install pygdal=="`gdal-config --version`.*"

Finally install the current app in dev mode

pip install -e .

Should have we needed to work on the geonode_mapstore_client, we would avoid completely to use the requirements.txt file, by cloning and installing manually both requirements.

A warning about the editing of the requirements.txt file: please note that when releasing your geonode project, the geonode requirement should be in there, so we need to uncomment the line we commented out before pushing our files to a git repository.
An alternative way to avoid using the geonode version declared in the requirements.txt file, without the need to edit it, would have been:

  • pip install the original requirements.txt file

  • pip uninstall GeoNode

  • and then, same as the above task, pip install -e /opt/geonode

Anyway keep in mind that this alternative procedure requires to download geonode sources twice.

# Ensure the NGINX and UWSGI services have been stopped
sudo systemctl stop nginx
sudo pkill -9 -f uwsgi
sudo ps aux | grep uwsgi

# Ensure we are in the correct virtualenv and folder
workon my_geonode
cd /opt/geonode-project/my_geonode/
  • Let’s edit the project .env in order to match the dev environment

Configuration

The GeoNode settings are configurable using environment variables. There is a sample file containing the most common variables that may need to be customized.

Copy that sample file into a file we are going to edit:

cd /opt/geonode-project/my_geonode
cp .override_dev_env.sample .override_dev_env

Also copy the sample files used to run the admin commands:

cp paver_dev.sh.sample paver_dev.sh
cp manage_dev.sh.sample manage_dev.sh

chmod +x paver_dev.sh manage_dev.sh

Edit the file .override_dev_env and make sure the database info are correct. Also, add a line

export ASYNC_SIGNALS=False

This is a recap of the edited lines:

(my_geonode) geonode@geonode-32x-vm:/opt/geonode-project/my_geonode$ diff .override_dev_env.sample .override_dev_env
10c10
< export GEONODE_DATABASE=my_geonode
---
> export GEONODE_DATABASE=geonode
12c12
< export GEONODE_GEODATABASE=my_geonode_data
---
> export GEONODE_GEODATABASE=geonode_data
15,16c15,16
< export DATABASE_URL=postgis://my_geonode:geonode@localhost:5432/my_geonode
< export GEODATABASE_URL=postgis://my_geonode_data:geonode@localhost:5432/my_geonode_data
---
> export DATABASE_URL=postgis://geonode:geonode@localhost:5432/geonode
> export GEODATABASE_URL=postgis://geonode_data:geonode@localhost:5432/geonode_data
96a97,98
> 
> export ASYNC_SIGNALS=False

Align the DB and GeoNode

./paver_dev.sh sync

WARNING: Whenever you face some issues with the migrations, please try upgrading the dependency as shown below

pip install geonode-oauth-toolkit==2.2.2

Align the internal URLs and Metadata links

# The order is important! Those are regex expressions and will be executed one after the other...

# Fix GeoServer URLs first
./manage_dev.sh migrate_baseurl --source-address=http://localhost/geoserver --target-address=http://localhost:8080/geoserver

# Fix GeoNode URLs
./manage_dev.sh migrate_baseurl --source-address=http://localhost/ --target-address=http://localhost:8000/

# Align the Metadata links
./manage_dev.sh set_all_layers_metadata -d

Run GeoNode

Finally, start my_geonode with either

./manage_dev.sh runserver 0.0.0.0:8000

or (run in background)

./paver_dev.sh start_django
  • Notice that we don’t need to fix GeoServer OAuth2 endpoints since we did already on the previous section

  • Open the browser and go to the location http://localhost:8000

  • The main page and theme have been changed again

image