User Tools

Site Tools


proyecto:armar_la_aplicacion_inicial

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
proyecto:armar_la_aplicacion_inicial [2025/06/23 16:46] – ahoganproyecto:armar_la_aplicacion_inicial [2026/11/11 00:23] (current) – Armar la Aplicación: correcciones para Debian 13 (PHP 8.4, Django 6 en venv, Tomcat 10) y servlet-test.zip actualizado semorale
Line 3: Line 3:
 ===== Objetivo ===== ===== Objetivo =====
  
-La idea de la aplicación es tener una interfaz HTML donde el usuario puede ingresar algo (como en un "textbox" por ejemplo), y dada esta entrada, la aplicación crea una consulta SQL, ejecuta la consulta sobre la base de datos, y despliega los resultados en HTML para el usuario. +La idea de la aplicación es tener una interfaz HTML donde se puede ingresar algo (como en un "textbox" por ejemplo), y dada esta entrada, la aplicación crea una consulta SQL, ejecuta la consulta sobre la base de datos, y despliega los resultados en HTML. 
  
    * Como fue mencionado antes, hay que tener al menos tres consultas demostrando una mezcla de rasgos de SQL, es decir, joins, consultas anidadas, agregación, etc.     * Como fue mencionado antes, hay que tener al menos tres consultas demostrando una mezcla de rasgos de SQL, es decir, joins, consultas anidadas, agregación, etc. 
-   * Al menos dos de las consultas deberían incluir uno o más parámetros ingresados por el usuario de la aplicación web.+   * Al menos dos de las consultas deberían incluir uno o más parámetros ingresados desde la aplicación web.
    * No es necesario tener todos los rasgos en todas las consultas. La idea es que se demuestren los rasgos en alguna consulta. Se puede empezar con una consulta simple.    * No es necesario tener todos los rasgos en todas las consultas. La idea es que se demuestren los rasgos en alguna consulta. Se puede empezar con una consulta simple.
    * Es importante usar indices, vistas, etc., para optimizar las consultas.    * Es importante usar indices, vistas, etc., para optimizar las consultas.
-   * Si uno quiere usar una vista, y si la complejidad está en la vista (es decir, si la vista maneja la agregación o los joins, etc.), está bien tener una consulta más simple. O sea, si hay una vista con los rasgos mencionados, eso también cuenta.+   * Si se quiere usar una vista, y si la complejidad está en la vista (es decir, si la vista maneja la agregación o los joins, etc.), está bien tener una consulta más simple. O sea, si hay una vista con los rasgos mencionados, eso también cuenta.
    * Se pueden armar varias interfaces (una página diferente para cada consulta) o una interfaz con varios formularios (una página para todas las consultas).    * Se pueden armar varias interfaces (una página diferente para cada consulta) o una interfaz con varios formularios (una página para todas las consultas).
    * Es importante usar métodos seguros, especialmente contra inyección.    * Es importante usar métodos seguros, especialmente contra inyección.
Line 31: Line 31:
 </code> </code>
  
