Skip to content

saezlab/omnipath-server-django

Repository files navigation

Step by Step Development of Omnipath Web server (Fullstack + API)

Repository name: omnipath-server-django

Minimum Viable Product (MVP):

  • Load a subset of the interactions table (100 rows) into a PosgreSQL database.
  • Build an API to retrieve information from this database.

Software required

  • Python: >= 3.10
  • Poetry
  • Docker
  • PosgreSQL: >=15
  • pgAdmin or dBeaver
  • Postman

Setting up pre-requirements

  1. Configure Poetry environment to be created inside of project's folder
poetry config virtualenvs.in-project true

Setting up main project

Installing required Python packages

  1. Create an empty project using Poetry
  • Poetry ~1.8
poetry new omnipath-server-django
  • Poetry >2.0
poetry new omnipath-server-django --flat
  1. Install Django Framework

The current version of Django by the time of writing this document is 5.1.6. We are going to install this version by using poetry add.

poetry add Django="5.1.6"
  1. Install Django REST Framework
poetry add djangorestframework="^3.15"
  1. Install CORS headers support for Django
poetry add django-cors-headers="^4.7.0"
  1. Install Psycopg (PostgreSQL driver for Python)
# Psycopg 3 (recommended for new projects)
poetry add psycopg[binary]

Create the main Django project

  1. Go to the root of the recently created project.
cd omnipath-server-django
  1. Delete the folder omnipath_server_django. This folder was created by Poetry. By doing this we are avoiding a possible conflict with the folder that Django will create.
rm -rf omnipath_server_django
  1. Create an empty Django project (main project)

Note: do no forget the dot (.) at the end, this allows Django to create the project in the current folder

poetry run django-admin startproject omnipath_server_django .

In the end of this process, you should check that the folder omnipath_server_django and a Python file have been created. The structure of the project should look like this:

omnipath-server-django/
├── manage.py                # Django CLI tool
├── omnipath_server_django/  # Django project settings
│   ├── asgi.py              # ASGI entry point
│   ├── __init__.py          # init file│
│   ├── settings.py          # project settings
│   ├── urls.py              # root URL config
│   └── wsgi.py              # WSGI entry point
├── poetry.lock              # poetry lock file
├── pyproject.toml           # poetry dependencies
├── README.md                # project documentation
├── tests                    # test suite folder (unit, integration, etc.)
|   └── __init__.py          # init file
└── .venv/                   # virtual environment (optional)

Configure PostgreSQL as default Database

  1. By default Django uses SQLite, for our project we are going to configure PosgreSQL as the default database. Open the omnipath_server_django/settings.py file and add the following parameters in the DATABASES section:
  • Connection details:
    • Database name: omnipath_db
    • User: postgres
    • Password: omnipath_admin_123 (for the superuser postgres)
    • Host: 127.0.0.1 (localhost)
    • Port: 5432 (default for PostgreSQL)
DATABASES = {
	# ---------------------------
	# --  PostgreSQL Settings  --
	# ---------------------------
	"default": {
        "ENGINE": "django.db.backends.postgresql",
        "NAME": "omnipath_db",
        "USER": "postgres",
        "PASSWORD": "omnipath_admin_123",
        "HOST": "127.0.0.1",
        "PORT": 5432,
    }

    # --------------------------
	# --   SQLite Settings    --
	# --------------------------
	# "default": {
	#   "ENGINE": "django.db.backends.sqlite3",
	#   "NAME": BASE_DIR / "db.sqlite3",
	# }
}

Create the API app

  1. Create a Django app as part of the overall project, this app will be our API.
poetry run python startapp api
  1. Register the following apps including the api as part of the project in the file omnipath_server_django/settings.py. Add the following elements in INSTALLED_APPS list:
  • "django.contrib.postgres"
  • "rest_framework"
  • "corsheaders"
  • "api"

The INSTALLED_APPS should look like this:

INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "django.contrib.postgres",
    "rest_framework",
    "corsheaders",
    "api",
]
  1. Add the CORS middleware in the MIDDLEWARE section by adding the following:
  • "corsheaders.middleware.CorsMiddleware"

The MIDDLEWARE section should look like this:

MIDDLEWARE = [
    "corsheaders.middleware.CorsMiddleware",
    "django.middleware.security.SecurityMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.middleware.csrf.CsrfViewMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "django.contrib.messages.middleware.MessageMiddleware",
    "django.middleware.clickjacking.XFrameOptionsMiddleware",
]

Creating the Django Model

A model is a class that represents a table or collection in a database. Our naming convention for tables will be the following:

  • Use only lowercase letters and underscore to separate words.
  • Add the suffix omnipath at the end of the name.

The table names for the Omnipath database will be:

  • interactions_omnipath
  • enzsub_omnipath
  • complexes_omnipath
  • intercell_omnipath
  • annotations_omnipath

For our MVP we will be working on the interactions_omnipath table. This table consist of the following schema:

