sql >> Base de Datos >  >> RDS >> PostgreSQL

Esquemas / espacios de nombres de PostgreSQL con Django

¿Qué le parecería si pudiera organizar los objetos de su base de datos (p. ej., tablas y vistas) en espacios de nombres de acuerdo con sus roles en el sistema?
En este artículo veremos la forma correcta de manejar los esquemas de PostgreSQL en Django y algunos pequeños consejos sobre Modelos de Django y Python.

Esquema

También conocido como espacio de nombres, el esquema es un tipo de objeto de base de datos cuyo propósito es ser una capa de organización jerárquica que se encuentra justo debajo de una base de datos.
En PostgreSQL, "público" es el esquema predeterminado, pero puede crear uno propio espacios de nombres para organizar otros tipos de objetos como tablas, vistas, funciones, etc.

Jerarquía de objetos de base de datos

- Server
   |- PostgreSQL Instance (Port 5432 by default)
       |- Role (Users and Groups)
       |- Tablespace
       |- Database
           |- Trigger
           |- Extension
           |- Language
           |- Schema      
               |- Table
               |- View
               |- Materialized View
               |- Sequence
               |- Function
               |- Procedure

Acerca de nuestro laboratorio

Ese es un laboratorio simple con Django en un entorno virtual (con virtualenv) y PostgreSQL instalado en localhost.

  • Python 3.8
  • Django 3.0
  • PostgreSQL 12

Debería funcionar con muchas versiones anteriores 🙂

Códigos

  • > SQL (psql);
  • $ shell (Linux, FreeBSD, Unix*);
  • >>> shell de Python.

Practica

  • PostgreSQL

La estructura de la base de datos es lo primero que haremos.

  • Creación de usuario de base de datos para la aplicación;
  • Creación de base de datos;
  • Creación de esquemas;
  • Creación de tablas

Vamos a crear nuestro propio ejemplo en la herramienta de línea de comandos integrada de psql:

$ psql

Creación de aplicación de usuario:

CREATE ROLE user_test ENCRYPTED PASSWORD '123' LOGIN;

El rol de la base de datos se creó con una contraseña cifrada y un atributo de inicio de sesión (usuario).

Creación de base de datos para pruebas:

> CREATE DATABASE db_test OWNER user_test;

La base de datos es propiedad de "user_test".

Conéctese a él como usuario "user_test":

> \c db_test user_test

Dentro del nombre de usuario de la base de datos psql shell \c.

Creación de un esquema:

> CREATE SCHEMA ns_hr;

¡El espacio de nombres para nuestro ejemplo está listo!

Mostrar todos los esquemas que no son catálogos:

> SELECT
nspname AS namespace
FROM pg_catalog.pg_namespace
WHERE nspname !~ '(^pg_|information_schema)';

Salida:

namespace 
-----------
 public
 ns_hr

Fíjate que aparece el espacio de nombres por defecto (público) y el ns_hr, creado para nuestro laboratorio.

Creación de una tabla en el esquema ns_hr:

> CREATE TABLE ns_hr.tb_person(
    id_ serial primary key,
    name text not null,
    surname text not null
);

Una mesa sencilla…

Presiona <Ctrl> + D para salir.

  • Django

¡Es hora de codificar en Python! 😀

  • Entorno virtual;
  • Instalación de módulos de Python;
  • Creación y configuración de proyectos Django;
  • Creación de la aplicación Django;
  • Creación de modelos Django;
  • Migraciones;
  • Pruebas en shell;

Creación de entornos virtuales:

$ virtualenv -p `which python3.8` django

La ruta absoluta del binario de Python 3.8 se indicó como intérprete de Python de este entorno.

Acceda al directorio del entorno y actívelo:

$ cd django && source bin/activate

Su mensaje cambió, comenzó en "(django)", lo que indica que su entorno virtual se activó.

Instalar módulos necesarios para nuestras pruebas:

$ pip install django psycopg2-binary configobj ipython

Respectivamente:framework web Django, controlador PostgreSQL, lector de archivos de configuración y shell interactivo mejorado.

Creación de un nuevo proyecto Django:

$ django-admin startproject my_project

Cambie el nombre del directorio del proyecto a src:

$ mv my_project src

Esto es para facilitar la jerarquía de directorios y no afectará los resultados. Es porque tiene un directorio con el mismo nombre que puede causar cierta confusión...

Creación del archivo de configuración de la base de datos:

$ cat << EOF > src/my_project/db.conf
DB_HOST = 'localhost'
DB_NAME = 'db_test'
DB_USER = 'user_test'
DB_PASSWORD = '123'
DB_PORT = 5432
EOF

Aquí creamos un archivo de configuración separado para la conexión de la base de datos.

Editar el archivo de configuración principal del proyecto:

$ vim src/my_project/settings.py

import os

from configobj import ConfigObj

Debajo de las importaciones, agregue una línea que traiga la clase ConfigObj.

# Database
# https://docs.djangoproject.com/en/2.2/ref/settings/#databases

# Database configuration file location
DB_CONF_FILE = f'{BASE_DIR}/my_project/db.conf'

# Read the configurations from file
DB_CONFIG = ConfigObj(DB_CONF_FILE)

# Database connection parameters

DB_HOST = DB_CONFIG['DB_HOST']
DB_NAME = DB_CONFIG['DB_NAME']
DB_USER = DB_CONFIG['DB_USER']
DB_PASSWORD = DB_CONFIG['DB_PASSWORD']
DB_PORT = DB_CONFIG['DB_PORT']

