One place for hosting & domains

      Cómo instalar y configurar una pila LEMP usando Software Collections en CentOS 7


      El autor seleccionó la Apache Software Foundation para recibir una donación de $100 como parte del programa Write for DOnations.

      Introducción

      Una pila de software LEMP es un grupo de software de código abierto que se instala normalmente en conjunto para permitir que un servidor hospede sitios web dinámicos y aplicaciones web. Este término es realmente un acrónimo que representa el sistema operativo de Linux y el servidor web de ENginx (que sustituye al componente Apache de una pila LAMP). Los datos del sitio se almacenan en una base de datos de MySQL (utilizando MariaDB) y el contenido dinámico se procesa mediante PHP.

      Los componentes de pilas LEMP a veces se instalan usando el repositorio de EPEL de CentOS 7. Sin embargo, este repositorio contiene paquetes obsoletos. Por ejemplo, no puede instalar ninguna versión de PHP superior a la 5.4.16 desde EPEL, aunque no exista soporte para esta versión desde hace mucho tiempo. Para obtener las versiones más recientes del software, se recomienda que utilice Software Collections, también conocido como “SCLs”. Las SCL son recopilaciones de recursos para desarrolladores proporcionadas por RedHat que le permiten usar varias versiones de software en el mismo sistema sin afectar paquetes previamente instalados.

      En esta guía, instalará una pila LEMP en un servidor de CentOS 7. El sistema operativo CentOS se ocupa del componente Linux. Instalará el resto de los componentes usando el repositorio de Software Collections y luego podrá configurarlos para una página web simple.

      Requisitos previos

      Antes de iniciar este tutorial, debe configurar el servidor de CentOS 7 siguiendo la guía de configuración inicial del servidor de CentOS 7 e incluir un usuario sudo no root.

      Paso 1: Habilitación del repositorio de Software Collections

      Si desea obtener acceso a SCLs para CentOS, instale el archivo de versión de Linux Software Collections de CentOS:

      • sudo yum install centos-release-scl

      Consulte la lista de paquetes SCL disponibles usando el siguiente comando:

      • yum --disablerepo='*' --enablerepo='centos-sclo-rh' --enablerepo='centos-sclo-sclo' list available

      Para evitar conflictos en todo el sistema, los paquetes SCL se instalan en el directorio /opt/rh. Esto le permite, por ejemplo, instalar Python 3.5 en una máquina con CentOS 7 sin eliminar Python 2.7 ni interferir con su funcionamiento.

      Todos los archivos de configuración para paquetes de SCLs se almacenan en el directorio correspondiente dentro del directorio /etc/opt/rh/. Los paquetes de SCLs proporcionan scripts de shell que definen las variables de entorno necesarias para usar las aplicaciones incluidas. Por ejemplo, PATH, LD_LIBRARY_PATH y MANPATH. Estos scripts se almacenan en el sistema de archivos como /opt/rh/nombre del paquete/enable.

      Con esto, estará listo para comenzar a instalar los paquetes indicados en esta guía.

      Paso 2: Instalación del servidor web Nginx

      Para mostrar páginas web a los visitantes vamos a emplear Nginx, un servidor web moderno y eficiente.

      Instale Nginx usando el siguiente comando yum. Asegúrese de sustituir el valor resaltado por la versión de Nginx que desee instalar; el número más alto en el nombre del paquete corresponderá a la versión más reciente (112 en el momento en que se redactó este artículo):

      • sudo yum install rh-nginx112

      Una vez terminada la instalación, inicie el servicio Nginx:

      • sudo systemctl start rh-nginx112-nginx

      Confirme que Nginx esté en ejecución ingresando el comando systemctl status:

      • sudo systemctl status rh-nginx112-nginx

      Output

      ● rh-nginx112-nginx.service - The nginx HTTP and reverse proxy server Loaded: loaded (/usr/lib/systemd/system/rh-nginx112-nginx.service; disabled; vendor preset: disabled) Active: active (running) since Fri 2018-03-19 15:15:43 UTC; 1min 17s ago Main PID: 10556 (nginx) CGroup: /system.slice/rh-nginx112-nginx.service ├─10556 nginx: master process /opt/rh/rh-nginx112/root/usr/sbin/nginx ├─10557 nginx: worker process └─10558 nginx: worker process Mar 19 15:15:43 lemp-centos-222 systemd[1]: Starting The nginx HTTP and reverse proxy server... Mar 19 15:15:43 lemp-centos-222 nginx-scl-helper[10541]: nginx: the configuration file /etc/opt/rh/rh-nginx... ok Mar 19 15:15:43 lemp-centos-222 nginx-scl-helper[10541]: nginx: configuration file /etc/opt/rh/rh-nginx112/...ful Mar 19 15:15:43 lemp-centos-222 systemd[1]: Started The nginx HTTP and reverse proxy server. Hint: Some lines were ellipsized, use -l to show in full.

      En este momento, su servidor podría estar expuesto a accesos por parte de usuarios no autorizados. Para corregir esto, configure un firewall usando firewalld. Quizá necesite instalar primero firewalld. Puede hacerlo con el siguiente comando:

      • sudo yum install firewalld

      Luego, inicie el servicio firewalld:

      • sudo systemctl start firewalld

      A continuación, añada algunas reglas de firewall para permitir el acceso de SSH a su servidor y conexiones HTTP y HTTPS con Nginx:

      • sudo firewall-cmd --permanent --add-service=ssh
      • sudo firewall-cmd --zone=public --permanent --add-service=http
      • sudo firewall-cmd --zone=public --permanent --add-service=https

      Vuelva a cargar firewalld para implementar las nuevas reglas de firewall:

      • sudo firewall-cmd --reload

      Encontrará más información sobre firewalld en la sección Cómo configurar un firewall usando FirewallD en CentOS 7.

      Una vez agregadas estas nuevas reglas, podrá probar si el servidor se encuentra en ejecución accediendo al nombre de dominio o a la dirección IP pública de su servidor en su navegador web.

      Si no tiene un nombre de dominio para su servidor y no conoce la dirección IP pública de este, puede encontrarla escribiendo lo siguiente en su terminal:

      Escriba la dirección IP resultante en la barra de dirección de su navegador web. Con esto, deberá poder ver la página de inicio predeterminada de Nginx:

      http://server_domain_or_IP
      

      Página predeterminada de Nginx

      Si ve esta página, significa que instaló Nginx correctamente. Antes de continuar, habilite Nginx para que comience a funcionar en el inicio usando el siguiente comando:

      • sudo systemctl enable rh-nginx112-nginx

      El servidor Nginx ya está instalado. Ahora puede proceder a instalar el software de base de datos MariaDB.

      Paso 3: Instalación de MariaDB para gestionar datos de sitios

      Ahora que contamos con un servidor web, es el momento de instalar MariaDB, un reemplazo a medida de MySQL, para almacenar y administrar los datos de su sitio.

      Instale MariaDB con el comando que se muestra a continuación. Una vez más, reemplace el valor señalado por el número de versión que desee instalar; el número más alto corresponde a la versión más reciente disponible (102, en el momento en que se redactó este artículo):

      • sudo yum install rh-mariadb102

      Una vez que se complete la instalación, inicie el servicio MariaDB con el siguiente comando:

      • sudo systemctl start rh-mariadb102-mariadb

      Con esto, MariaDB quedará instalado y en funcionamiento. No obstante, faltará completar su configuración.

      Para proteger la instalación, MariaDB incorpora un script de seguridad que solicita modificar algunos ajustes no seguros predeterminados. Ejecute el script escribiendo lo siguiente:

      • source /opt/rh/rh-mariadb102/enable
      • mysql_secure_installation

      El mensaje solicitará su contraseña root actual. Puesto que acaba de instalar MySQL, es probable que no disponga de una. Podrá dejar el campo en blanco presionando ENTER. Luego se le preguntará si desea configurar una contraseña root. Introduzca Y y siga las instrucciones:

      . . .
      Enter current password for root (enter for none):
      OK, successfully used password, moving on...
      
      Setting the root password ensures that nobody can log into the MariaDB
      root user without the proper authorization.
      
      Set root password? [Y/n] Y
      New password: password
      Re-enter new password: password
      Password updated successfully!
      Reloading privilege tables..
       ... Success!
      . . .
      

      Para el resto de las preguntas, presione la tecla ENTER en cada mensaje para aceptar los valores predeterminados. Con esto, se eliminarán algunos usuarios anónimos y la base de datos de prueba, se deshabilitarán las credenciales de inicio de sesión remoto de root y se cargarán estas nuevas reglas para que MariaDB aplique de inmediato los cambios que realizamos.

      Lo último que se debe hacer aquí es habilitar MariaDB para que se ejecute en el inicio. Utilice el siguiente comando para hacerlo:

      • sudo systemctl enable rh-mariadb102-mariadb

      En este punto, su sistema de base de datos estará configurado y podrá proceder a configurar PHP en su servidor.

      Paso 4: Instalación y configuración de PHP para procesamiento

      Ya tiene instalados Nginx para sus páginas y MariaDB para el almacenamiento y la administración de sus datos. Sin embargo, aún le falta instalar una herramienta que pueda generar contenido dinámico. Es el momento de PHP.

      Dado que Nginx no contiene procesamiento PHP nativo como otros servidores web, deberá instalar php-fpm, que significa “administrador de proceso de fastCGI”. Más adelante, configurará Nginx para que transmita solicitudes PHP a este software para su procesamiento.

      Instale este módulo y también use un paquete helper que permitirá la comunicación de PHP con el backend de su base de datos. La instalación extraerá los archivos principales de PHP necesarios. Podrá ejecutarla escribiendo lo siguiente:

      • sudo yum install rh-php71-php-fpm rh-php71-php-mysqlnd

      De esta manera, sus componentes PHP quedarán instalados. Sin embargo, existe un ligero cambio de configuración que debería realizar para reforzar la seguridad de su configuración.

      Abra el archivo de configuración de php.ini principal con privilegios root:

      • sudo vi /etc/opt/rh/rh-php71/php.ini

      En este archivo, busque el parámetro que configura cgi.fix_pathinfo. Este se comentará con un punto y coma (;) y se fijará en “1” por defecto.

      Este ajuste es extremadamente inseguro porque indica a PHP que intente ejecutar el archivo más cercano que pueda encontrar si no se puede hallar el archivo PHP solicitado. Básicamente, esto permitiría a los usuarios realizar solicitudes PHP de una forma que haría posible la ejecución scripts que no deberían poder ejecutar.

      Cambie ambas condiciones eliminando los comentarios de la línea y fijando su valor en “0”, como se muestra aquí:

      71/php.ini’>/etc/opt/rh/rh-php71/php.ini

      cgi.fix_pathinfo=0
      

      Guarde y cierre el archivo cuando termine (presione ESC, ingrese :wq y luego presione Enter).

      A continuación, abra el archivo de configuración de php-fpm www.conf:

      • sudo vi /etc/opt/rh/rh-php71/php-fpm.d/www.conf

      Por defecto, este archivo está configurado para usarse con el servidor Apache. Dado que su servidor tiene Nginx instalado, encuentre las líneas que configuran user y group y cambie sus valores de “apache” a “nginx”:

      71/php-fpm.d/www.conf’>/etc/opt/rh/rh-php71/php-fpm.d/www.conf

      user = nginx
      group = nginx
      

      Luego, guarde y cierre el archivo.

      A continuación, inicie su procesador PHP escribiendo lo siguiente:

      • sudo systemctl start rh-php71-php-fpm

      Luego habilite php-fpm para que se ejecute en el inicio:

      • sudo systemctl enable rh-php71-php-fpm

      Con esto, PHP quedará correctamente instalado en su servidor. Sin embargo, deberá configurarlo para complementarse con el otro software que instaló, de modo que su servidor funcione correctamente con el contenido de su sitio.

      Paso 5: Configuración de Nginx para usar el procesador PHP

      En este punto, ya tendrá instalados todos los componentes requeridos de una pila LEMP. En el nivel de la configuración, el único cambio que aún debe hacer es indicarle a Nginx que utilice su procesador PHP para contenido dinámico.

      Este cambio de configuración se realiza en el nivel de bloque del servidor (los bloques de servidor son similares a los hosts virtuales de Apache). Abra el archivo predeterminado de configuración de bloques del servidor Nginx escribiendo lo siguiente:

      • sudo vi /etc/opt/rh/rh-nginx112/nginx/nginx.conf

      Elimine los comentarios del bloque de ubicación ~ .php$ (el segmento del archivo que se ocupa de las solicitudes PHP, que se encuentra dentro del bloque del server) y su contenido borrando los símbolos de numeral (#) del principio de cada línea. También debe actualizar la opción fastcgi_param a SCRIPT FILENAME $document_root$fastcgi_script_name. Esto informa a PHP sobre la ubicación de la raíz del documento donde puede encontrar archivos para procesar.

      Una vez realizados los cambios necesarios, el bloque del server tendrá este aspecto:

      /etc/nginx/sites-available/default

      ...
      server {
          listen       80 default_server;
          listen       [::]:80 default_server;
          server_name  _;
          root         /opt/rh/rh-nginx112/root/usr/share/nginx/html;
      
          # Load configuration files for the default server block.
          include      /etc/opt/rh/rh-nginx112/nginx/default.d/*.conf;
      
          location / {
          }
      
          error_page 404 /404.html;
          location = /40x.html {
          }
      
          error_page 500 502 503 504  /50x.html;
          location = /50x.html {
          }
      
          # proxy the PHP scripts to Apache listening on 127.0.0.1:80
          #
          #location ~ .php$ {
          #    proxy_pass   http://127.0.0.1;
          #}
      
          # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
          #
          location ~ .php$ {
              root           html;
              fastcgi_pass   127.0.0.1:9000;
              fastcgi_index  index.php;
              fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
              include        fastcgi_params;
          }
      
          # deny access to .htaccess files, if Apache's document root
          # concurs with nginx's one
          #
          #location ~ /.ht {
          #    deny  all;
          #}
      }
      ...
      

      Cuando realice los cambios, podrá guardar el archivo y salir del editor.

      A continuación, pruebe someta a prueba su archivo de configuración en busca de errores de sintaxis ejecutando los siguientes comandos:

      • source /opt/rh/rh-nginx112/enable
      • sudo nginx -t

      Si se notifica algún error, vuelva a revisar su archivo antes de continuar.

      Una vez que su archivo de configuración sea válido, vuelva a cargar Nginx para implementar los cambios que realizó:

      • sudo systemctl reload rh-nginx112-nginx

      Ahora que Nginx, PHP y MariaDB se han instalado y configurado, solo queda confirmar que la configuración de pila LEMP pueda facilitar correctamente el contenido a los visitantes de su sitio.

      Paso 6: Creación de un archivo PHP para probar la configuración

      Su pila LEMP ahora está completamente configurada y puede probarla para validar que Nginx pueda proporcionar archivos .php a su procesador PHP correctamente. Esto se realiza creando un archivo PHP de prueba en la raíz de nuestro documento.

      Abra un nuevo archivo llamado info.php dentro de la raíz del documento:

      • sudo vi /opt/rh/rh-nginx112/root/usr/share/nginx/html/info.php

      Añada al archivo la línea que se muestra a continuación. En ella se incluye código PHP válido que mostrará información sobre su servidor:

      112/root/usr/share/nginx/html/info.php’>/opt/rh/rh-nginx112/root/usr/share/nginx/html/info.php

      <?php phpinfo(); ?>
      

      Cuando termine, guarde y cierre el archivo. Luego, visite esta página en su navegador web usando el nombre de dominio o la dirección IP pública de su servidor seguidos de /info.php:

      http://server_domain_or_IP/info.php
      

      Verá una página web generada por PHP con información sobre su servidor:

      Información de página de PHP

      Si ve una página con este aspecto, significa que habrá configurado el procesamiento de PHP con Nginx de forma satisfactoria.

      Tras verificar que Nginx represente la página de forma correcta, la mejor opción será eliminar el archivo que creó porque puede dar indicios sobre su configuración que podrían ser útiles para que usuarios no autorizados intenten ingresar. Siempre puede regenerar este archivo si lo necesita más adelante.

      Elimine el archivo escribiendo lo siguiente:

      • sudo rm /opt/rh/rh-nginx112/root/usr/share/nginx/html/info.php

      Con esto, confirmará que todos los componentes de la pila LEMP se instalaron y configuraron correctamente en su servidor.

      Conclusión

      Ahora contará con una pila LEMP totalmente segura en su servidor CentOS 7. Esto le proporcionará una base muy flexible para proporcionar contenido web a sus visitantes.

      Las SCLs también se utilizan para instalar varias versiones de software y alternar entre ellas. Puede ver la lista de todas las colecciones instaladas en el sistema ejecutando lo siguiente:

      Si le interesa, podrá encontrar más información sobre Software Collections en el sitio oficial.



      Source link

      Cómo configurar una aplicación de Node.js para producción en Ubuntu 18.04


      Introducción

      Node.js es un entorno de tiempo de ejecución de código abierto basado en JavaScript que use usa para crear aplicaciones de redes. La plataforma funciona en Linux, macOS, FreeBSD y Windows. Aunque puede ejecutar aplicaciones de Node.js en la línea de comandos, en este tutorial se pondrá el foco en su ejecución como un servicio. Esto significa que se reiniciarán durante el inicio o ante una falla y que pueden usarse de forma segura en un entorno de producción.

      A través de este tutorial, configurará un entorno de Node.js listo para producción en un servidor único de Ubuntu 18.04. Este servidor ejecutará una aplicación de Node.js administrada por PM2 y brindará a los usuarios acceso seguro a la aplicación mediante un proxy inverso de Nginx. El servidor de Nginx brindará HTTPS usando un certificado gratuito proporcionado por Let’s Encrypt.

      Requisitos previos

      Para esta guía, se supone cuenta con lo siguiente:

      Una vez que cumpla con los requisitos previos, dispondrá de un servidor en el que funcionará la página de marcador de posición predeterminada de su dominio en https://example.com/.

      Paso 1: Instalar Node.js

      Comencemos instalando la versión más reciente de LTS de Node.js con los archivos de paquete de NodeSource.

      Primero, instale el PPA de NodeSource para poder acceder a su contenido. Asegúrese de estar posicionado en su directorio de inicio y use curl para recuperar la secuencia de instalación para los archivos de Node.js 8.x:

      • cd ~
      • curl -sL https://deb.nodesource.com/setup_8.x -o nodesource_setup.sh

      Puede inspeccionar el contenido de esta secuencia de comandos con nano o su editor de texto preferido:

      Cuando termine de inspeccionar la secuencia, ejecútela con sudo:

      • sudo bash nodesource_setup.sh

      El PPA se agregará a su configuración y su caché de paquetes locales se actualizará de forma automática. Después de ejecutar la secuencia de comandos de configuración de Nodesource, puede instalar el paquete de Node.js.

      Para comprobar la versión de Node.js que instaló después de estos pasos iniciales, escriba lo siguiente:

      Output

      v8.11.3

      Nota: Cuando la instalación se realiza a partir del PPA de NodeSource, el ejecutable de Node.js se llama nodejs, en lugar de node.

      El paquete nodejs contiene el binario nodejs y npm, un administrador de paquetes para módulos de Node, por lo que no tendrá que instalar npm por separado.

      npm usa un archivo de configuración en su directorio de inicio para hacer un seguimiento de las actualizaciones. Se creará la primera vez que ejecute npm. Ejecute este comando para verificar que npm esté instalado y crear el archivo de configuración:

      Output

      5.6.0

      Para que algunos paquetes de npm funcionen (por ejemplo, aquellos para los cuales se seba compilar código de una fuente), deberá instalar el paquete build-essential:

      • sudo apt install build-essential

      Ahora dispondrá de las herramientas necesarias para trabajar con paquetes npm para los que se deba compilar código de la fuente.

      Ahora que está instalado el tiempo de ejecución de Node.js, escribiremos una la aplicación de Node.js.

      Paso 2: Crear una aplicación de Node.js

      Escribiremos una aplicación Hello World que responda “Hello World” a cualquier solicitud de HTTP. Con esta aplicación de ejemplo, podrá a configurar Node.js. Puede reemplazarla por su propia aplicación; solo debe asegurarse de modificar su aplicación para escuchar en las direcciones IP y los puertos apropiados.

      Primero, crearemos una aplicación de ejemplo llamada hello.js:

      Inserte el siguiente código en el archivo:

      ~/hello.js

      const http = require('http');
      
      const hostname = 'localhost';
      const port = 3000;
      
      const server = http.createServer((req, res) => {
        res.statusCode = 200;
        res.setHeader('Content-Type', 'text/plain');
        res.end('Hello World!n');
      });
      
      server.listen(port, hostname, () => {
        console.log(`Server running at http://${hostname}:${port}/`);
      });
      

      Guarde el archivo y salga del editor.

      La aplicación Node.js escucha la dirección (localhost) y el puerto (3000) especificados, y responde “Hello World!” con un código de éxito HTTP 200. Debido a que escucharemos en localhost, los clientes remotos no podrán conectarse a nuestra aplicación.

      Para probar su aplicación, escriba lo siguiente:

      Verá el siguiente resultado:

      Output

      Server running at http://localhost:3000/

      Nota: Ejecutar una aplicación de Node.js de esta manera bloqueará comandos adicionales hasta que esta se detenga pulsando CTRL+C.

      Para probar la aplicación, abra otra sesión de terminal en su servidor y conéctese a localhost con curl:

      • curl http://localhost:3000

      Si ve el siguiente resultado, significa que la aplicación funciona de forma adecuada y escucha en las direcciones y los puertos correctos.

      Output

      Hello World!

      Si no ve el resultado esperado, asegúrese de que su aplicación de Node.js funcione y esté configurada para escuchar en la dirección y el puerto apropiados.

      Una vez que esté seguro de que funciona, deténgala (si aún no lo hizo) presionando CTRL+C.

      Paso 3: Instalar PM2

      A continuación, instalaremos PM2, un administrador de procesos para aplicaciones de Node.js. PM2 permite implementar demonios en aplicaciones para que puedan funcionar en segundo plano como servicios.

      Use npm para instalar la última versión de PM2 en su servidor:

      • sudo npm install pm2@latest -g

      La opción -g indica a npm que instale el módulo de forma global, de modo que esté disponible en todo el sistema.

      Primero, usaremos el comando pm2 start para ejecutar su aplicación, hello.js, en segundo plano:

      Con esto, también se agrega su aplicación a la lista de procesos de PM2, que se emite cada vez que se inicia una aplicación:

      Output

      [PM2] Spawning PM2 daemon with pm2_home=/home/sammy/.pm2 [PM2] PM2 Successfully daemonized [PM2] Starting /home/sammy/hello.js in fork_mode (1 instance) [PM2] Done. ┌──────────┬────┬──────┬──────┬────────┬─────────┬────────┬─────┬───────────┬───────┬──────────┐ │ App name │ id │ mode │ pid │ status │ restart │ uptime │ cpu │ mem │ user │ watching │ ├──────────┼────┼──────┼──────┼────────┼─────────┼────────┼─────┼───────────┼───────┼──────────┤ │ hello │ 0 │ fork │ 1338 │ online │ 0 │ 0s │ 0% │ 23.0 MB │ sammy │ disabled │ └──────────┴────┴──────┴──────┴────────┴─────────┴────────┴─────┴───────────┴───────┴──────────┘ Use `pm2 show <id|name>` to get more details about an app

      Como puede ver, PM2 asigna automáticamente un App name (según el nombre del archivo, sin la extensión .js) y un id de PM2. También conversa otra información, como el PID de los procesos, su estado actual y su uso de memoria.

      Las aplicaciones que se ejecutan en PM2 se reiniciarán de forma automática si la aplicación se bloquea o se detiene, pero podemos dar un paso adicional para que se cargue en el inicio del sistema usando el subcomando startup. Este subcomando genera y configura una secuencia de comandos de inicio para iniciar PM2 y sus procesos administrados al iniciarse el servidor:

      En la última línea del resultado obtenido se incluirá un comando que se ejecutará con privilegios de superusuario a fin de configurar PM2 para que se cargue en el inicio:

      Output

      [PM2] Init System found: systemd [PM2] To setup the Startup Script, copy/paste the following command: sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u sammy --hp /home/sammy

      Ejecute el comando del resultado, con su nombre de usuario en lugar de sammy:

      • sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u sammy --hp /home/sammy

      Como paso adicional, podemos guardar la lista de procesos de PM2 y los entornos correspondientes:

      De esta manera, habrá creado una unidad de systemd que ejecuta pm2 para su usuario en el inicio. Esta instancia de pm2, a su vez, ejecuta hello.js.

      Inicie el servicio con systemctl:

      • sudo systemctl start pm2-sammy

      Compruebe el estado de la unidad de systemd:

      • systemctl status pm2-sammy

      Para hallar una descripción detallada de systemd, consulte Aspectos básicos de systemd: trabajar con servicios, unidades y el componente de diario.

      Además de los subcomandos que ya abarcamos, PM2 proporciona muchos que le permiten administrar o buscar información sobre sus aplicaciones.

      Detenga una aplicación con este comando (especifique App name o id de PM2):

      Reinicie una aplicación:

      • pm2 restart app_name_or_id

      Liste las aplicaciones actualmente administradas por PM2:

      Obtenga información sobre una aplicación específica usando su App name:

      El monitor de procesos de PM2 se puede extraer con el subcomando monit. Con esto, se muestra el estado y el uso de CPU y memoria de la aplicación:

      Tenga en cuenta que si se ejecuta pm2 sin argumentos, también se mostrará una página de ayuda con uso de ejemplos.

      Ahora que su aplicación de Node.js funciona y PM2 la administra, configuraremos el proxy inverso.

      Paso 4: Configurar Nginx como servidor proxy inverso

      Su aplicación está en ejecución y escucha en localhost, pero necesita configurar una alternativa para que sus usuarios accedan a ella. Configuraremos el servidor web de Nginx como un proxy inverso para este propósito.

      En el tutorial de los requisitos previos, configuró sus ajustes de Nginx en el archivo /etc/nginx/sites-available/example.com. Abra este archivo para editarlo:

      • sudo nano /etc/nginx/sites-available/example.com

      En el bloque server, debería disponer de un bloque location /. Sustituya el contenido de dicho bloque por la siguiente configuración. Si su aplicación está configurada para escuchar en un puerto diferente, actualice la parte resaltada con el número de puerto correcto:

      /etc/nginx/sites-available/example.com

      server {
      ...
          location / {
              proxy_pass http://localhost:3000;
              proxy_http_version 1.1;
              proxy_set_header Upgrade $http_upgrade;
              proxy_set_header Connection 'upgrade';
              proxy_set_header Host $host;
              proxy_cache_bypass $http_upgrade;
          }
      ...
      }
      

      Con esto, se configurará el servidor para que responda las solicitudes en su root. Suponiendo que nuestro servidor esté disponible en example.com, al acceder a https://example.com/ a través de un navegador web se enviaría la solicitud a hello.js y la escucha se realizaría en el puerto 3000 en localhost.

      Puede agregar bloques location al mismo bloque de servidor para proporcionar acceso a otras aplicaciones en el mismo servidor. Por ejemplo, si también contaba con otra aplicación Node.js en el puerto 3001, podría agregar este bloque de ubicación para permitir el acceso a él a través de https://example.com/app2:

      /etc/nginx/sites-available/example.com — Optional

      server {
      ...
          location /app2 {
              proxy_pass http://localhost:3001;
              proxy_http_version 1.1;
              proxy_set_header Upgrade $http_upgrade;
              proxy_set_header Connection 'upgrade';
              proxy_set_header Host $host;
              proxy_cache_bypass $http_upgrade;
          }
      ...
      }
      

      Una vez que termine de agregar los bloques de ubicación a sus aplicaciones, guarde el archivo y cierre el editor.

      Asegúrese de no haber introducido errores de sintaxis escribiendo lo siguiente:

      Reinicie Nginx:

      • sudo systemctl restart nginx

      Suponiendo que su aplicación Node.js está en ejecución, y que su aplicación y las configuraciones de Nginx son correctas, ahora debería poder acceder a su aplicación a través del proxy inverso de Nginx. Pruébelo accediendo a la URL de su servidor (su dirección IP pública o nombre de dominio).

      Conclusión

      ¡Felicitaciones! De esta manera, habrá logrado hacer funcionar su aplicación de Node.js detrás de un proxy inverso de Nginx en un servidor de Ubuntu 18.04. Esta configuración de proxy inverso es suficientemente flexible como para proporcionar a sus usuarios acceso a otras aplicaciones o a contenido web estático que desee compartir.



      Source link

      Cómo crear una aplicación web moderna para gestionar la información de clientes con Django y React on Ubuntu 18.04


      El autor seleccionó Open Sourcing Mental Illness Ltd para recibir una donación como parte del programa Write for Donations.

      Introducción

      Las personas utilizan diferentes tipos de dispositivos para conectarse a internet y navegar por la Web. Debido a esto, las aplicaciones deben ser accesibles desde varios lugares. Para los sitios web tradicionales, tener una IU receptiva suele ser suficiente, pero las aplicaciones más complejas suelen requerir el uso de otras técnicas y arquitecturas. Entre ellas se contempla tener aplicaciones back-end y front-end REST independientes que puedan implementarse como aplicaciones web para el cliente, aplicaciones web progresivas (PWA) o aplicaciones móviles nativas.

      Algunas herramientas que puede utilizar al crear aplicaciones más complejas incluyen:

      • React, un marco de trabajo de JavaScript que permite a los desarrolladores crear frontends web y nativos para sus backend de API REST.
      • Django, una estructura web de Python gratuita y de código abierto que sigue el patrón de arquitectura del software de modelo vista controlador (MVC).
      • Django REST framework, un conjunto de herramientas potentes y flexibles para el desarrollo de REST APIs en Django.

      En este tutorial, usted creará una aplicación web moderna con un backend REST API independiente y un frontend utilizando React, Django y Django REST Framework. Al utilizar React con Django, podrá beneficiarse de los últimos avances en el desarrollo de JavaScript y front-end. En lugar de crear una aplicación de Django que utilice un motor de plantillas incorporado, usted utilizará React como biblioteca de IU, aprovechando su enfoque virtual de Modelo de objetos de documentos (DOM), enfoque declarativo y componentes que rápidamente reproduzcan cambios en los datos.

      La aplicación web que usted creará almacena registros sobre clientes en una base de datos, y puede utilizarlo como punto de partida para una aplicación CRM. Cuando haya terminado, podrá crear, leer, actualizar y borrar registros utilizando una interfaz React de estilo Bootstrap 4.

      Requisitos previos

      Para completar este tutorial, necesitará lo siguiente:

      Paso 1: Creación de un entorno virtual de Python e instalación de dependencias

      En este paso, crearemos un entorno virtual e instalaremos las dependencias necesarias para nuestra aplicación, entre ellas, Django, Django REST framework y django-cors-headers.

      Nuestra aplicación utilizará dos servidores de desarrollo distintos para Django y React. Se ejecutarán en diferentes puertos y funcionarán como dos dominios separados. Debido a esto, debemos permitir el intercambio de recursos de origen cruzado (CORS) para enviar solicitudes HTTP desde React a Django sin que el navegador pueda bloquearlos.

      Navegue a su directorio principal y cree un entorno virtual utilizando el módulo venv Python 3:

      • cd ~
      • python3 -m venv ./env

      Active el entorno virtual creado utilizando “source:

      A continuación, instale las dependencias del proyecto con pip. Entre ellas se incluyen:

      • Django: el marco de trabajo web para el proyecto.
      • Django REST framework: Una aplicación externa que desarrolla REST APIs con Django.
      • django-cors-headers: un paquete que habilita CORS.

      Instalar la estructura de Django:

      • pip install django djangorestframework django-cors-headers

      Con las dependencias del proyecto instaladas, puede crear el proyecto Django y el frontend de React.

      Paso 2: Creación del proyecto Django

      En este paso, generaremos el proyecto Django utilizando las siguientes comandos y utilidades:

      • **django-admin startproject project-name**:django-admin es una utilidad de línea de comandos que se utiliza para realizar tareas con Django. El comando startproject crea un nuevo proyecto Django.

      • **python manage.py startapp myapp**: manage.py es un script de utilidad que se añade automáticamente a cada proyecto de Django, y que ejecuta varias tareas administrativas, como crear nuevas aplicaciones, migrar la base de datos y servir de forma local el proyecto de Django. Su comando startapp crea una aplicación de Django dentro del proyecto Django. En Django, el término aplicación describe un paquete de Python que proporciona algunas características en un proyecto.

      Para comenzar, cree el proyecto Django con django-admin startproject. Hemos de nombrar a nuestro proyecto djangoreactproject

      • django-admin startproject djangoreactproject

      Antes de seguir, observemos la estructura del directorio de nuestro proyecto Django utilizando el comando tree.

      Nota: tree es un comando útil para visualizar estructuras de archivos y directorio desde la línea de comandos. Puede instalarlo con el comando que se indica a continuación:

      • sudo apt-get install tree

      Para utilizarlo, use el comando cd en el directorio que desee y escriba tree o proporcione la ruta al punto de partida con tree /home/sammy/sammys-project.

      Navegue a la carpeta djangoreactproject dentro del root de su proyecto y ejecute el comando tree:

      • cd ~/djangoreactproject
      • tree

      Verá lo siguiente:

      Output

      ├── djangoreactproject │ ├── __init__.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py └── manage.py

      La carpeta ~/djangoreactproject es la root del proyecto. Dentro de esta carpeta, hay varios archivos que serán importantes para su labor:

      • manage.py: el script de utilidad que realiza diversas tareas administrativas.
      • settings.py: el archivo de configuración principal para el proyecto de Django, donde puede modificar la configuración del proyecto. Estos ajustes incluyen variables como INSTALLED_APPS, una lista de strings que designan las aplicaciones habilitadas para su proyecto. La documentación de Django contiene más información sobre los ajustes disponibles.
      • urls.py: este archivo contiene una lista de patrones de URL y vistas relacionadas. Cada patrón traza una conexión entre una URL y la función que se debe solicitar para esa URL. Para más información sobre URL y vistas, consulte nuestro tutorial sobre Cómo crear vistas de Django.

      Nuestro primer paso en el trabajo con el proyecto será configurar los paquetes que instalamos en el paso anterior, incluidos Django REST framework y el paquete Django CORS, al añadirlos a settings.py. Abra el archivo con nano o su editor favorito:

      • nano ~/djangoreactproject/djangoreactproject/settings.py

      Navegue al ajuste INSTALLED_APPS y añada las aplicaciones rest_framework y corsheaders en la parte inferior de la lista:

      ~/djangoreactproject/djangoreactproject/settings.py

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

      A continuación, añada el middleware corsheaders.middleware.CorsMiddleware desde el paquete CORS instalado previamente al ajuste MIDDLEWARE. Este ajuste es una lista de middlewares, una clase de Python que contiene código que se procesa cada vez que su aplicación web gestiona una solicitud o respuesta:

      ~/djangoreactproject/djangoreactproject/settings.py

      ...
      
      MIDDLEWARE = [
      ...
      'django.contrib.messages.middleware.MessageMiddleware',
      'django.middleware.clickjacking.XFrameOptionsMiddleware',
      'corsheaders.middleware.CorsMiddleware'
      ]
      

      A continuación, puede habilitar CORS. El ajuste CORS_ORIGIN_ALLOW_ALL especifica si desea habilitar CORS para todos los dominios o no, y CORS_ORIGIN_WHITELIST es una tupla de Python que contiene URL permitidas. En nuestro caso, dado que el servidor de desarrollo de React se ejecutará en http://localhost:3000, añadiremos nuevos ajustes CORS_ORIGIN_ALLOW_ALL = False y CORS_ORIGIN_WHITELIST('localhost:3000',) a nuestro archivo settings.py. Añade estos ajustes en cualquier parte del archivo:

      ~/djangoreactproject/djangoreactproject/settings.py

      
      ...
      CORS_ORIGIN_ALLOW_ALL = False
      
      CORS_ORIGIN_WHITELIST = (
             'localhost:3000',
      )
      ...
      

      Puede encontrar más opciones de configuración en la documentación de django-cors-headers.

      Guarde el archivo y salga del editor cuando haya terminado.

      Aún en el directorio ~/djangoreactproject, cree una nueva aplicación de Django llamada customers:

      • python manage.py startapp customers

      Contendrá los modelos y las vistas para gestionar clientes. Los modelos definen los campos y los comportamientos de nuestros datos de aplicaciones, mientras que las vistas permiten a nuestras aplicaciones gestionar adecuadamente las solicitudes web y devolver las respuestas requeridas.

      A continuación, añada esta aplicación a la lista de aplicaciones instaladas en el archivo settings.py de su proyecto para que Django la reconozca como parte del proyecto. Abra settings.py de nuevo:

      • nano ~/djangoreactproject/djangoreactproject/settings.py

      Añada la aplicación customers:

      ~/djangoreactproject/djangoreactproject/settings.py

      ...
      INSTALLED_APPS = [
          ...
          'rest_framework',
          'corsheaders',
          'customers'
      ]
      ...
      

      A continuación, *migre *la base de datos e inicie el servidor de desarrollo local. Las migraciones son la manera en que Django propaga los cambios que usted realiza a sus modelos en su esquema de base de datos. Estos cambios pueden ser, por ejemplo, añadir un campo o eliminar un modelo. Para obtener más información sobre modelos y migraciones, consulte Cómo crear modelos de Django.

      Migre la base de datos:

      Inicie el servidor de desarrollo local:

      • python manage.py runserver

      El resultado debe ser similar a lo siguiente:

      Output

      Performing system checks... System check identified no issues (0 silenced). October 22, 2018 - 15:14:50 Django version 2.1.2, using settings 'djangoreactproject.settings' Starting development server at http://127.0.0.1:8000/ Quit the server with CONTROL-C.

      Su aplicación web se ejecuta desde http://127.0.0.1:8000. Si se dirige a esta dirección en su navegador web, debería ver la siguiente página:

      Página de demostración de Django

      En este momento, deje la aplicación en ejecución y abra una nueva terminal para seguir desarrollando el proyecto.

      Paso 3: creación del frontend de React

      En esta sección, vamos a crear la aplicación frontend de nuestro proyecto utilizando React.

      React tiene una herramienta oficial que le permite generar proyectos de React de forma rápida sin tener que configurar Webpack directamente. Webpack es un empaquetador de módulos que se utiliza para agrupar recursos web, como código de JavaScript, CSS e imágenes. Normalmente, para poder utilizar Webpack, debe establecer varias opciones de configuración, pero, gracias a la herramienta create-react-app, no tiene que lidiar con Webpack directamente hasta que decida que necesita más control. Para ejecutar create-react-app puede utilizar npx, una herramienta que ejecuta binarios de paquetes npm.

      En su segunda terminal, asegúrese de que estar en el directorio de su proyecto:

      Cree un proyecto de React llamado frontend utilizando create-react-app y npx

      • npx create-react-app frontend

      A continuación, navegue al interior de su aplicación de React e inicie el servidor de desarrollo:

      • cd ~/djangoreactproject/frontend
      • npm start

      Su aplicación se ejecutará desde http://localhost:3000/:

      Página de demostración de React

      Deje el servidor de desarrollo de React en ejecución y abra otra ventana de terminal para proceder.

      Para ver la estructura del directorio de todo el proyecto en este punto, navegue a la carpeta root y ejecute el comando tree de nuevo:

      • cd ~/djangoreactproject
      • tree

      Verá una estructura como esta:

      Output

      ├── customers │ ├── admin.py │ ├── apps.py │ ├── __init__.py │ ├── migrations │ │ └── __init__.py │ ├── models.py │ ├── tests.py │ └── views.py ├── djangoreactproject │ ├── __init__.py │ ├── __pycache__ │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── frontend │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ └── manifest.json │ ├── README.md │ ├── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── index.css │ │ ├── index.js │ │ ├── logo.svg │ │ └── registerServiceWorker.js │ └── yarn.lock └── manage.py

      Nuestra aplicación utilizará Bootstrap 4 para dar forma a la interfaz de React, por lo que lo incluiremos en el archivo frontend/src/App.css que gestiona nuestros ajustes de CSS. Abra el archivo:

      • nano ~/djangoreactproject/frontend/src/App.css

      Añada la importación que se indica a continuación al comienzo del archivo. Puede eliminar el contenido existente del archivo, pero no es necesario hacerlo:

      ~/djangoreactproject/frontend/src/App.css

      @import  'https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css';
      

      Aquí, @import es una instrucción de CSS que se utiliza para importar reglas de estilo de otras hojas de estilo.

      Ahora que hemos creado las aplicaciones back-end y front-end, vamos a crear el modelo de cliente y algunos datos de prueba.

      Paso 4: creación del modelo de cliente y datos iniciales

      Tras crear la aplicación de Django y el frontend de React, nuestro próximo paso será crear el modelo de cliente, que representa la tabla de base de datos que almacenará información sobre los clientes. No necesita nada de SQL, dado que el mapeo objeto-relacional (ORM) de Django se encargará de las operaciones de la base de datos al asignar las clases y variables de Python a tablas y columnas de SQL. De esta manera, el ORM de Django extrae las interacciones de SQL con la base de datos a través de una interfaz de Python.

      Active su entorno virtual de nuevo:

      • cd ~
      • source env/bin/activate

      Diríjase al directorio customers y abra models.py, un archivo de Python que contiene los modelos de su aplicación:

      • cd ~/djangoreactproject/customers/
      • nano models.py

      El archivo incluirá el siguiente contenido:

      ~/djangoreactproject/customers/models.py

      from django.db import models
      # Create your models here.
      

      La API del modelo de cliente ya está importada en el archivo gracias a la instrucción import from django.db import models. Ahora, añadirá la clase Customer, que extiende models.Model. Cada modelo de Django es una clase de Python que extiende django.db.models.Model.

      El modelo Customer tendrá estos campos de base de datos:

      • first_name: el nombre del cliente.
      • last_name: el apellido del cliente.
      • email: la dirección de correo electrónico del cliente.
      • phone: el número de teléfono del cliente.
      • address: la dirección del cliente.
      • description: la descripción del cliente.
      • createdAt: la fecha en que se añade el cliente.

      También añadiremos la función __str__(), que define la manera en que se mostrará el modelo. En nuestro caso, será con el nombre del cliente. Para obtener más información sobre la creación de clases y la definición de objetos, consulte Cómo crear clases y definir objetos en Python 3.

      Añada el código siguiente al archivo:

      ~/djangoreactproject/customers/models.py

      from django.db import models
      
      class Customer(models.Model):
          first_name = models.CharField("First name", max_length=255)
          last_name = models.CharField("Last name", max_length=255)
          email = models.EmailField()
          phone = models.CharField(max_length=20)
          address =  models.TextField(blank=True, null=True)
          description = models.TextField(blank=True, null=True)
          createdAt = models.DateTimeField("Created At", auto_now_add=True)
      
          def __str__(self):
              return self.first_name
      

      A continuación, migre la base de datos para crear las tablas de la base de datos. El comando makemigrations crea los archivos de migración en los que se añadirán los cambios al modelo, y migrate aplica los cambios en los archivos de migraciones a la base de datos.

      Vuelva a navegar a la carpeta root del proyecto:

      Ejecute lo siguiente para crear los archivos de migración:

      • python manage.py makemigrations

      Verá algo similar a esto:

      Output

      customers/migrations/0001_initial.py - Create model Customer

      Aplique estos cambios en la base de datos:

      Verá un resultado que indica que la migración se realizó correctamente:

      Output

      Operations to perform: Apply all migrations: admin, auth, contenttypes, customers, sessions Running migrations: Applying customers.0001_initial... OK

      A continuación, utilizará un archivo de migración de datos para crear datos iniciales de clientes. Un archivo de migración de datos es una migración que añade o altera datos en la base de datos. Cree un archivo de migración de datos vacío para la aplicación customers:

      • python manage.py makemigrations --empty --name customers customers

      Visualizará la siguiente confirmación con el nombre de su archivo de migración:

      Output

      Migrations for 'customers': customers/migrations/0002_customers.py

      Tenga en cuenta que el nombre de su archivo de migración es 0002_customers.py.

      A continuación, navegue al interior de la carpeta de migraciones de la aplicación customers:

      • cd ~/djangoreactproject/customers/migrations

      Abra el archivo de migración creado:

      Este es el contenido inicial del archivo:

      ~/djangoreactproject/customers/migrations/0002_customers.py

      from django.db import migrations
      
      class Migration(migrations.Migration):
          dependencies = [
              ('customers', '0001_initial'),
          ]
          operations = [
          ]        
      

      La instrucción import importa la API de migraciones, una API de Django para crear migraciones, desde django.db, un paquete incorporado que contiene clases para trabajar con bases de datos.

      La clase Migration es una clase de Python que describe las operaciones que se ejecutan al migrar bases de datos. Esta clase extiende migrations.Migration y tiene dos listas:

      • dependencies: contiene las migraciones dependientes.
      • operations: contiene las operaciones que se ejecutarán al aplicar la migración.

      A continuación, añada un método para crear datos de clientes de prueba. Añada el método que se indica a continuación antes de la definición de la clase Migration:

      ~/djangoreactproject/customers/migrations/0002_customers.py

      ...
      def create_data(apps, schema_editor):
          Customer = apps.get_model('customers', 'Customer')
          Customer(first_name="Customer 001", last_name="Customer 001", email="[email protected]", phone="00000000", address="Customer 000 Address", description= "Customer 001 description").save()
      
      ...
      

      En este método, estamos tomando la clase Customer de nuestra aplicación customers y creando un cliente de prueba para insertar en la base de datos.

      Para obtener la clase Customer, que permitirá la creación de nuevos clientes, usamos el método get_model() del objeto apps. El objeto apps representa el registro de aplicaciones instaladas y sus modelos de base de datos.

      El objeto apps se pasará del método RunPython() cuando lo usemos para ejecutar create_data(). Añada el método migrations.RunPython() a la lista operations vacía:

      ~/djangoreactproject/customers/migrations/0002_customers.py

      
      ...
          operations = [
              migrations.RunPython(create_data),
          ]  
      

      RunPython() es parte de la API de Migrations que le permite ejecutar código de Python personalizado en una migración. Nuestra lista operations especifica que este método se ejecutará al aplicar la migración.

      Este es el archivo completo:

      ~/djangoreactproject/customers/migrations/0002_customers.py

      from django.db import migrations
      
      def create_data(apps, schema_editor):
          Customer = apps.get_model('customers', 'Customer')
          Customer(first_name="Customer 001", last_name="Customer 001", email="[email protected]", phone="00000000", address="Customer 000 Address", description= "Customer 001 description").save()
      
      class Migration(migrations.Migration):
          dependencies = [
              ('customers', '0001_initial'),
          ]
          operations = [
              migrations.RunPython(create_data),
          ]        
      

      Para obtener más información sobre migraciones de datos, consulte la documentación sobre migraciones de datos en Django

      Para migrar su base de datos, primero, vuelva a navegar a la carpeta root de su proyecto:

      Migre su base de datos para crear los datos de prueba:

      Visualizará un resultado que confirma la migración:

      Output

      Operations to perform: Apply all migrations: admin, auth, contenttypes, customers, sessions Running migrations: Applying customers.0002_customers... OK

      Para obtener más detalles sobre este proceso, consulte Cómo crear modelos de Django.

      Con el modelo Customer y los datos de prueba creados, podemos pasar a la creación de la API REST.

      Paso 5: creación de la API REST

      En este paso, vamos a crear la API REST utilizando Django REST Framework. Crearemos varias vistas de API diferentes. Una vista de API es una función que gestiona una solicitud o llamada de API, mientras que un punto de final de API es una URL única que representa un punto de contacto con el sistema REST. Por ejemplo, cuando el usuario envía una solicitud de GET a un punto final de API, Django llama a la función o vista de API correspondiente para gestionar la solicitud y devolver los resultados posibles.

      También utilizaremos serializadores. Un serializador de Django REST Framework permite que instancias de modelos complejas y QuerySets se conviertan en formato JSON para el consumo de API. La clase de serialización también puede funcionar en dirección inversa, proporcionando mecanismos para el análisis y la deserialización de datos en QuerySets y modelos de Django.

      Nuestros puntos finales de API incluirán lo siguiente:

      • api/customers: este punto final se utiliza para crear clientes y devuelve conjuntos paginados de clientes.
      • api/clusters/<pk>: este punto final se utiliza para obtener, actualizar y eliminar clientes individuales por clave primaria o id.

      También crearemos URL en el archivo urls.py del proyecto para los puntos finales correspondientes (es decir, api/clusters y api/clusters/<pk>).

      Comencemos por crear la clase de serialización para nuestro modelo Customer.

      Incorporación de la clase de serialización

      Es necesario crear una clase de serialización para nuestro modelo Customer para transformar las instancias de cliente y QuerySets hacia y desde JSON. Para crear la clase de serialización, primero, cree un archivo serializer.py dentro de la aplicación customers:

      • cd ~/djangoreactproject/customers/
      • nano serializers.py

      Añada el código siguiente para importar el modelo Customer y la API de serializadores:

      ~/djangoreactproject/customers/serializers.py

      from rest_framework import serializers
      from .models import Customer
      

      A continuación, cree una clase de serialización que extienda serializers.ModelSerializer y especifique los campos que han de serializarse:

      ~/djangoreactproject/customers/serializers.py

      
      ...
      class CustomerSerializer(serializers.ModelSerializer):
      
          class Meta:
              model = Customer 
              fields = ('pk','first_name', 'last_name', 'email', 'phone','address','description')
      

      La clase Meta especifica qué campos y modelos se serializarán: pk, first_name, last_name, email, phone, address, description.

      Este es el contenido completo del archivo:

      ~/djangoreactproject/customers/serializers.py

      from rest_framework import serializers
      from .models import Customer
      
      class CustomerSerializer(serializers.ModelSerializer):
      
          class Meta:
              model = Customer 
              fields = ('pk','first_name', 'last_name', 'email', 'phone','address','description')
      

      Ahora que hemos creado nuestra clase de serialización, podemos añadir las vistas de API.

      Incorporación de vistas de API

      En esta sección, crearemos las vistas de API para nuestra aplicación, a las que llamará Django cuando el usuario visite el punto final correspondiente a la función de vista.

      Abra ~/djangoreactproject/customers/views.py:

      • nano ~/djangoreactproject/customers/views.py

      Elimine lo que haya allí y añada las siguientes importaciones:

      ~/djangoreactproject/customers/views.py

      from rest_framework.response import Response
      from rest_framework.decorators import api_view
      from rest_framework import status
      
      from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
      from .models import Customer 
      from .serializers import *
      

      Estamos importando el serializador que creamos, junto con el modelo Customer y las API de Django y Django REST Framework.

      A continuación, añada la vista para el procesamiento de POST y las solicitudes GET HTTP:

      ~/djangoreactproject/customers/views.py

      ...
      
      @api_view(['GET', 'POST'])
      def customers_list(request):
          """
       List  customers, or create a new customer.
       """
          if request.method == 'GET':
              data = []
              nextPage = 1
              previousPage = 1
              customers = Customer.objects.all()
              page = request.GET.get('page', 1)
              paginator = Paginator(customers, 10)
              try:
                  data = paginator.page(page)
              except PageNotAnInteger:
                  data = paginator.page(1)
              except EmptyPage:
                  data = paginator.page(paginator.num_pages)
      
              serializer = CustomerSerializer(data,context={'request': request} ,many=True)
              if data.has_next():
                  nextPage = data.next_page_number()
              if data.has_previous():
                  previousPage = data.previous_page_number()
      
              return Response({'data': serializer.data , 'count': paginator.count, 'numpages' : paginator.num_pages, 'nextlink': '/api/customers/?page=' + str(nextPage), 'prevlink': '/api/customers/?page=' + str(previousPage)})
      
          elif request.method == 'POST':
              serializer = CustomerSerializer(data=request.data)
              if serializer.is_valid():
                  serializer.save()
                  return Response(serializer.data, status=status.HTTP_201_CREATED)
              return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
      

      Primero, usamos el decorador @api_view(['GET', 'POST']) para crear una vista de API que pueda aceptar solicitudes GET y POST. Un decorador es una función que toma otra función y la extiende de forma dinámica.

      En el cuerpo del método, usamos la variable request.method para verificar el método HTTP actual y ejecutar la lógica correspondiente dependiendo del tipo de solicitud:

      • Si se trata de una solicitud GET, el método pagina los datos utilizando Django Paginator y devuelve a la primera página de datos después de la serialización, el conteo de clientes disponibles, el número de páginas disponibles y los enlaces a las páginas anteriores y siguientes. Paginator es una clase integrada de Django que pagina una lista de datos en páginas y proporciona métodos para acceder a los elementos de cada una de ellas.
      • Si se trata de una solicitud POST, el método serializa los datos de clientes recibidos y, luego, llama al método save() del objeto serializador. A continuación, devuelve un objeto de Response, una instancia de HttpResponse, con el código de estado 201. Cada vista que crea se encarga de regresar un objeto HttpResponse. El método save() guarda los datos serializados en la base de datos.

      Para obtener más información sobre HttpResponse y las vistas, consulte esta discusión con respecto a la creación de funciones de vista.

      Ahora, añada la vista de API que se encargará del procesamiento de las solicitudes GET, PUT y DELETE para obtener, actualizar y eliminar clientes por pk (clave primaria):

      ~/djangoreactproject/customers/views.py

      
      ...
      @api_view(['GET', 'PUT', 'DELETE'])
      def customers_detail(request, pk):
       """
       Retrieve, update or delete a customer by id/pk.
       """
          try:
              customer = Customer.objects.get(pk=pk)
          except Customer.DoesNotExist:
              return Response(status=status.HTTP_404_NOT_FOUND)
      
          if request.method == 'GET':
              serializer = CustomerSerializer(customer,context={'request': request})
              return Response(serializer.data)
      
          elif request.method == 'PUT':
              serializer = CustomerSerializer(customer, data=request.data,context={'request': request})
              if serializer.is_valid():
                  serializer.save()
                  return Response(serializer.data)
              return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
      
          elif request.method == 'DELETE':
              customer.delete()
              return Response(status=status.HTTP_204_NO_CONTENT)
      

      El método está representado con @api_view(['GET', 'PUT', 'DELETE']) para indicar que se trata de una vista de API que puede aceptar las solicitudes GET, PUT y DELETE.

      La marca de revisión en el campo request.method verifica el método de solicitud y, dependiendo de su valor, llama a la lógica correcta:

      • Si se trata de una solicitud GET, se serializan los datos de clientes y se envían utilizando un objeto Response.
      • Si se trata de una solicitud PUT, el método crea un serializador para nuevos datos de cliente y, luego, llama al método save() del objeto serializador creado. Por último, envía un objeto Response con el cliente actualizado.
      • Si se trata de una solicitud DELETE, el método llama al método delete() del objeto de cliente para eliminarlo y, a continuación, devuelve un objeto Response sin datos.

      El archivo completo se ve de este modo:

      ~/djangoreactproject/customers/views.py

      from rest_framework.response import Response
      from rest_framework.decorators import api_view
      from rest_framework import status
      
      from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
      from .models import Customer 
      from .serializers import *
      
      
      @api_view(['GET', 'POST'])
      def customers_list(request):
          """
       List  customers, or create a new customer.
       """
          if request.method == 'GET':
              data = []
              nextPage = 1
              previousPage = 1
              customers = Customer.objects.all()
              page = request.GET.get('page', 1)
              paginator = Paginator(customers, 5)
              try:
                  data = paginator.page(page)
              except PageNotAnInteger:
                  data = paginator.page(1)
              except EmptyPage:
                  data = paginator.page(paginator.num_pages)
      
              serializer = CustomerSerializer(data,context={'request': request} ,many=True)
              if data.has_next():
                  nextPage = data.next_page_number()
              if data.has_previous():
                  previousPage = data.previous_page_number()
      
              return Response({'data': serializer.data , 'count': paginator.count, 'numpages' : paginator.num_pages, 'nextlink': '/api/customers/?page=' + str(nextPage), 'prevlink': '/api/customers/?page=' + str(previousPage)})
      
          elif request.method == 'POST':
              serializer = CustomerSerializer(data=request.data)
              if serializer.is_valid():
                  serializer.save()
                  return Response(serializer.data, status=status.HTTP_201_CREATED)
              return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
      
      @api_view(['GET', 'PUT', 'DELETE'])
      def customers_detail(request, pk):
          """
       Retrieve, update or delete a customer by id/pk.
       """
          try:
              customer = Customer.objects.get(pk=pk)
          except Customer.DoesNotExist:
              return Response(status=status.HTTP_404_NOT_FOUND)
      
          if request.method == 'GET':
              serializer = CustomerSerializer(customer,context={'request': request})
              return Response(serializer.data)
      
          elif request.method == 'PUT':
              serializer = CustomerSerializer(customer, data=request.data,context={'request': request})
              if serializer.is_valid():
                  serializer.save()
                  return Response(serializer.data)
              return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
      
          elif request.method == 'DELETE':
              customer.delete()
              return Response(status=status.HTTP_204_NO_CONTENT)
      

      Ahora, podemos pasar a crear nuestros puntos finales.

      Incorporación de puntos finales de API

      Ahora, crearemos los puntos finales de API: api/customers/ para consultar y crear clientes, y api/customers/ <pk> para obtener, actualizar o eliminar clientes individuales por su pk.

      Abra ~/djangoreactproject/djangoreactproject/urls.py:

      • nano ~/djangoreactproject/djangoreactproject/urls.py

      Deje lo que haya allí, pero añada la importación a las vistas customers en la parte superior del archivo:

      ~/djangoreactproject/djangoreactproject/urls.py

      from django.contrib import admin
      from django.urls import path
      from customers import views
      from django.conf.urls import url
      

      A continuación, añada las URL de api/customers/ y api/customers/<pk> a la lista urlpatterns que contiene las URL de la aplicación:

      ~/djangoreactproject/djangoreactproject/urls.py

      ...
      
      urlpatterns = [
          path('admin/', admin.site.urls),
          url(r'^api/customers/$', views.customers_list),
          url(r'^api/customers/(?P<pk>[0-9]+)$', views.customers_detail),
      ]
      

      Con nuestros puntos finales REST creados, veamos cómo podemos consumirlos.

      Paso 6: consumo de API REST con Axios.

      En este paso, instalaremos Axios, el cliente HTTP que utilizaremos para realizar llamadas de API. También crearemos una clase para consumir los puntos finales de API que hemos creado.

      Primero, desactive su entorno virtual:

      A continuación, navegue a su carpeta frontend:

      • cd ~/djangoreactproject/frontend

      Instale axios desde npm utilizando:

      La opción --save añade la dependencia axios al archivo package.json de su aplicación.

      A continuación, cree un archivo de JavaScript denominado CustomersService.js, que contendrá el código para llamar a las API REST. Realizaremos esto dentro de la carpeta src, donde residirá el código de la aplicación de nuestro proyecto:

      • cd src
      • nano CustomersService.js

      Añada el código siguiente, que contiene métodos para conectarse a la API REST de Django:

      ~/djangoreactproject/frontend/src/CustomersService.js

      import axios from 'axios';
      const API_URL = 'http://localhost:8000';
      
      export default class CustomersService{
      
          constructor(){}
      
      
          getCustomers() {
              const url = `${API_URL}/api/customers/`;
              return axios.get(url).then(response => response.data);
          }  
          getCustomersByURL(link){
              const url = `${API_URL}${link}`;
              return axios.get(url).then(response => response.data);
          }
          getCustomer(pk) {
              const url = `${API_URL}/api/customers/${pk}`;
              return axios.get(url).then(response => response.data);
          }
          deleteCustomer(customer){
              const url = `${API_URL}/api/customers/${customer.pk}`;
              return axios.delete(url);
          }
          createCustomer(customer){
              const url = `${API_URL}/api/customers/`;
              return axios.post(url,customer);
          }
          updateCustomer(customer){
              const url = `${API_URL}/api/customers/${customer.pk}`;
              return axios.put(url,customer);
          }
      }
      

      La clase CustomersService llamará a los siguientes métodos de Axios:

      • getCustomers(): obtiene la primera página de clientes.
      • getCustomersByURL(): obtiene clientes por URL. Esto permite obtener las siguientes páginas de clientes al pasar enlaces como /api/customers/?page=2.
      • get Customer(): obtiene un cliente por clave primaria.
      • createCustomer(): crea un cliente.
      • updateCustomer(): actualiza un cliente.
      • deleteCustomer(): elimina un cliente.

      Ahora, podemos mostrar los datos de nuestra API en nuestra IU de React al crear un componente CustomersList.

      Paso 7: visualización de datos de la API en la aplicación de React

      En este paso, crearemos el componente CustomersList de React. Un componente de React representa una parte de la IU; también le permite dividir la IU en piezas independientes y reutilizables.

      Comience por crear CustomersList.js en frontend/src:

      • nano ~/djangoreactproject/frontend/src/CustomersList.js

      Inicie la importación de React y Component para crear un componente de React:

      ~/djangoreactproject/frontend/src/CustomersList.js

      import  React, { Component } from  'react';
      

      A continuación, importe e instancie el módulo CustomersService que creó en el paso anterior, el cual proporciona métodos que interactúan con el backend de API REST:

      ~/djangoreactproject/frontend/src/CustomersList.js

      
      ...
      import  CustomersService  from  './CustomersService';
      
      const  customersService  =  new  CustomersService();
      

      A continuación, cree un componente CustomersList que extienda Component para llamar a la API REST. Un componente de React debería extender o crear una subclase de la clase Component. Para obtener más información acerca de las clases E6 y herencia, consulte nuestro tutorial sobre Comprensión de las clases de JavaScript.

      Añada el siguiente código para crear un componente de React que extienda react.Component:

      ~/djangoreactproject/frontend/src/CustomersList.js

      
      ...
      class  CustomersList  extends  Component {
      
          constructor(props) {
              super(props);
              this.state  = {
                  customers: [],
                  nextPageURL:  ''
              };
              this.nextPage  =  this.nextPage.bind(this);
              this.handleDelete  =  this.handleDelete.bind(this);
          }
      }
      export  default  CustomersList;
      

      Dentro del constructor, estamos inicializando el objeto state. Este almacena las variables de estado de nuestro componente utilizando una matriz customers vacía. Esta matriz almacenará clientes y una nextPageURL que contendrá la URL de la siguiente página que se obtendrá del back-end de la API. También procedemos a vincular los métodos nextPage() y handleDelete() a this para que sean accesibles desde el código HTML.

      A continuación, añada el método componentDidMount() y una llamada a getCustomers() dentro de la clase CustomersList, antes de la llave de cierre.

      El método componentDidMount() es un método de ciclo de vida del componente que se llama al crear el componente y se inserta en el DOM. getCustomers() llama al objeto Customers Service para obtener la primera página de datos y el enlace de la siguiente página del backend de Django:

      ~/djangoreactproject/frontend/src/CustomersList.js

      
      ...
      componentDidMount() {
          var  self  =  this;
          customersService.getCustomers().then(function (result) {
              self.setState({ customers:  result.data, nextPageURL:  result.nextlink})
          });
      }
      

      Ahora, añada el método handleDelete(), que gestiona la eliminación de un cliente, debajo de componentDidMount():

      ~/djangoreactproject/frontend/src/CustomersList.js

      
      ...
      handleDelete(e,pk){
          var  self  =  this;
          customersService.deleteCustomer({pk :  pk}).then(()=>{
              var  newArr  =  self.state.customers.filter(function(obj) {
                  return  obj.pk  !==  pk;
              });
              self.setState({customers:  newArr})
          });
      }
      

      El método handleDelete() llama al método deleteCustomer() para eliminar un cliente utilizando su pk (clave primaria). Si la operación se realiza correctamente, la matriz customers se filtra por el cliente eliminado.

      A continuación, añada un método nextPage() para obtener los datos de la siguiente página y actualice el enlace de la página siguiente:

      ~/djangoreactproject/frontend/src/CustomersList.js

      
      ...
      nextPage(){
          var  self  =  this;
          customersService.getCustomersByURL(this.state.nextPageURL).then((result) => {
              self.setState({ customers:  result.data, nextPageURL:  result.nextlink})
          });
      }
      

      El método nextPage() llama a un método getCustomersByURL(), que obtiene la URL de la página siguiente del objeto de estado, this.state.nextPageURL, y actualiza la matriz customers con los datos devueltos.

      Por último, añada el método render() del componente, que produce una tabla de clientes del estado de componente:

      ~/djangoreactproject/frontend/src/CustomersList.js

      
      ...
      render() {
      
          return (
          <div  className="customers--list">
              <table  className="table">
                  <thead  key="thead">
                  <tr>
                      <th>#</th>
                      <th>First Name</th>
                      <th>Last Name</th>
                      <th>Phone</th>
                      <th>Email</th>
                      <th>Address</th>
                      <th>Description</th>
                      <th>Actions</th>
                  </tr>
                  </thead>
                  <tbody>
                      {this.state.customers.map( c  =>
                      <tr  key={c.pk}>
                          <td>{c.pk}  </td>
                          <td>{c.first_name}</td>
                          <td>{c.last_name}</td>
                          <td>{c.phone}</td>
                          <td>{c.email}</td>
                          <td>{c.address}</td>
                          <td>{c.description}</td>
                          <td>
                          <button  onClick={(e)=>  this.handleDelete(e,c.pk) }> Delete</button>
                          <a  href={"/customer/" + c.pk}> Update</a>
                          </td>
                      </tr>)}
                  </tbody>
              </table>
              <button  className="btn btn-primary"  onClick=  {  this.nextPage  }>Next</button>
          </div>
          );
      }
      

      Este es el contenido completo del archivo:

      ~/djangoreactproject/frontend/src/CustomersList.js

      import  React, { Component } from  'react';
      import  CustomersService  from  './CustomersService';
      
      const  customersService  =  new  CustomersService();
      
      class  CustomersList  extends  Component {
      
      constructor(props) {
          super(props);
          this.state  = {
              customers: [],
              nextPageURL:  ''
          };
          this.nextPage  =  this.nextPage.bind(this);
          this.handleDelete  =  this.handleDelete.bind(this);
      }
      
      componentDidMount() {
          var  self  =  this;
          customersService.getCustomers().then(function (result) {
              console.log(result);
              self.setState({ customers:  result.data, nextPageURL:  result.nextlink})
          });
      }
      handleDelete(e,pk){
          var  self  =  this;
          customersService.deleteCustomer({pk :  pk}).then(()=>{
              var  newArr  =  self.state.customers.filter(function(obj) {
                  return  obj.pk  !==  pk;
              });
      
              self.setState({customers:  newArr})
          });
      }
      
      nextPage(){
          var  self  =  this;
          console.log(this.state.nextPageURL);        
          customersService.getCustomersByURL(this.state.nextPageURL).then((result) => {
              self.setState({ customers:  result.data, nextPageURL:  result.nextlink})
          });
      }
      render() {
      
          return (
              <div  className="customers--list">
                  <table  className="table">
                  <thead  key="thead">
                  <tr>
                      <th>#</th>
                      <th>First Name</th>
                      <th>Last Name</th>
                      <th>Phone</th>
                      <th>Email</th>
                      <th>Address</th>
                      <th>Description</th>
                      <th>Actions</th>
                  </tr>
                  </thead>
                  <tbody>
                  {this.state.customers.map( c  =>
                      <tr  key={c.pk}>
                      <td>{c.pk}  </td>
                      <td>{c.first_name}</td>
                      <td>{c.last_name}</td>
                      <td>{c.phone}</td>
                      <td>{c.email}</td>
                      <td>{c.address}</td>
                      <td>{c.description}</td>
                      <td>
                      <button  onClick={(e)=>  this.handleDelete(e,c.pk) }> Delete</button>
                      <a  href={"/customer/" + c.pk}> Update</a>
                      </td>
                  </tr>)}
                  </tbody>
                  </table>
                  <button  className="btn btn-primary"  onClick=  {  this.nextPage  }>Next</button>
              </div>
              );
        }
      }
      export  default  CustomersList;
      

      Ahora que hemos creado el componente CustomersList para visualizar la lista de clientes, podemos añadir el componente que gestiona la creación y la actualización de clientes.

      Paso 8: incorporación del componente de React de creación y actualización de clientes

      En este paso, crearemos el componente CustomerCreateUpdate, que se encargará de crear y actualizar clientes. Lo hará al proporcionar una forma que los usuarios puedan utilizar para ingresar datos sobre un cliente nuevo o actualizar una entrada existente.

      En frontend/src, cree un archivo CustomerCreateUpdate.js:

      • nano ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js

      Añada el siguiente código para crear un componente de React, importando React y Component:

      ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js

      import  React, { Component } from  'react';
      

      A continuación, también podemos importar e instanciar la clase CustomersService que creamos en el paso anterior, que proporciona métodos que interactúan con el backend de API REST:

      ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js

      ...
      import  CustomersService  from  './CustomersService';
      
      const  customersService  =  new  CustomersService();
      

      Luego, cree un componente CustomerCreateUpdate que extienda Component para crear y actualizar clientes:

      ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js

      
      ...
      class  CustomerCreateUpdate  extends  Component {
      
          constructor(props) {
              super(props);
          }
      
      }
      export default CustomerCreateUpdate;
      

      Dentro de la definición de clase, añada el método render() del componente, que produce un formulario HTML que toma información sobre el cliente:

      ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js

      
      ...
      render() {
              return (
                <form onSubmit={this.handleSubmit}>
                <div className="form-group">
                  <label>
                    First Name:</label>
                    <input className="form-control" type="text" ref='firstName' />
      
                  <label>
                    Last Name:</label>
                    <input className="form-control" type="text" ref='lastName'/>
      
                  <label>
                    Phone:</label>
                    <input className="form-control" type="text" ref='phone' />
      
                  <label>
                    Email:</label>
                    <input className="form-control" type="text" ref='email' />
      
                  <label>
                    Address:</label>
                    <input className="form-control" type="text" ref='address' />
      
                  <label>
                    Description:</label>
                    <textarea className="form-control" ref='description' ></textarea>
      
      
                  <input className="btn btn-primary" type="submit" value="Submit" />
                  </div>
                </form>
              );
        }
      

      Para cada elemento de entrada del formulario, el método añade una propiedad ref para acceder al valor del elemento del formulario y establecerlo.

      A continuación, por encima del método render(), defina un método handleSubmit(event) de modo que tenga la funcionalidad correcta cuando un usuario haga clic en el botón de enviar:

      ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js

      
      ...
      handleSubmit(event) {
          const { match: { params } } =  this.props;
          if(params  &&  params.pk){
              this.handleUpdate(params.pk);
          }
          else
          {
              this.handleCreate();
          }
          event.preventDefault();
      }
      
      ...
      

      El método handleSubmit(event) gestiona el envío del formulario y, dependiendo de la ruta, llama al método handleUpdate(pk) para actualizar el cliente con la pk correcta, o el método handleCreate() para crear un nuevo cliente. Procederemos a definir estos métodos en breve.

      De nuevo en el constructor del componente, vincule el método handleSubmit() recientemente añadido a this para poder acceder a él en su formulario:

      ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js

      ...
      class CustomerCreateUpdate extends Component {
      
      constructor(props) {
          super(props);
          this.handleSubmit = this.handleSubmit.bind(this);
      }
      ...
      

      A continuación, defina el método handleCreate() para crear un cliente a partir de los datos del formulario. Encima del método handleSubmit(event), añada el siguiente código:

      ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js

      
      ...
      handleCreate(){
          customersService.createCustomer(
              {
              "first_name":  this.refs.firstName.value,
              "last_name":  this.refs.lastName.value,
              "email":  this.refs.email.value,
              "phone":  this.refs.phone.value,
              "address":  this.refs.address.value,
              "description":  this.refs.description.value
              }).then((result)=>{
                      alert("Customer created!");
              }).catch(()=>{
                      alert('There was an error! Please re-check your form.');
              });
      }
      
      ...
      

      El método handleCreate() se utilizará para crear un cliente a partir de los datos ingresados. Llama al método CustomersService.createCustomer() correspondiente que provoca que la API real llame al backend para crear un cliente.

      A continuación, por debajo del método handleCreate(), defina el método handleUpdate(pk) para implementar actualizaciones:

      ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js

      
      ...
      handleUpdate(pk){
      customersService.updateCustomer(
          {
          "pk":  pk,
          "first_name":  this.refs.firstName.value,
          "last_name":  this.refs.lastName.value,
          "email":  this.refs.email.value,
          "phone":  this.refs.phone.value,
          "address":  this.refs.address.value,
          "description":  this.refs.description.value
          }
          ).then((result)=>{
      
              alert("Customer updated!");
          }).catch(()=>{
              alert('There was an error! Please re-check your form.');
          });
      }
      

      El método updateCustomer() actualizará un cliente por pk, utilizando la nueva información del formulario de información de clientes. Llama al método customersService.updateCustomer().

      A continuación, añada un método componentDidMount(). Si el usuario visita una ruta customer/:pk, queremos que el formulario se complete con información relacionada con el cliente utilizando la clave primaria de la URL. Para ello, podemos añadir el método getCustomer(pk) una vez que el componente se monte en el evento de ciclo de vida de componentDidMount(). Añada el siguiente código por debajo del constructor del componente para añadir este método:

      ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js

      
      ...
      componentDidMount(){
          const { match: { params } } =  this.props;
          if(params  &&  params.pk)
          {
              customersService.getCustomer(params.pk).then((c)=>{
                  this.refs.firstName.value  =  c.first_name;
                  this.refs.lastName.value  =  c.last_name;
                  this.refs.email.value  =  c.email;
                  this.refs.phone.value  =  c.phone;
                  this.refs.address.value  =  c.address;
                  this.refs.description.value  =  c.description;
              })
          }
      }
      

      Este es el contenido completo del archivo:

      ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js

      import React, { Component } from 'react';
      import CustomersService from './CustomersService';
      
      const customersService = new CustomersService();
      
      class CustomerCreateUpdate extends Component {
          constructor(props) {
              super(props);
      
              this.handleSubmit = this.handleSubmit.bind(this);
            }
      
            componentDidMount(){
              const { match: { params } } = this.props;
              if(params && params.pk)
              {
                customersService.getCustomer(params.pk).then((c)=>{
                  this.refs.firstName.value = c.first_name;
                  this.refs.lastName.value = c.last_name;
                  this.refs.email.value = c.email;
                  this.refs.phone.value = c.phone;
                  this.refs.address.value = c.address;
                  this.refs.description.value = c.description;
                })
              }
            }
      
            handleCreate(){
              customersService.createCustomer(
                {
                  "first_name": this.refs.firstName.value,
                  "last_name": this.refs.lastName.value,
                  "email": this.refs.email.value,
                  "phone": this.refs.phone.value,
                  "address": this.refs.address.value,
                  "description": this.refs.description.value
              }          
              ).then((result)=>{
                alert("Customer created!");
              }).catch(()=>{
                alert('There was an error! Please re-check your form.');
              });
            }
            handleUpdate(pk){
              customersService.updateCustomer(
                {
                  "pk": pk,
                  "first_name": this.refs.firstName.value,
                  "last_name": this.refs.lastName.value,
                  "email": this.refs.email.value,
                  "phone": this.refs.phone.value,
                  "address": this.refs.address.value,
                  "description": this.refs.description.value
              }          
              ).then((result)=>{
                console.log(result);
                alert("Customer updated!");
              }).catch(()=>{
                alert('There was an error! Please re-check your form.');
              });
            }
            handleSubmit(event) {
              const { match: { params } } = this.props;
      
              if(params && params.pk){
                this.handleUpdate(params.pk);
              }
              else
              {
                this.handleCreate();
              }
      
              event.preventDefault();
            }
      
            render() {
              return (
                <form onSubmit={this.handleSubmit}>
                <div className="form-group">
                  <label>
                    First Name:</label>
                    <input className="form-control" type="text" ref='firstName' />
      
                  <label>
                    Last Name:</label>
                    <input className="form-control" type="text" ref='lastName'/>
      
                  <label>
                    Phone:</label>
                    <input className="form-control" type="text" ref='phone' />
      
                  <label>
                    Email:</label>
                    <input className="form-control" type="text" ref='email' />
      
                  <label>
                    Address:</label>
                    <input className="form-control" type="text" ref='address' />
      
                  <label>
                    Description:</label>
                    <textarea className="form-control" ref='description' ></textarea>
      
      
                  <input className="btn btn-primary" type="submit" value="Submit" />
                  </div>
                </form>
              );
            }  
      }
      
      export default CustomerCreateUpdate;
      

      Con el componente CustomerCreateUpdate creado, podemos actualizar el componente principal App para añadir enlaces a los diferentes componentes que hemos creado.

      Paso 9: actualización del componente principal App

      En esta sección, actualizaremos el componente App de nuestra aplicación para crear enlaces a los componentes que hemos creado en los pasos anteriores.

      Desde la carpeta frontend, ejecute el siguiente comando para instalar React Router, que le permite añadir enrutamiento y navegación entre varios componentes de React:

      • cd ~/djangoreactproject/frontend
      • npm install --save react-router-dom

      A continuación, abra ~/djangoreactproject/frontend/src/App.js:

      • nano ~/djangoreactproject/frontend/src/App.js

      Elimine todo lo que haya allí y añada el siguiente código para importar las clases necesarias para incorporar enrutamiento. Estas incluyen BrowserRouter, que crea un componente Router, y Route, que crea un componente de ruta:

      ~/djangoreactproject/frontend/src/App.js

      import  React, { Component } from  'react';
      import { BrowserRouter } from  'react-router-dom'
      import { Route, Link } from  'react-router-dom'
      import  CustomersList  from  './CustomersList'
      import  CustomerCreateUpdate  from  './CustomerCreateUpdate'
      import  './App.css';
      

      BrowserRoutermantiene la IU sincronizada con la URL utilizando la ](https://developer.mozilla.org/en-US/docs/Web/API/History_API)API de historial HTML5[.

      A continuación, cree un diseño base que proporcione el componente básico que envolverá el componente BrowserRouter:

      ~/djangoreactproject/frontend/src/App.js

      ...
      
      const  BaseLayout  = () => (
      <div  className="container-fluid">
          <nav  className="navbar navbar-expand-lg navbar-light bg-light">
              <a  className="navbar-brand"  href="https://www.digitalocean.com/#">Django React Demo</a>
              <button  className="navbar-toggler"  type="button"  data-toggle="collapse"  data-target="#navbarNavAltMarkup"  aria-controls="navbarNavAltMarkup"  aria-expanded="false"  aria-label="Toggle navigation">
              <span  className="navbar-toggler-icon"></span>
          </button>
          <div  className="collapse navbar-collapse"  id="navbarNavAltMarkup">
              <div  className="navbar-nav">
                  <a  className="nav-item nav-link"  href="/">CUSTOMERS</a>
                  <a  className="nav-item nav-link"  href="http://www.digitalocean.com/customer">CREATE CUSTOMER</a>
              </div>
          </div>
          </nav>
          <div  className="content">
              <Route  path="/"  exact  component={CustomersList}  />
              <Route  path="/customer/:pk"  component={CustomerCreateUpdate}  />
              <Route  path="/customer/"  exact  component={CustomerCreateUpdate}  />
          </div>
      </div>
      )
      

      Utilizamos el componente Route para definir las rutas de nuestra aplicación; el componente que el enrutador debe cargar cuando se encuentra una coincidencia. Cada ruta requiere un path que especifique la ruta que se debe seguir y un component que indique el componente que se debe cargar. La propiedad exact le indica al enrutador que siga la trayectoria exacta.

      Por último, cree el componente App, el componente root o de nivel superior de nuestra aplicación de React:

      ~/djangoreactproject/frontend/src/App.js

      ...
      
      class  App  extends  Component {
      
      render() {
          return (
          <BrowserRouter>
              <BaseLayout/>
          </BrowserRouter>
          );
      }
      }
      export  default  App;
      

      Hemos envuelto el componente BaseLayout con el componente BrowserRouter, dado que nuestra aplicación está diseñada para ejecutarse en un navegador.

      El archivo completo se ve de este modo:

      ~/djangoreactproject/frontend/src/App.js

      import React, { Component } from 'react';
      import { BrowserRouter } from 'react-router-dom'
      import { Route, Link } from 'react-router-dom'
      
      import  CustomersList from './CustomersList'
      import  CustomerCreateUpdate  from './CustomerCreateUpdate'
      import './App.css';
      
      const BaseLayout = () => (
        <div className="container-fluid">
      <nav className="navbar navbar-expand-lg navbar-light bg-light">
        <a className="navbar-brand" href="https://www.digitalocean.com/#">Django React Demo</a>
        <button className="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
          <span className="navbar-toggler-icon"></span>
        </button>
        <div className="collapse navbar-collapse" id="navbarNavAltMarkup">
          <div className="navbar-nav">
            <a className="nav-item nav-link" href="/">CUSTOMERS</a>
            <a className="nav-item nav-link" href="http://www.digitalocean.com/customer">CREATE CUSTOMER</a>
      
          </div>
        </div>
      </nav>  
      
          <div className="content">
            <Route path="/" exact component={CustomersList} />
            <Route path="/customer/:pk"  component={CustomerCreateUpdate} />
            <Route path="/customer/" exact component={CustomerCreateUpdate} />
      
          </div>
      
        </div>
      )
      
      class App extends Component {
        render() {
          return (
            <BrowserRouter>
              <BaseLayout/>
            </BrowserRouter>
          );
        }
      }
      
      export default App;
      

      Ahora que añadimos enrutamiento a nuestra aplicación, estamos listos para probarla. Navegue a http://localhost:3000. Debería ver la primera página de la aplicación:

      Página de inicio de la aplicación

      Con la implementación de esta aplicación, ahora, cuenta con la base para una aplicación de CRM.

      Conclusión

      En este tutorial, usted creó una aplicación de prueba utilizando Django y React. Utilizó Django REST framework para crear la API REST, Axios para consumir la API y Bootstrap 4 para dar estilo a su CSS. Puede encontrar el código fuente de este proyecto en este repositorio de GitHub.

      En la configuración de este tutorial, se utilizaron aplicaciones de front-end y back-end. Para obtener un enfoque diferente de la integración de React con Django, consulte este tutorial y este otro tutorial.

      Para obtener más información sobre la creación de aplicaciones con Django, puede seguir la serie de desarrollo de Django. También puede consultar la documentación oficial de Django.



      Source link