Column Name Data Type (SQL alchemy) Data Type (Django ORM) Nullable Auto Increment Default
id Integer models.IntegerField(primary_key=True)
source String models.CharField(null=True, blank=True)
target String models.CharField(null=True, blank=True)
source_genesymbol String models.CharField(null=False, blank=True)
target_genesymbol String models.CharField(null=False, blank=True)
is_directed Boolean models.BooleanField()
is_stimulation Boolean models.BooleanField()
is_inhibition Boolean models.BooleanField()
consensus_direction Boolean models.BooleanField()
consensus_stimulation Boolean models.BooleanField()
consensus_inhibition Boolean models.BooleanField()
sources ARRAY(String) models.ArrayField(models.CharField(max_length=255))
references String models.CharField(null=False, blank=True)
omnipath Boolean models.BooleanField()
kinaseextra Boolean models.BooleanField()
ligrecextra Boolean models.BooleanField()
pathwayextra Boolean models.BooleanField()
mirnatarget Boolean models.BooleanField()
dorothea Boolean models.BooleanField()
collectri Boolean models.BooleanField()
tf_target Boolean models.BooleanField()
lncrna_mrna Boolean models.BooleanField()
tf_mirna Boolean models.BooleanField()
small_molecule Boolean models.BooleanField()
dorothea_curated Boolean models.BooleanField()
dorothea_chipseq Boolean models.BooleanField()
dorothea_tfbs Boolean models.BooleanField()
dorothea_coexp Boolean models.BooleanField()
dorothea_level ARRAY(String) models.ArrayField(models.CharField(max_length=255))
type String models.CharField(null=False, blank=True)
curation_effort Integer models.IntegerField()
extra_attrs JSONB models.JSONField(null=True, blank=True)
evidences JSONB models.JSONField(null=True, blank=True)
ncbi_tax_id_source Integer models.IntegerField()
entity_type_source String models.CharField(null=False, blank=True)
ncbi_tax_id_target Integer models.IntegerField()
entity_type_target String models.CharField(null=False, blank=True)
  1. Create a model or blueprint for each table. Open the file omnipath_server_django/api/models.py file. This file will contains all the classes that represent the tables. In our case we are going to create just one class for the table interactions_omnipath
from django.db import models


# Model for the table `interactions_omnipath`.
class InteractionsOmnipath(models.Model):
    source = models.CharField(null=True, blank=True)
    target = models.CharField(null=True, blank=True)
    source_genesymbol = models.CharField(null=False, blank=True)
    target_genesymbol = models.CharField(null=False, blank=True)
    is_directed = models.BooleanField()
    is_stimulation = models.BooleanField()
    is_inhibition = models.BooleanField()
    consensus_direction = models.BooleanField()
    consensus_stimulation = models.BooleanField()
    consensus_inhibition = models.BooleanField()
    sources = models.ArrayField(models.CharField(max_length=255))
    references = models.CharField(null=False, blank=True)
    omnipath = models.BooleanField()
    kinaseextra = models.BooleanField()
    ligrecextra = models.BooleanField()
    pathwayextra = models.BooleanField()
    mirnatarget = models.BooleanField()
    dorothea = models.BooleanField()
    collectri = models.BooleanField()
    tf_target = models.BooleanField()
    lncrna_mrna = models.BooleanField()
    tf_mirna = models.BooleanField()
    small_molecule = models.BooleanField()
    dorothea_curated = models.BooleanField()
    dorothea_chipseq = models.BooleanField()
    dorothea_tfbs = models.BooleanField()
    dorothea_coexp = models.BooleanField()
    dorothea_level = models.ArrayField(models.CharField(max_length=255))
    type = models.CharField(null=False, blank=True)
    curation_effort = models.IntegerField()
    extra_attrs = models.JSONField(null=True, blank=True)
    evidences = models.JSONField(null=True, blank=True)
    ncbi_tax_id_source = models.IntegerField()
    entity_type_source = models.CharField(null=False, blank=True)
    ncbi_tax_id_target = models.IntegerField()
    entity_type_target = models.CharField(null=False, blank=True)

    class Meta:
        db_table = "interactions_omnipath"  # Name of the table in the database
        verbose_name = (
            "Interactions Omnipath"  # Optional, for human-readable name in Django admin
        )
        ordering = ("id",)

Creating the Serializer file

  1. Create a file in /api/serializers.py. This file will serve to create encoding and decoding classes.
from rest_framework import serializers
from api.models import InteractionsOmnipath

class InteractionsOmnipathSerializer(serializers.ModelSerializer):

    class Meta:
        model = InteractionsOmnipath
        fields = ("id", "source", "target")  # Just two fields for this example

Create a superuser account for Django

  1. Run the following command
poetry run python manage.py createsuperuser

Fields

Mapping Views to URLS

  1. in omnipath_server_django/urls.py
from django.urls import re_path
from . import views

urlpatterns = [
    re_path(r"^api/interactions$", views.interactions_list),
    re_path(r"^api/interactions/(?P<pk>[0-9]+)$", views.interaction_detail),
]
  1. In api/urls.py
from django.contrib import admin
from django.urls import path
from django.urls import include

urlpatterns = [
    path("admin/", admin.site.urls),
    path("", include("api.urls")),
]

Register model with admin site

  1. In api/admin.py inser the following
from django.contrib import admin
from .models import In