DATABASES = {
             'default': {
                         'ENGINE': 'django.db.backends.postgresql',
                         'NAME': DB_NAME,
                         'USER': DB_USER,
                         'PASSWORD': DB_PASSWORD,
                         'HOST': DB_HOST,
                         'PORT': DB_PORT,
                         }
            }

Modifique la "sesión" de la base de datos como se indicó anteriormente.

Creación de enlace simbólico para manage.py:

$ ln -s `pwd`/src/manage.py `pwd`/bin/manage.py

Para facilitar nuestro trabajo, creamos un enlace simbólico a manage.py en el directorio bin que se encuentra en nuestro $PATH.

Ejecutar servidor web virtual:

$ manage.py runserver 0.0.0.0:8000

Pruebe en su navegador:http://localhost:8000 y luego + C para cancelar.

Acceder al directorio del proyecto:

$ cd src

Veamos los archivos dentro del directorio actual:

$ tree .

Salida:

.
├── manage.py
└── my_project
    ├── db.conf
    ├── __init__.py
    ├── __pycache__
    │   ├── __init__.cpython-38.pyc
    │   ├── settings.cpython-38.pyc
    │   ├── urls.cpython-38.pyc
    │   └── wsgi.cpython-38.pyc
    ├── settings.py
    ├── urls.py
    └── wsgi.py

Muestra el contenido del directorio actual en un formato de árbol.
Aquí vemos todos los archivos dentro del proyecto.

Primera migración de metadatos de Django:

$ manage.py migrate

Creación de superusuario de Django:

$ manage.py createsuperuser

Crear una aplicación:

$ manage.py startapp human_resource

Editar settings.py para agregar una nueva aplicación:

$ vim my_project/settings.py
# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    # Custom Apps
    'human_resource',
]

Un truco genial de Django:puedes usar un directorio models en lugar de un archivo models.py.
Pero debes crear un archivo dunder init (__init__.py) dentro del directorio models.
¡Vamos!

Creación del directorio de modelos dentro del directorio de la aplicación:

$ mkdir human_resource/models

Eliminar el archivo models.py:

$ rm -f human_resource/models.py

Creación de modelo:

$ vim human_resource/models/hr.py
from django.db.models import AutoField
from django.db.models import Model
from django.db.models import TextField


class Person(Model):
    '''
    Person Model

    Namespace: ns_hr
    Table: tb_person
    '''

    id_ = AutoField(db_column='id_', name='id', primary_key=True,)
    name = TextField(db_column='name', name='name',)
    surname = TextField(db_column='surname', name='surname',)

    def __str__(self):
        return f'{self.name} {self.surname}'

    class Meta:
        db_table = 'ns_hr"."tb_person'  # 'schema"."object'
        verbose_name_plural = 'Person'

Para disfrutar de los beneficios de los esquemas de PostgreSQL, dentro de su modelo, en la clase interna Meta, al valor del atributo "db_table" debe poner un punto que separa el espacio de nombres y el objeto entre comillas.

'schema"."object'

El objeto podría ser una tabla o una vista, por ejemplo...

Dunder init dentro del directorio de modelos para que las migraciones surtan efecto:

vim human_resource/models/__init__.py
from human_resource.models.hr import Person

Esto es necesario para que el directorio de modelos funcione como un archivo models.py.

(No) Migraciones:¡Mi Base de Datos, Mis Reglas!

¡Nosotros creamos la estructura de nuestra base de datos y ningún ORM debería hacerlo por nosotros!
¡Tenemos el poder!
¡Tenemos el poder!
¡Estamos al mando!

¡Nuestra base de datos, nuestras reglas! 😉

Simplemente modele su base de datos con sus propias manos y realice una migración falsa de Django.
Porque solo nosotros sabemos cómo se deben crear los objetos de la base de datos 😉

Realizar migraciones para la aplicación human_resource:

$ manage.py makemigrations human_resource

Migración falsa:

$ manage.py migrate --fake

Veamos la jerarquía de directorios de la aplicación:

$ tree human_resource/
human_resource/
├── admin.py
├── apps.py
├── __init__.py
├── migrations
│   ├── 0001_initial.py
│   ├── __init__.py
│   └── __pycache__
│       ├── 0001_initial.cpython-38.pyc
│       └── __init__.cpython-38.pyc
├── models
│   ├── hr.py
│   ├── __init__.py
│   └── __pycache__
│       ├── hr.cpython-38.pyc
│       └── __init__.cpython-38.pyc
├── __pycache__
│   ├── admin.cpython-38.pyc
│   └── __init__.cpython-38.pyc
├── tests.py
└── views.py

Concha de Django (Ipython):

$ manage.py shell
>>> from human_resource.models.hr import Person

>>> p = Person(name='Ludwig', surname='van Beethoven')                                                                         

>>> print(p)

Salida:

Ludwig van Beethoven
>>> p.save()   # Persist in database

Presiona <Ctrl> + D para salir!

Shell de base de datos (psql):

$ manage.py dbshell

Una consulta para verificar si los datos fueron insertados por Django:

>  SELECT id_, name, surname FROM ns_hr.tb_person;

Salida:

 id |  name  |    surname    
----+--------+---------------
  1 | Ludwig | van Beethoven

Conclusión

PostgreSQL es un RDBMS robusto y potente con muchas funciones, incluidos espacios de nombres para sus objetos.
Django es un excelente marco web que es muy robusto y también tiene muchas funciones.
Entonces, puede extrae lo mejor de ambos para lograr mejores resultados y para hacer esto, una de las formas es obtener una mejor organización.
Organizar los objetos de tu base de datos en espacios de nombres de acuerdo con sus funciones te traerá beneficios 😉