# Create a GeoNode project
The [`geonode-project`](https://github.com/GeoNode/geonode-project/tree/4.1.x) repository contains a Django project **template** that allows us to create a brand new web project that _has GeoNode core as a dependency_.
In simple words, using this project template, can customize our GeoNode instance without actually touching the core GeoNode code.
Thanks to the power of Django, we can override **HTML templates**, **views**, and, within certain limits, the **models**.
We'll be calling a **GeoNode project** (or _`geonode-project` instance_) which is 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 called `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.10:
```bash
mkvirtualenv -p $(which python3.10) my_geonode
```
command output
```shell
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
```shell
pip install Django==3.2.18
```
command output
```shell
Collecting Django==3.2.18
Downloading Django-3.2.15-py3-none-any.whl (7.9 MB)
|████████████████████████████████| 7.9 MB 6.5 MB/s
Collecting pytz
Downloading pytz-2021.3-py2.py3-none-any.whl (503 kB)
|████████████████████████████████| 503 kB 6.3 MB/s
Collecting sqlparse>=0.2.2
Downloading sqlparse-0.4.2-py3-none-any.whl (42 kB)
|████████████████████████████████| 42 kB 1.2 MB/s
Collecting asgiref<4,>=3.3.2
Downloading asgiref-3.5.0-py3-none-any.whl (22 kB)
Installing collected packages: pytz, sqlparse, asgiref, Django
Successfully installed Django-3.2.15 asgiref-3.5.0 pytz-2021.3 sqlparse-0.4.2
```
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:
```shell
cd /opt
sudo mkdir geonode-project
sudo chown -Rf $USER: geonode-project/
cd geonode-project/
```
Now clone the `geonode-project` template from the repository:
```shell
git clone https://github.com/GeoNode/geonode-project.git -b 4.1.x
```
Create the `my_django` project by using the `geonode-project` as a template:
```shell
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` that contains a Django project instance
Content of "my_geonode/src" directory
```shell
/opt/geonode-project/my_geonode/src$ ll
total 152
drwxrwxr-x 6 geonode-vm-321 geonode-vm-321 4096 Mar 16 17:42 ./
drwxrwxr-x 4 geonode-vm-321 geonode-vm-321 4096 Mar 16 17:42 ../
-rwxrwxr-x 1 geonode-vm-321 geonode-vm-321 1280 Mar 16 17:42 celery-cmd*
-rw-rw-r-- 1 geonode-vm-321 geonode-vm-321 540 Mar 16 17:42 celery.sh
-rwxrwxr-x 1 geonode-vm-321 geonode-vm-321 2578 Mar 16 17:42 entrypoint.sh*
drwxrwxr-x 2 geonode-vm-321 geonode-vm-321 4096 Mar 16 17:42 fixtures/
-rw-rw-r-- 1 geonode-vm-321 geonode-vm-321 506 Mar 16 17:42 jetty-runner.xml
-rw-rw-r-- 1 geonode-vm-321 geonode-vm-321 559 Mar 16 17:42 Makefile
-rw-rw-r-- 1 geonode-vm-321 geonode-vm-321 52 Mar 16 17:42 manage_dev.sh.sample
-rwxrwxr-x 1 geonode-vm-321 geonode-vm-321 1092 Mar 16 17:42 manage.py*
-rwxrwxr-x 1 geonode-vm-321 geonode-vm-321 77 Mar 16 17:42 manage.sh*
-rw-rw-r-- 1 geonode-vm-321 geonode-vm-321 256 Mar 16 17:42 monitoring-cron
drwxrwxr-x 5 geonode-vm-321 geonode-vm-321 4096 Mar 16 17:42 my_geonode/ <------- Django main app folder
drwxrwxr-x 3 geonode-vm-321 geonode-vm-321 4096 Mar 16 17:42 package/
-rw-rw-r-- 1 geonode-vm-321 geonode-vm-321 39745 Mar 16 17:42 pavement.py
-rw-rw-r-- 1 geonode-vm-321 geonode-vm-321 40 Mar 16 17:42 paver_dev.sh.sample
-rwxrwxr-x 1 geonode-vm-321 geonode-vm-321 31 Mar 16 17:42 paver.sh*
-rw-rw-r-- 1 geonode-vm-321 geonode-vm-321 13 Mar 16 17:42 README.md
-rw-rw-r-- 1 geonode-vm-321 geonode-vm-321 160 Mar 16 17:42 requirements.txt <------- GeoNode/Django dependencies
drwxrwxr-x 3 geonode-vm-321 geonode-vm-321 4096 Mar 16 17:42 scripts/
-rw-rw-r-- 1 geonode-vm-321 geonode-vm-321 1642 Mar 16 17:42 setup.py
-rw-rw-r-- 1 geonode-vm-321 geonode-vm-321 22868 Mar 16 17:42 tasks.py
-rw-rw-r-- 1 geonode-vm-321 geonode-vm-321 2447 Mar 16 17:42 uwsgi.ini
-rwxrwxr-x 1 geonode-vm-321 geonode-vm-321 691 Mar 16 17:42 wait-for-databases.sh*
```
By taking a look into the `/opt/geonode-project/my_geonode/src/my_geonode` you should be able to recognize a standard Django app structure
```shell
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, which are
- 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 `/opt/geonode-project/my_geonode/src/requirements.txt` and comment out the line
```
cd /opt/geonode-project/my_geonode/src
vim requirements.txt
```
```diff
--- requirements.txt 2022-07-25 12:40:54.883782750 +0100
+++ requirements.txt 2022-07-25 13:15:59.807862863 +0100
@@ -1,2 +1,3 @@
-# -e git+https://github.com/GeoNode/geonode-mapstore-client.git@4.1.x#egg=django_geonode_mapstore_client
+-e git+https://github.com/GeoNode/geonode-mapstore-client.git@4.1.x#egg=django_geonode_mapstore_client
+#GeoNode==4.0.3
+-e /opt/geonode
```
Then install the other listed requirements:
```shell
workon my_geonode
pip install -r /opt/geonode-project/my_geonode/src/requirements.txt
```
This will install the local GeoNode and a copy of the geonode-mapstore-client in development mode
As part of the GeoNode setup, you need to manually install some requirements that are bound to the locally installed binary packages:
```shell
pip install pygdal=="`gdal-config --version`.*"
```
Finally, install the current app in dev mode
```shell
cd /opt/geonode-project/my_geonode/src/
pip install -e .
```
```shell
# Ensure the NGINX and UWSGI services have been stopped
sudo systemctl stop nginx
sudo pkill -9 -f uwsgi
sudo ps aux | grep uwsgi
```
- 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 the file we are going to edit:
```shell
# Ensure we are in the correct virtualenv and folder
workon my_geonode
cd /opt/geonode-project/my_geonode/src
cp ../.override_dev_env.sample ../.override_dev_env
```
Also, copy the sample files used to run the admin commands:
```shell
cd /opt/geonode-project/my_geonode/src/
cp paver_dev.sh.sample paver_dev.sh
cp manage_dev.sh.sample manage_dev.sh
cp ../dev_config.yml .
chmod +x paver_dev.sh manage_dev.sh
```
Edit the `.override_dev_env` file
```bash
cd /opt/geonode-project/my_geonode/src
vim ../.override_dev_env
```
Make sure the database info is correct and add the following line
```bash
export ASYNC_SIGNALS=False
```
This is a recap of the edited lines:
```shell
(my_geonode) geonode@geonode-32x-vm:/opt/geonode-project/my_geonode$ diff -u --color .override_dev_env.sample src/.override_dev_env
```
```diff
--- ../.override_dev_env.sample 2022-03-17 16:37:38.211554417 +0000
+++ ../.override_dev_env 2022-03-17 17:03:35.357738873 +0000
@@ -7,13 +7,13 @@
export GEONODE_INSTANCE_NAME=geonode
export DJANGO_SETTINGS_MODULE=my_geonode.settings
-export GEONODE_DATABASE=my_geonode
+export GEONODE_DATABASE=geonode
export GEONODE_DATABASE_PASSWORD=geonode
-export GEONODE_GEODATABASE=my_geonode_data
+export GEONODE_GEODATABASE=geonode_data
export GEONODE_GEODATABASE_PASSWORD=geonode
-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:geonode@localhost:5432/geonode_data
export DEFAULT_BACKEND_DATASTORE=datastore
export GEOSERVER_WEB_UI_LOCATION=http://localhost:8080/geoserver/
@@ -94,3 +94,5 @@
export EXIF_ENABLED=True
export CREATE_LAYER=True
export FAVORITE_ENABLED=True
+
+export ASYNC_SIGNALS=False
```
### Align the DB and GeoNode
```shell
workon my_geonode
cd /opt/geonode-project/my_geonode/src
./manage_dev.sh makemigrations
./manage_dev.sh migrate
```
Align the internal URLs and Metadata links
```shell
# 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_datasets_metadata -d -p
```
### Run GeoNode
Finally, start `my_geonode` with either
```shell
./manage_dev.sh runserver 0.0.0.0:8000
```
or (run in the background)
```shell
./paver_dev.sh start_django
```
- **Notice** how we don't need to fix the GeoServer `OAuth2` endpoints since we already did that in the previous section
- Open the browser and go to the location `http://localhost:8000`
- The main page and theme have been changed again

#### [Next Section: Customize a geonode project model](055_project_customize_model.md)