-... y después usar ''webuser'' y su contraseña en la aplicación. Hay más información sobre [[https://www.postgresql.org/docs/11/static/sql-grant.html|GRANT aquí]].+... y después usar ''webuser'' y su contraseña en la aplicación. Hay más información sobre [[https://www.postgresql.org/docs/17/sql-grant.html|GRANT aquí]].
  
 Hay que tener cuidado con consultas como: Hay que tener cuidado con consultas como:
Line 48: Line 48:
 ===== Servidor Web ===== ===== Servidor Web =====
  
-Hay que eligir una sola opción aquí.+Hay que elegir una sola opción aquí.
  
-La primera opción (PHP) es de un nivel más bajo, y uno puede empezar rápidamente con ejemplos simples usando PHP.+La primera opción (PHP) es de un nivel más bajo, y se puede empezar rápidamente con ejemplos simples usando PHP.
  
 La segunda opción (Django+Python) es un ejemplo de framework //Model-View-Controller// (MVC), el uso del cual es popular hoy en día. Ofrece una abstracción de nivel más alto, pero hay que aprender y configurar mucho. La segunda opción (Django+Python) es un ejemplo de framework //Model-View-Controller// (MVC), el uso del cual es popular hoy en día. Ofrece una abstracción de nivel más alto, pero hay que aprender y configurar mucho.
Line 56: Line 56:
 La tercera opción (Java Servlets) queda un poco desactualizada, pero todavía hay varios sistemas legados que las usan. Se recomienda en el caso de realmente querer programar en Java. La tercera opción (Java Servlets) queda un poco desactualizada, pero todavía hay varios sistemas legados que las usan. Se recomienda en el caso de realmente querer programar en Java.
  
-Se puede eligir otra opción también. El curso no se trata del desarrollo de aplicaciones web, así que no importa qué opción se prefiere con respecto a la evaluación final (solo importan el resultado final y la seguridad).+Se puede elegir otra opción también. El curso no se trata del desarrollo de aplicaciones web, así que no importa qué opción se prefiere con respecto a la evaluación final (solo importan el resultado final y la seguridad).
  
 **Nota 1**: Durante el tutorial se pedirá usar: **Nota 1**: Durante el tutorial se pedirá usar:
Line 106: Line 106:
 sudo apt-get update sudo apt-get update
 sudo apt-get install apache2 sudo apt-get install apache2
 +</code>
 +
 +La máquina trae nginx, otro servidor web, que ya ocupa el puerto 80. Si al instalar aparece ''Could not execute systemctl'', o si la página de abajo muestra "Welcome to nginx!", hay que deshabilitar nginx y partir apache2:
 +
 +<code>
 +sudo systemctl disable --now nginx
 +sudo systemctl start apache2
 </code> </code>
  
Line 120: Line 127:
 PHP (PHP: Hypertext Preprocessor) es un lenguaje para crear scripts que se ejecutan en el servidor (al contrario de Javascript, por ejemplo, que se ejecuta normalmente en el lado del cliente). PHP (PHP: Hypertext Preprocessor) es un lenguaje para crear scripts que se ejecutan en el servidor (al contrario de Javascript, por ejemplo, que se ejecuta normalmente en el lado del cliente).
  
-Para instalar PHP con soporte para apache2 y postgres (ojo que si no hay la versión exacta, también se puede usar una versión más nueva):+Para instalar PHP con soporte para apache2 y postgres (sin número de versión, se instala la que trae Debian, que es la 8.4):
  
-<code>sudo apt-get install php8.2 libapache2-mod-php8.2 php8.2-pgsql</code>+<code>sudo apt-get install php libapache2-mod-php php-pgsql</code>
  
 Ahora, tenemos que reiniciar Apache: Ahora, tenemos que reiniciar Apache:
Line 174: Line 181:
 </code> </code>
  
-Este formulario le mandará a ''print.php'' un atributo con el nombre ''msg'' y un valor que sea la entrada del usuario; el formulario usará HTTP ''get'' para mandar la información. Entonces tenemos que dar el código en ''print.php'':+Este formulario le mandará a ''print.php'' un atributo con el nombre ''msg'' y un valor que sea la entrada del usuario; el formulario usará HTTP ''get'' para mandar la información. Entonces tenemos que dar el código en ''print.php'' (''htmlspecialchars'' evita que el mensaje se interprete como HTML; sin eso, se podría inyectar código en la página):
  
 <code> <code>
Line 183: Line 190:
 <?php <?php
 $name = $_GET['msg']; $name = $_GET['msg'];
-echo "El mensaje es: $name";+echo "El mensaje es: " . htmlspecialchars($name);
 ?> ?>
 </code> </code>
Line 227: Line 234:
 === Debugear / Logs === === Debugear / Logs ===
  
-Si tu aplicación PHP no está funcionado, y en particular si ves "''HTTP ERROR 500''" no entres en pánico. Es que hay un bug en tu código. Primero deberías revisar el siguiente log de apache2 que lista los errores que ha encontrado:+Si su aplicación PHP no está funcionando, y en particular si ven "''HTTP ERROR 500''", no entren en pánico. Es que hay un bug en su código. Primero deberían revisar el siguiente log de apache2 que lista los errores que ha encontrado:
  
 <code>sudo more /var/log/apache2/error.log</code> <code>sudo more /var/log/apache2/error.log</code>
  
-Al final del archivo habrá los errores más recientes. Puedes usar la barra espaciadora para avanzar en el archivo. El error debería proveer más información para resolver el problema.+Al final del archivo habrá los errores más recientes. Pueden usar la barra espaciadora para avanzar en el archivo. El error debería proveer más información para resolver el problema.
  
 Si el error no es de Apache2 + PHP, puede tratarse de Postgres. Para ver los logs hay que abrir: Si el error no es de Apache2 + PHP, puede tratarse de Postgres. Para ver los logs hay que abrir:
  
-<code>sudo more /var/log/postgresql/postgresql-11-main.log</code>+<code>sudo more /var/log/postgresql/postgresql-17-main.log</code>
  
 Y ver al final del archivo el posible error. Y ver al final del archivo el posible error.
Line 250: Line 257:
 La idea de Django es proveer una abstracción Modelo/Vista/Controlador de una aplicación Web en Python, donde el modelo captura los datos (p.ej. SQL) y la lógica (p.ej. python), la vista representa la información de salida que hay que desplegar para el usuario (p.ej. HTML), y el controlador acepta la entrada del usuario y la convierte en modificaciones al modelo (p.ej. para actualizar la base de datos desde una petición en HTML). La idea de Django es proveer una abstracción Modelo/Vista/Controlador de una aplicación Web en Python, donde el modelo captura los datos (p.ej. SQL) y la lógica (p.ej. python), la vista representa la información de salida que hay que desplegar para el usuario (p.ej. HTML), y el controlador acepta la entrada del usuario y la convierte en modificaciones al modelo (p.ej. para actualizar la base de datos desde una petición en HTML).
  
-Django tiene un costo inicial muy alto, pero después uno tendrá una abstracción más limpia, la cual es útil, en particular, para aplicaciones complejas. Si ustedes quieren hacer algo más simple y rápido, PHP sería la mejora opción. Si ustedes quieren aprender algo de un framework usado bastante en la práctica, Django es una buena opción PERO aquí sólo se dará la información suficiente para instalar y configurar una aplicación básica. No será un tutorial completo (el enfoque del curso es bases de datos, no aplicaciones web). Aquí puede encontrar más información útil: desde tutoriales hasta documentación: [[https://www.djangoproject.com/start/|Django docs]].+Django tiene un costo inicial muy alto, pero después uno tendrá una abstracción más limpia, la cual es útil, en particular, para aplicaciones complejas. Si ustedes quieren hacer algo más simple y rápido, PHP sería la mejora opción. Si ustedes quieren aprender algo de un framework usado bastante en la práctica, Django es una buena opción PERO aquí sólo se dará la información suficiente para instalar y configurar una aplicación básica. No será un tutorial completo (el enfoque del curso es bases de datos, no aplicaciones web). Aquí pueden encontrar más información útil: desde tutoriales hasta documentación: [[https://www.djangoproject.com/start/|Django docs]].
  
 === Instalar Python === === Instalar Python ===
Line 267: Line 274:
 </code> </code>
  
-Considerar que la versión de Python 3 instalada puede variar, en este caso se trabajó con la versión ''3.7''.+Considerar que la versión de Python 3 instalada puede variar, en este caso se trabajó con la versión ''3.13''.
  
-(Por defecto, ''python'' usa ''python2'' porque algunas dependencias del sistema operativo asumen eso y no son compatibles con python3. Para ejecutar ''python3'', hay que usar el comando ''python3'' .)+(En Debian 13 no existe el comando ''python''; hay que usar ''python3''.)
  
 === Instalar Django === === Instalar Django ===
  
-Usaremos PIP (un instalador para packages de Python) para instalar la versión más reciente de Django para python3.+Usaremos PIP (un instalador para packages de Python) para instalar la versión más reciente de Django. Debian no deja instalar paquetes con ''pip'' en el Python del sistema (si lo intentan, ''pip'' responde ''error: externally-managed-environment''), así que primero crearemos un //entorno virtual// (''venv''): una carpeta con su propio Python, donde ''pip'' sí puede instalar.
  
 <code> <code>
-sudo apt-get install python3-pip+sudo apt-get install python3-venv 
 +mkdir /home/cc3201/django 
 +cd /home/cc3201/django 
 +python3 -m venv venv
 </code> </code>
  
-Ahora, instalamos Django usando ''pip3'':+Para usar el entorno virtual hay que activarlo:
  
 <code> <code>
-sudo pip3 install django+source /home/cc3201/django/venv/bin/activate
 </code> </code>
  
-También tenemos que instalar soporte para Postgres:+La línea de comandos empieza ahora con ''(venv)''. Mientras esté activo, ''python3'' y ''pip'' son los del entorno virtual. Hay que activarlo cada vez que entren al servidor para trabajar en Django. 
 + 
 +Ahora, instalamos Django, junto con el soporte para Postgres:
  
 <code> <code>
-sudo apt-get install libpq-dev python-dev +pip install django psycopg2-binary
-sudo pip3 install psycopg2+
 </code> </code>
  
Line 298: Line 309:
 </code> </code>
  
-En este tutorial se instalo la versión ''3.0.7''. Si sale el error: +En este tutorial se instaló la versión ''6.1.3''.
- +
-<code> +
-django-admin.py Command no found +
-</code> +
- +
-Tenemos que darle el camino correcto al administrador de ''django'': +
- +
-<code> +
-sudo vi /usr/bin/django-admin +
-</code> +
- +
-... y cambiar el camino aquí: +
- +
-<code> +
-if command -v python3 > /dev/null && test -e /usr/lib/python3/dist-packages/django/bin/django-admin.py +
-</code> +
- +
-... por: +
- +
-<code> +
-if command -v python3 > /dev/null && test -e /usr/local/lib/python3.7/dist-packages/django/bin/django-admin.py +
-</code> +
- +
-(agregando ''local'' y ''.7'' o la versión de python que corresponda).+
  
 === Crear un proyecto === === Crear un proyecto ===
  
-Ahora que tenemos todo instalado, podemos crear un proyecto inicial en Django. Crearemos una carpeta para el proyecto:+Ahora que tenemos todo instalado, podemos crear un proyecto inicial en Django, en la carpeta que creamos antes:
  
 <code> <code>
-mkdir /home/cc3201/django 
 cd /home/cc3201/django cd /home/cc3201/django
 </code> </code>
Line 349: Line 335:
  
 <code> <code>
-sudo python3 /home/cc3201/django/cc3201/manage.py migrate+python3 /home/cc3201/django/cc3201/manage.py migrate
 </code> </code>
  
Line 356: Line 342:
 (//Dos cosas que haremos aquí que no se deberían hacer en un sistema de producción: (1) Django tiene un servidor web integrado para probar las aplicaciones. Usaremos eso porque es más conveniente pero en general, Django no es un servidor web maduro, y en la producción, sería mejor usar un servidor web como apache2 o nginx. (2) Corremos Django en el puerto 80 y por eso, tendremos que usar ''sudo''; en general, no es una buena idea correr un servidor web con ''sudo'' pero está bien aquí.//)  (//Dos cosas que haremos aquí que no se deberían hacer en un sistema de producción: (1) Django tiene un servidor web integrado para probar las aplicaciones. Usaremos eso porque es más conveniente pero en general, Django no es un servidor web maduro, y en la producción, sería mejor usar un servidor web como apache2 o nginx. (2) Corremos Django en el puerto 80 y por eso, tendremos que usar ''sudo''; en general, no es una buena idea correr un servidor web con ''sudo'' pero está bien aquí.//) 
  
-Ahora, podemos intentar iniciar un servidor de desarrollo en el puerto 80:+Ahora, podemos intentar iniciar un servidor de desarrollo en el puerto 80. Como ''sudo'' no ve el entorno virtual, hay que darle la ruta completa a su ''python3'':
  
 <code> <code>
-sudo python3 /home/cc3201/django/cc3201/manage.py runserver 0.0.0.0:80+sudo /home/cc3201/django/venv/bin/python3 /home/cc3201/django/cc3201/manage.py runserver 0.0.0.0:80
 </code> </code>
  
-(Si hay un error "''That port is already in use''", hay que deshabiliar apache2 o tomcat7 ...)+(Si hay un error "''That port is already in use''", hay que deshabilitar nginx, que viene en la máquina, o apache2 o tomcat10 si los instalaron ...)
  
 <code> <code>
-sudo service apache2 stop +sudo systemctl disable --now nginx 
-sudo service tomcat7 stop+sudo systemctl disable --now apache2 
 +sudo systemctl disable --now tomcat10
 </code> </code>
  
Line 435: Line 422:
  
 <code> <code>
-sudo python3 /home/cc3201/django/cc3201/manage.py runserver 0.0.0.0:80+sudo /home/cc3201/django/venv/bin/python3 /home/cc3201/django/cc3201/manage.py runserver 0.0.0.0:80
 </code> </code>
  
Line 469: Line 456:
  
 <code> <code>
-sudo python3 /home/cc3201/django/cc3201/manage.py createsuperuser+python3 /home/cc3201/django/cc3201/manage.py createsuperuser
 </code> </code>
  
Line 514: Line 501:
     {     {
         'BACKEND': 'django.template.backends.django.DjangoTemplates',         'BACKEND': 'django.template.backends.django.DjangoTemplates',
-        'DIRS': [os.path.join(BASE_DIR, 'templates')],+        'DIRS': [BASE_DIR / 'templates'],
         'APP_DIRS': True,         'APP_DIRS': True,
         'OPTIONS': {         'OPTIONS': {
Line 531: Line 518:
  
 <code> <code>
-STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')+STATIC_ROOT = BASE_DIR / 'staticfiles'
 STATICFILES_DIRS = [ STATICFILES_DIRS = [
-    os.path.join(BASE_DIR, "static/"),+    BASE_DIR / 'static',
 ] ]
 </code> </code>
Line 546: Line 533:
  
 <code> <code>
-"""cc3201 URL Configuration+""" 
 +URL configuration for cc3201 project.
  
 The `urlpatterns` list routes URLs to views. For more information please see: The `urlpatterns` list routes URLs to views. For more information please see:
-    https://docs.djangoproject.com/en/1.11/topics/http/urls/+    https://docs.djangoproject.com/en/6.1/topics/http/urls/
 Examples: Examples:
 Function views Function views
     1. Add an import:  from my_app import views     1. Add an import:  from my_app import views
-    2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')+    2. Add a URL to urlpatterns:  path('', views.home, name='home')
 Class-based views Class-based views
     1. Add an import:  from other_app.views import Home     1. Add an import:  from other_app.views import Home
-    2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')+    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
 Including another URLconf Including another URLconf
-    1. Import the include() function: from django.conf.urls import url, include +    1. Import the include() function: from django.urls import include, path 
-    2. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))+    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
 """ """
-import os 
- 
 from django.conf import settings from django.conf import settings
 from django.conf.urls.static import static from django.conf.urls.static import static
Line 720: Line 706:
 </code> </code>
  
-Ahora, tenemos una vista pero tenemos que mapear un URL a la vista. Para eso, crearemos un archivo nuevo ''urls.py'' en la misma carpeta (''/home/cc3201/django/cc3201/prueba'' en mi caso):+Ahora, tenemos una vista pero tenemos que mapear un URL a la vista. Para eso, crearemos un archivo nuevo ''urls.py'' en la misma carpeta (''/home/cc3201/django/cc3201/prueba''):
  
 <code> <code>
Line 748: Line 734:
  
 <code> <code>
-from django.conf.urls import include, url+from django.urls import include
 </code> </code>
  
Line 786: Line 772:
     'default': {     'default': {
         'ENGINE': 'django.db.backends.sqlite3',         'ENGINE': 'django.db.backends.sqlite3',
-        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),+        'NAME': BASE_DIR / 'db.sqlite3',
     }     }
 } }
Line 796: Line 782:
 DATABASES = { DATABASES = {
     'default': {     'default': {
-        'ENGINE': 'django.db.backends.postgresql_psycopg2',+        'ENGINE': 'django.db.backends.postgresql',
         'NAME': 'cc3201',         'NAME': 'cc3201',
         'USER': 'cc3201',         'USER': 'cc3201',
Line 842: Line 828:
 </code> </code>
  
-Estas corresponden a tablas que usa Django para diversas funcionalidades como manejo de usuarios o permisos.+Estas corresponden a tablas que usa Django para diversas funcionalidades como manejo de usuarios o permisos. Django las crea en el primer esquema del ''search_path'' de ''cc3201'', que es el esquema de su proyecto (ver [[proyecto:configurar_postgres|Configurar Postgres]]). Por eso, después de migrar no hay que cambiar el ''search_path'' de ''cc3201'': si el esquema del proyecto sale de la lista, Django deja de encontrar sus tablas y aparecen errores como ''relation "auth_user" does not exist''.
  
 === Crear un modelo para la base de datos === === Crear un modelo para la base de datos ===
  
-Crearemos el esquema ''test'' más una tabla para probar la funcionalidad:+Crearemos una tabla para probar la funcionalidad, en el esquema de su proyecto (en ''psql'', reemplazando ''<nombre>'' por el nombre de su esquema):
  
 <code> <code>
-CREATE SCHEMA test; +CREATE TABLE <nombre>.mes( 
- +
-ALTER USER cc3201 SET search_path TO test, public; +
-</code> +
- +
-Notar que es importante poner el path público para que Django puede reconocer este nuevo esquema. Ahora creamos la tabla de prueba: +
- +
-<code> +
-CREATE TABLE test.mes( +
   nombre varchar(255) PRIMARY KEY,   nombre varchar(255) PRIMARY KEY,
   numero int   numero int
 ); );
  
-INSERT INTO test.mes VALUES ('Mayo',5); +INSERT INTO <nombre>.mes VALUES ('Mayo',5); 
-INSERT INTO test.mes VALUES ('Junio',6);+INSERT INTO <nombre>.mes VALUES ('Junio',6);
 </code> </code>
  
Line 887: Line 865:
 Cada clase refleja una relación en la base de datos con sus atributos y algunas restricciones básicas. Una instancia de esa clase representará una tupla en la relación. Cada clase refleja una relación en la base de datos con sus atributos y algunas restricciones básicas. Una instancia de esa clase representará una tupla en la relación.
  
-Escribiremos el modelo a un archivo en la carpeta de la aplicación (en este caso ''prueba''):+Escribiremos el modelo de la tabla ''mes'' a un archivo en la carpeta de la aplicación (en este caso ''prueba''). Al poner el nombre de la tabla, ''inspectdb'' escribe solo esa clase, sin las tablas internas de Django:
  
 <code> <code>
-python3 /home/cc3201/django/cc3201/manage.py inspectdb > /home/cc3201/django/cc3201/prueba/models.py+python3 /home/cc3201/django/cc3201/manage.py inspectdb mes > /home/cc3201/django/cc3201/prueba/models.py
 </code> </code>
  
-Una complicación aquí es que hay que poner un límite al número de caracteres en cada campo del tipo ''CharField''. Entonces hay que revisar ''models.py'' y si hay una columna de una tabla así: +Si tienen más tablas, se pueden poner todas separadas por espacios (''inspectdb mes tabla2 tabla3'').
- +
-<code> +
- models.CharField(max_length=-1, blank=True, null=True) +
-</code> +
- +
-... cambiarla por: +
- +
-<code> +
-models.TextField(max_length=255, blank=True, null=True) +
-</code> +
- +
-... con las opciones que aplican. +
- +
-:(+
  
 === Consultar el modelo con Python === === Consultar el modelo con Python ===
  
-Dado un modelo, Django tiene [[https://docs.djangoproject.com/en/1.11/topics/db/queries/|varias funciones para interactuar con la base de datos en Python]]. Probaremos la conexión a la base de datos con algo simple en la aplicación ''prueba''. Empezaremos con una vista nueva ''mayo'':+Dado un modelo, Django tiene [[https://docs.djangoproject.com/en/6.1/topics/db/queries/|varias funciones para interactuar con la base de datos en Python]]. Probaremos la conexión a la base de datos con algo simple en la aplicación ''prueba''. Empezaremos con una vista nueva ''mayo'':
  
 <code> <code>
Line 962: Line 926:
 === Consultar a la base de datos usando SQL === === Consultar a la base de datos usando SQL ===
  
-En el proyecto, pueden hacer consultas por el modelo de Django o pueden [[https://docs.djangoproject.com/en/1.11/topics/db/sql/|usar consultas de SQL directas]]. (En el caso de usar el modelo, ojo que deberían incluir las consultas equivalentes de SQL en las entregas del proyecto.)+En el proyecto, pueden hacer consultas por el modelo de Django o pueden [[https://docs.djangoproject.com/en/6.1/topics/db/sql/|usar consultas de SQL directas]]. (En el caso de usar el modelo, ojo que deberían incluir las consultas equivalentes de SQL en las entregas del proyecto.)
  
-Crearemos una vista nueva para ejemplificar la funcionalidad:+Crearemos una vista nueva para ejemplificar la funcionalidad (reemplazando ''<nombre>'' en la consulta por el nombre de su esquema). El ''%s'' marca dónde va el parámetro, y Django lo manda por separado como sentencia precompilada, así que es seguro contra inyección:
  
 <code> <code>
Line 985: Line 949:
 def consultar_mes(mes): def consultar_mes(mes):
     with connection.cursor() as cursor:     with connection.cursor() as cursor:
-        cursor.execute("SELECT numero FROM test.mes WHERE nombre = %s", [mes])+        cursor.execute("SELECT numero FROM <nombre>.mes WHERE nombre = %s", [mes])
         results = namedtuplefetchall(cursor)         results = namedtuplefetchall(cursor)
     return results     return results
Line 1029: Line 993:
 </code> </code>
  
-Crearemos un formulario para pedirle al usuario el nombre de un mes:+Crearemos un formulario para pedir el nombre de un mes:
  
 <code>vi /home/cc3201/django/cc3201/prueba/templates/mes_form.html</code> <code>vi /home/cc3201/django/cc3201/prueba/templates/mes_form.html</code>
Line 1045: Line 1009:
 </code> </code>
  
-La acción dice que vamos a mandar la información entregada al camino "/mes/" por HTTP ''post''.+La acción vacía (''action=""'') dice que vamos a mandar la información entregada a la misma página (''/prueba/mes/'') por HTTP ''post''.
  
 Ahora, podemos usar Django para definir los detalles del formulario (para reemplazar ''mes_form'' arriba): Ahora, podemos usar Django para definir los detalles del formulario (para reemplazar ''mes_form'' arriba):
Line 1111: Line 1075:
 def consultar_mes(mes): def consultar_mes(mes):
     with connection.cursor() as cursor:     with connection.cursor() as cursor:
-        cursor.execute("SELECT numero FROM test.mes WHERE nombre = %s", [mes])+        cursor.execute("SELECT numero FROM <nombre>.mes WHERE nombre = %s", [mes])
         results = namedtuplefetchall(cursor)         results = namedtuplefetchall(cursor)
     return results     return results
Line 1146: Line 1110:
 === Eso === === Eso ===
  
-Con el ejemplo previo, y por fin, tienen todos los ingredientes para armar su aplicación usando Django. Un recordatorio: hay que verificar que la aplicación **esté segura contra inyección**. Puede ser que los ejemplos que doy aquí no sean seguros, entonces hay que investigar en la Web si son seguros o no.+Con el ejemplo previo, y por fin, tienen todos los ingredientes para armar su aplicación usando Django. Un recordatorio: hay que verificar que la aplicación **esté segura contra inyección**. Puede ser que los ejemplos de aquí no sean seguros, entonces hay que investigar en la Web si son seguros o no.
  
 ==== Opción 3: Java Servlets ==== ==== Opción 3: Java Servlets ====
Line 1157: Line 1121:
 La opción de Java Servlets es una opción legada que tenía relevancia cuando el lenguaje usado en el curso Introducción a Programación fue Java. En vez de borrar la opción, la hemos mantenido acá, pero en general, no es una opción recomendada, salvo en el caso de que un grupo realmente quiera programar en Java. La opción de Java Servlets es una opción legada que tenía relevancia cuando el lenguaje usado en el curso Introducción a Programación fue Java. En vez de borrar la opción, la hemos mantenido acá, pero en general, no es una opción recomendada, salvo en el caso de que un grupo realmente quiera programar en Java.
  
-=== Instalar tomcat9 ===+=== Instalar tomcat10 ===
  
-Hay que instalar ''tomcat9'', un servidor web para Java Servlets:+Hay que instalar ''tomcat10'', un servidor web para Java Servlets:
  
 <code> <code>
 sudo apt-get update sudo apt-get update
-sudo apt-get install tomcat9 tomcat9-admin tomcat9-examples tomcat9-docs authbind+sudo apt-get install tomcat10 tomcat10-admin tomcat10-examples tomcat10-docs
 </code> </code>
  
-=== Configurar tomcat9 ===+(Desde Tomcat 10, los servlets usan los paquetes ''jakarta.servlet'' en vez de ''javax.servlet''. Los ejemplos y tutoriales antiguos que usan ''javax'' no funcionan en Tomcat 10 sin cambiar los ''import''.) 
 + 
 +=== Configurar tomcat10 ===
  
 Tenemos que poner un usuario "admin" y una contraseña: Tenemos que poner un usuario "admin" y una contraseña:
  
 <code> <code>
-sudo nano /etc/tomcat9/tomcat-users.xml+sudo nano /etc/tomcat10/tomcat-users.xml
 </code> </code>
  
Line 1177: Line 1143:
  
 <code> <code>
-<tomcat-users>+<tomcat-users ...>
 </tomcat-users> </tomcat-users>
 </code> </code>
Line 1184: Line 1150:
  
 <code> <code>
-<tomcat-users>+<tomcat-users ...>
     <user username="admin" password="holaprueba" roles="manager-gui,admin-gui"/>     <user username="admin" password="holaprueba" roles="manager-gui,admin-gui"/>
 </tomcat-users> </tomcat-users>
Line 1191: Line 1157:
 ... y guardar el archivo. ... y guardar el archivo.
  
-Por defecto, tomcat9 será instalado con el puerto 8080, el cual no es accesible desde afuera. Tenemos que cambiarlo a 80 (el puerto por defecto en HTTP).+Por defecto, tomcat10 será instalado con el puerto 8080, el cual no es accesible desde afuera. Tenemos que cambiarlo a 80 (el puerto por defecto en HTTP).
  
 <code> <code>
-sudo nano /etc/tomcat9/server.xml+sudo nano /etc/tomcat10/server.xml
 </code> </code>
  
Line 1209: Line 1175:
 </code> </code>
  
-... y guardar el archivo. +... y guardar el archivo. El servicio ''tomcat10'' de Debian ya tiene permiso para usar el puerto 80, así que no hay que configurar nada más para el puerto.
- +
-Ahora ... +
- +
-<code> +
-sudo nano /etc/default/tomcat9 +
-</code> +
- +
-Hay que cambiar: +
- +
-<code> +
-#AUTHBIND=no +
-</code> +
- +
-por (ojo: hay que borrar el gato): +
- +
-<code> +
-AUTHBIND=yes +
-</code> +
- +
-... y guardar el archivo. +
- +
-El próximo paso es deshabilitar IPv6 porque ''AUTHBIND'' solo funciona con IPv4. +
- +
-<code> +
-sudo nano /usr/share/tomcat9/bin/setenv.sh +
-</code> +
- +
-Hay que poner: +
- +
-<code> +
-export CATALINA_OPTS="$CATALINA_OPTS -Djava.net.preferIPv4Stack=true" +
-</code> +
- +
-Después, en: +
- +
-<code> +
-sudo nano /usr/share/tomcat9/bin/startup.sh +
-</code> +
- +
-Hay que comentar la primera línea aquí y agregar la segunda: +
- +
-<code> +
-# exec "$PRGDIR"/"$EXECUTABLE" start "$@"  +
-exec authbind --deep "$PRGDIR"/"$EXECUTABLE" start "$@" +
-</code> +
- +
-Por fin, está lista la configuración del puerto 80.+
  
-Finalmente, hay que darle a Tomcat acceso al controlador de Postgres:+Finalmente, hay que darle a Tomcat acceso al controlador de Postgres (JDBC). Debian lo trae como paquete, y basta con dejarlo en la carpeta ''lib'' de Tomcat:
  
 <code> <code>
-sudo apt-get install wget +sudo apt-get install libpostgresql-jdbc-java 
-cd /usr/share/tomcat9/lib/ +sudo ln -s /usr/share/java/postgresql.jar /usr/share/tomcat10/lib/postgresql.jar
-sudo wget https://jdbc.postgresql.org/download/postgresql-9.4.1212.jre6.jar+
 </code> </code>
  
 Ahora se puede usar JDBC para consultar a Postgres desde Tomcat. Ahora se puede usar JDBC para consultar a Postgres desde Tomcat.
  
-=== Correr el servidor de tomcat9 ===+=== Correr el servidor de tomcat10 ===
  
-En el caso de que Apache esté instalado y corriendo, hay que deshabilitarlo (si no está instalado, se puede saltar este paso):+La máquina trae nginx, que ya ocupa el puerto 80, así que hay que deshabilitarlo. En el caso de que Apache esté instalado y corriendo, también hay que deshabilitarlo (si no está instalado, se puede saltar esa línea):
  
 <code> <code>
-sudo /etc/init.d/apache2 stop+sudo systemctl disable --now nginx 
 +sudo systemctl disable --now apache2
 </code> </code>
  
-Está lista la configuración así que tenemos que reiniciar tomcat9:+Está lista la configuración así que tenemos que reiniciar tomcat10:
  
 <code> <code>
-sudo service tomcat9 restart+sudo service tomcat10 restart
 </code> </code>
  
Line 1285: Line 1204:
  
 <code> <code>
-http://cc3201.dcc.uchile.cl/grupoXX/+http://grupoXX.cc3201.dcc.uchile.cl/
 </code> </code>
  
Line 1292: Line 1211:
 === Un ejemplo de un Java Servlet === === Un ejemplo de un Java Servlet ===
  
-(//Una confesión: en el ejemplo que doy, pongo HTML en el código de Java. Eso es muy feo porque mezcla la presentación y la lógica de la aplicación. Sería muchísimo mejor usar JSP con los servlets, pero también más complicado.//)+(//Una confesión: en el ejemplo, el HTML va en el código de Java. Eso es muy feo porque mezcla la presentación y la lógica de la aplicación. Sería muchísimo mejor usar JSP con los servlets, pero también más complicado.//)
  
 Efectivamente, un servlet es como un paquete de código en Java en un formato "WAR". Es como un JAR pero con algunas diferencias: tiene una página web y algunas configuraciones más. Efectivamente, un servlet es como un paquete de código en Java en un formato "WAR". Es como un JAR pero con algunas diferencias: tiene una página web y algunas configuraciones más.
  
-Descargar [[http://aidanhogan.com/teaching/tools/cc3201/servlet-test.zip|servlet-test.zip]] y abrirlo en Eclipse o IntelliJ, etc.+Descargar {{proyecto:servlet-test.zip|servlet-test.zip}} y abrirlo en Eclipse o IntelliJ, etc. (Es la versión actualizada para Tomcat 10, con ''jakarta.servlet''.)
  
 En ''src/'' está el código. En ''src/'' está el código.
Line 1306: Line 1225:
 En ''web/WEB-INF/web.xml'' está la configuración del servlet. En ''web/WEB-INF/web.xml'' está la configuración del servlet.
  
-En ''web/WEB-INF/context.xml'' hay que cambiar el ''username'' y el ''password''. Se debería usar el usuario de la aplicación (p.ej. ''webuser''), no un super-usuario como ''cc3201'' o ''postgres''. No hay que cambiar el IP ni el puerto (la aplicación será instalada directamente en la máquina virtual así que la conexión será por localhost) ni la base de datos.+En ''web/META-INF/context.xml'' hay que cambiar el ''username'' y el ''password''. Se debería usar el usuario de la aplicación (p.ej. ''webuser''), no un super-usuario como ''cc3201'' o ''postgres''. No hay que cambiar el IP ni el puerto (la aplicación será instalada directamente en la máquina virtual así que la conexión será por localhost) ni la base de datos.
  
-Tenemos que crear un paquete ''.war''. Sobre ''build.xml'' hacer clic derecho, ''Run As > Ant Build''.+Tenemos que crear un paquete ''.war''. Sobre ''build.xml'' hacer clic derecho, ''Run As > Ant Build''. (También se puede compilar sin un IDE: con [[https://ant.apache.org/|Ant]] y Java 17 o más nuevo instalados, basta con ejecutar ''ant'' en la carpeta del proyecto.)
  
 Ahora hay que refrescar el proyecto: hacer clic en la carpeta del proyecto y presionar ''F5''. En ''dist/'', debería haber un archivo ''bddservlet.war''. Ahora hay que refrescar el proyecto: hacer clic en la carpeta del proyecto y presionar ''F5''. En ''dist/'', debería haber un archivo ''bddservlet.war''.
  
-Tenemos que subir el archivo ''bddservlet.war'' a la carpeta ''/var/lib/tomcat9/webapps/'' pero será más fácil si ''cc3201'' tiene permisos para estas carpetas:+Tenemos que subir el archivo ''bddservlet.war'' a la carpeta ''/var/lib/tomcat10/webapps/'' pero será más fácil si ''cc3201'' tiene permisos para estas carpetas:
  
 <code> <code>
-sudo chown -R tomcat9:tomcat9 /var/lib/tomcat9 +sudo chown -R tomcat:tomcat /var/lib/tomcat10 
-sudo chmod -R g+r /var/lib/tomcat9/conf +sudo chmod -R g+r /var/lib/tomcat10/conf 
-sudo chmod -R g+w /var/lib/tomcat9/conf +sudo chmod -R g+w /var/lib/tomcat10/conf 
-sudo chmod -R g+w /var/lib/tomcat9/logs +sudo chmod -R g+w /var/lib/tomcat10/logs 
-sudo chmod -R g+w /var/lib/tomcat9/webapps +sudo chmod -R g+w /var/lib/tomcat10/webapps 
-sudo chmod -R g+w /var/lib/tomcat9/work +sudo chmod -R g+w /var/lib/tomcat10/work 
-sudo chmod -R g+s /var/lib/tomcat9/conf +sudo chmod -R g+s /var/lib/tomcat10/conf 
-sudo chmod -R g+s /var/lib/tomcat9/logs +sudo chmod -R g+s /var/lib/tomcat10/logs 
-sudo chmod -R g+s /var/lib/tomcat9/webapps +sudo chmod -R g+s /var/lib/tomcat10/webapps 
-sudo chmod -R g+s /var/lib/tomcat9/work +sudo chmod -R g+s /var/lib/tomcat10/work 
-sudo usermod -a -G tomcat9 cc3201+sudo usermod -a -G tomcat cc3201
 </code> </code>
  
-Después, [[https://wiki.dcc.uchile.cl/cc3201/doku.php?id=proyecto:acceso_al_servidor#transferencia_de_datos|hay que usar]] ''scp'' o ''sftp'' o ''wget'' para poner ''bddservlet.war'' en la carpeta ''/var/lib/tomcat9/webapps/'' del servidor. Se instalará la aplicación automáticamente en la carpeta ''bddservlet/'' en ''/var/lib/tomcat9/webapps/bddservlet''. (Si uno hace la transferencia de nuevo, actualizará la carpeta también.)+(El grupo nuevo corre desde la próxima vez que entren por SSH, así que hay que salir con ''exit'' y volver a entrar.) 
 + 
 +Después, [[https://wiki.dcc.uchile.cl/cc3201/doku.php?id=proyecto:acceso_al_servidor#transferencia_de_datos|hay que usar]] ''scp'' o ''sftp'' o ''wget'' para poner ''bddservlet.war'' en la carpeta ''/var/lib/tomcat10/webapps/'' del servidor. Se instalará la aplicación automáticamente en la carpeta ''bddservlet/'' en ''/var/lib/tomcat10/webapps/bddservlet''. (Si se hace la transferencia de nuevo, actualizará la carpeta también.)
  
 Ir a: Ir a:
Line 1338: Line 1259:
 Aquí se pueden ver tres ejemplos simples de aplicaciones que pueden adaptar para su aplicación. Aquí se pueden ver tres ejemplos simples de aplicaciones que pueden adaptar para su aplicación.
  
-OJO: ¡es importante usar métodos seguros contra inyección! Mi ejemplo es solo una prueba, no un ejemplo a seguir.+OJO: ¡es importante usar métodos seguros contra inyección! Este ejemplo es solo una prueba, no un ejemplo a seguir: el servlet ''bdd'' ejecuta cualquier consulta que se escriba en el formulario.
  
-Si hay un problema con el servlet, el log está aquí:+Si hay un problema con el servlet, el log se puede ver así:
  
 <code> <code>
-sudo more /var/lib/tomcat9/logs/catalina.out+sudo journalctl -u tomcat10
 </code> </code>
 +
 +(y también en los archivos de ''/var/log/tomcat10/''.)
  
 ... el error más común es un problema con la contraseña/usuario en ''web/WEB-INF/context.xml''. Por eso, hay que revisar los detalles en ''psql'' para verificar que estén correctos. ... el error más común es un problema con la contraseña/usuario en ''web/WEB-INF/context.xml''. Por eso, hay que revisar los detalles en ''psql'' para verificar que estén correctos.
Line 1356: Line 1279:
 ... pero no podremos ofrecerles soporte si hay problemas. ... pero no podremos ofrecerles soporte si hay problemas.
  
-====== Conexión Externa =====+====== Conexión Externa ======
  
 Finalmente, se deben configurar los puertos de modo que la aplicación web quede disponible para acceder a través de una URL. Puede encontrar instrucciones de como hacerlo visitando [[proyecto:conexion_externa|este enlace]]. Finalmente, se deben configurar los puertos de modo que la aplicación web quede disponible para acceder a través de una URL. Puede encontrar instrucciones de como hacerlo visitando [[proyecto:conexion_externa|este enlace]].
proyecto/armar_la_aplicacion_inicial.txt · Last modified: by semorale