Tutorial: Implementación de una aplicación web de Django de Python con PostgreSQL en Azure App Service
En este tutorial se muestra cómo implementar una aplicación web de Django de Python en Azure App Service y cómo conectarla a una base de datos de Azure Database for Postgres. También puede seleccionar la opción anterior para probar la opción de servidor flexible de PostgresSQL (versión preliminar). La opción de servidor flexible proporciona un mecanismo de implementación más sencillo y menores costos continuos.
En este tutorial, se usa la CLI de Azure para completar las siguientes tareas:
- Configurar el entorno inicial con Python y la CLI de Azure
- Crear una base de datos de Azure Database for PostgreSQL
- Implementar código en Azure App Service y conectarse a PostgreSQL
- Actualizar el código y volver a implementarlo
- Visualización de los registros de diagnóstico
- Administrar la aplicación web en Azure Portal
También puede usar la versión de Azure Portal de este tutorial.
En este tutorial se muestra cómo implementar una aplicación web Python Django controlada por datos en Azure App Service y cómo conectarla a una base de datos de Azure Database for PostgreSQL: servidor flexible (versión preliminar). Si no puede usar la opción de servidor flexible de PostgreSQL (versión preliminar), seleccione la opción de servidor único anterior.
En este tutorial, se usa la CLI de Azure para completar las siguientes tareas:
- Configurar el entorno inicial con Python y la CLI de Azure
- Creación de una base de datos de Azure Database for PostgreSQL: servidor flexible
- Implementación de código en Azure App Service y conexión al servidor flexible de PostgreSQL
- Actualizar el código y volver a implementarlo
- Visualización de los registros de diagnóstico
- Administrar la aplicación web en Azure Portal
También puede usar la versión de Azure Portal de este tutorial.
1. Configuración del entorno inicial
- Disponga de una cuenta de Azure con una suscripción activa. Cree una cuenta gratuita.
- Instale Python 3.6 o una versión posterior.
- Instale la CLI de Azure 2.18.0 o posterior, con la que se ejecutan comandos en cualquier shell para aprovisionar y configurar los recursos de Azure.
Abra una ventana del terminal y compruebe que la versión de Python es la 3.6 o superior:
python3 --version
Compruebe que la versión de la CLI de Azure es la 2.18.0 o posterior:
az --version
Si necesita actualizar, pruebe el comando az upgrade (requiere la versión 2.11 o superior), o consulte Instalación de la CLI de Azure.
Después, inicie sesión en Azure mediante la CLI:
az login
Este comando abre un explorador que recopila las credenciales. Cuando el comando finaliza, muestra una salida JSON que contiene información sobre las suscripciones.
Una vez que haya iniciado sesión, puede ejecutar comandos de Azure con la CLI de Azure para trabajar con los recursos de su suscripción.
¿Tiene problemas? Póngase en contacto con nosotros.
2. Clonación o descarga de la aplicación de ejemplo
Clone el repositorio de ejemplo:
git clone https://github.com/Azure-Samples/djangoapp
Después, vaya a esa carpeta:
cd djangoapp
Para el servidor flexible (versión preliminar), use la rama de servidor flexible del ejemplo, que contiene algunos cambios necesarios, como cómo se establece la dirección URL del servidor de bases de datos y se agrega 'OPTIONS': {'sslmode': 'require'} a la configuración de la base de datos de Django según lo requiera el servidor flexible de Azure PostgreSQL.
git checkout flexible-server
El ejemplo djangoapp contiene la aplicación en Django de sondeos controlada por datos que se obtiene al seguir Creación de la primera aplicación Django de la documentación de Django. La aplicación completa se proporciona aquí para su comodidad.
El ejemplo también se ha modificado para ejecutarse en un entorno de producción, como App Service:
- La configuración para producción está en el archivo azuresite/production.py. Los valores del desarrollo están en el archivo azuresite/settings.py.
- La aplicación usa la configuración de producción cuando la variable de entorno
WEBSITE_HOSTNAMEestá establecida. Azure App Service establece automáticamente esta variable en la dirección URL de la aplicación web, comomsdocs-django.azurewebsites.net.
Los valores de producción son específicos de la configuración de Django para ejecutarse en cualquier entorno de producción y no son específicos de App Service. Para obtener más información, consulte la lista de implementación de Django. Consulte también Configuración de producción para Django en Azure para los detalles de algunos de los cambios.
¿Tiene problemas? Póngase en contacto con nosotros.
3. Creación de una base de datos de Postgres en Azure
Instale la extensión db-up para la CLI de Azure:
az extension add --name db-up
Si no se reconoce el comando az, asegúrese de que tiene instalada la CLI de Azure tal y como se describe en Configuración del entorno inicial.
A continuación, cree la base de datos de Postgres en Azure con el comando az postgres up:
az postgres up --resource-group DjangoPostgres-tutorial-rg --location centralus --sku-name B_Gen5_1 --server-name <postgres-server-name> --database-name pollsdb --admin-user <admin-username> --admin-password <admin-password> --ssl-enforcement Enabled
- Reemplace <postgres-server-name> por un nombre que sea único en Azure (el punto de conexión de servidor será
https://<postgres-server-name>.postgres.database.azure.com). Un buen patrón es usar una combinación del nombre de la empresa y otro valor exclusivo. - Para <admin-username> y <admin-password> , especifique las credenciales para crear un usuario administrador de este servidor Postgres. El nombre de inicio de sesión del administrador no puede ser azure_superuser, azure_pg_admin, admin, administrator, root, guest ni public. No puede empezar por pg_ . La contraseña debe contener entre 8 y 128 caracteres de tres de las categorías siguientes: letras del alfabeto inglés mayúsculas, letras del alfabeto inglés minúsculas, números (0 a 9) y caracteres no alfanuméricos (por ejemplo, !, $, #, %). La contraseña no puede contener el nombre de usuario.
- No use el carácter
$en el nombre de usuario ni la contraseña. Más adelante creará variables de entorno con estos valores, donde el carácter$tiene un significado especial dentro del contenedor de Linux que se usa para ejecutar aplicaciones de Python. - El plan de tarifa B_Gen5_1 (Básico, Gen5 y 1 núcleo) que se usa aquí es el menos costoso. En el caso de las bases de datos de producción, omita el argumento
--sku-namepara usar el nivel GP_Gen5_2 (De uso general, gen. 5, 2 núcleos) en su lugar.
Este comando realiza las siguientes acciones, que pueden tardar algunos minutos:
- Crea un grupo de recursos denominado
DjangoPostgres-tutorial-rg, si aún no existe. - Cree un servidor Postgres y asigne el nombre con el argumento
--server-name. - Cree una cuenta de administrador con los argumentos
--admin-usery--admin-password. Puede omitir estos argumentos para permitir que el comando genere automáticamente unas credenciales únicas. - Cree la base de datos
pollsdby asigne el nombre con el argumento--database-name. - Habilita el acceso desde la dirección IP local.
- Habilita el acceso desde servicios de Azure.
- Crea un usuario de base de datos con acceso a la base de datos
pollsdb.
Puede realizar todos los pasos por separado con otros comandos az postgres y psql, pero az postgres up realiza todos los pasos juntos.
Cuando el comando se completa, genera un objeto JSON que contiene cadenas de conexión diferentes para la base de datos, junto con la dirección URL del servidor, un nombre de usuario generado (como "joyfulKoala@msdocs-djangodb-12345") y una contraseña de GUID. Copie el nombre de usuario y la contraseña en un archivo de texto temporal, ya que los necesitará más adelante en este tutorial.
Sugerencia
-l <location-name>, se puede establecer en cualquiera de las regiones de Azure. Puede obtener las regiones disponibles para su suscripción con el comando az account list-locations. En el caso de las aplicaciones de producción, coloque la base de datos y la aplicación en la misma ubicación.
Habilite el almacenamiento en caché de parámetros con la CLI de Azure para que no sea necesario proporcionar esos parámetros con cada comando. (Los valores almacenados en caché se guardan en la carpeta .azure).
az config param-persist onCree un grupo de recursos (puede cambiarle el nombre, si lo desea). El nombre del grupo de recursos se almacena en caché y se aplica automáticamente a los comandos posteriores.
az group create --name Python-Django-PGFlex-rg --location centralusCree el servidor de bases de datos (el proceso tarda unos minutos):
az postgres flexible-server create --sku-name Standard_B1ms --public-access allSi no se reconoce el comando
az, asegúrese de que tiene instalada la CLI de Azure tal y como se describe en Configuración del entorno inicial.El comando az postgres flexible-server create realiza las siguientes acciones, que pueden tardar unos minutos:
- Cree un grupo de recursos predeterminado si aún no hay un nombre almacenado en caché.
- Cree un servidor flexible de PostgreSQL:
- De forma predeterminada, el comando usa un nombre generado tipo
server383813186. Puede especificar su propio nombre con el parámetro--name. El nombre debe ser único en todo Azure. - El comando usa el plan de tarifa
Standard_B1msde menor costo. Omita el argumento--sku-namepara usar el nivelStandard_D2s_v3predeterminado. - El comando usa el grupo de recursos y la ubicación almacenados en caché del comando
az group createanterior, que en este ejemplo es el grupo de recursosPython-Django-PGFlex-rgde la regióncentralus.
- De forma predeterminada, el comando usa un nombre generado tipo
- Cree una cuenta de administrador con nombre de usuario y contraseña. Puede especificar estos valores directamente con los parámetros
--admin-usery--admin-password. - Cree una base de datos que se llama
flexibleserverdbde manera predeterminada. Puede especificar otro nombre de base de datos con el parámetro--database-name. - Habilite el acceso público completo, que puede controlar mediante el parámetro
--public-access.
Cuando se complete el comando, copie la salida JSON del comando en un archivo, ya que necesita valores de la salida más adelante en este tutorial, específicamente el host, el nombre de usuario y la contraseña, junto con el nombre de la base de datos.
¿Tiene problemas? Póngase en contacto con nosotros.
4. Implementación del código en Azure App Service
En esta sección, creará un host de aplicación en la aplicación de App Service, conectará esta aplicación a la base de datos de Postgres y, a continuación, implementará el código en ese host.
4.1 Creación de la aplicación de App Service
En el terminal, asegúrese de estar en la carpeta del repositorio djangoapp que contiene el código de la aplicación.
Cree una aplicación de App Service (el proceso de host) con el comando az webapp up:
az webapp up --resource-group DjangoPostgres-tutorial-rg --location centralus --plan DjangoPostgres-tutorial-plan --sku B1 --name <app-name>
- Para el argumento
--location, use la misma ubicación que usó para la base de datos en la sección anterior. - Reemplace <app-name> por un nombre que sea único en Azure (el punto de conexión del servidor es
https://<app-name>.azurewebsites.net). Los caracteres permitidos para <app-name> sonA-Z,0-9y-. Un buen patrón es usar una combinación del nombre de la empresa y un identificador de la aplicación.
Este comando realiza las siguientes acciones, que pueden tardar algunos minutos:
- Cree el grupo de recursos si todavía no existe. (En este comando se usa el mismo grupo de recursos en el que se creó la base de datos anterior).
- Cree el plan de App Service DjangoPostgres-tutorial-plan en el plan de tarifa Básico (B1), si no existe.
--plany--skuson opcionales. - Cree la aplicación de App Service, si no existe.
- Habilite el registro predeterminado de la aplicación, si aún no está habilitado.
- Cargue el repositorio mediante la implementación del archivo ZIP con la automatización de compilación habilitada.
- Almacenar en caché los parámetros comunes, como el nombre del grupo de recursos y el plan de App Service, mediante el archivo .azure/config. Como consecuencia, no es necesario especificar el mismo parámetro con comandos posteriores. Por ejemplo, para volver a implementar la aplicación después de realizar cambios, puede ejecutar
az webapp upde nuevo sin ningún parámetro. Sin embargo, los comandos que proceden de extensiones de la CLI, comoaz postgres up, no usan la memoria caché en este momento, por lo que es necesario especificar aquí el grupo de recursos y la ubicación, con el uso inicial deaz webapp up.
En el terminal, asegúrese de estar en la carpeta del repositorio djangoapp que contiene el código de la aplicación.
Cambie a la rama
flexible-serverde la aplicación de ejemplo. Esta rama contiene la configuración específica necesaria para el servidor flexible de PostgreSQL:git checkout flexible-serverEjecute el siguiente comando
az webapp uppara crear el host de App Service para la aplicación:az webapp up --name <app-name> --sku B1Este comando realiza las siguientes acciones, que pueden tardar unos minutos, para lo que usa el grupo de recursos y la ubicación almacenados en caché del comando
az group createanterior (el grupoPython-Django-PGFlex-rgde la regióncentralusen este ejemplo).- Cree un plan de App Service en el plan de tarifa Básico (B1). Puede omitir
--skupara usar los valores predeterminados. - Cree la aplicación de App Service.
- Habilite el registro predeterminado para la aplicación.
- Cargue el repositorio mediante la implementación del archivo ZIP con la automatización de compilación habilitada.
- Cree un plan de App Service en el plan de tarifa Básico (B1). Puede omitir
Tras una implementación correcta, el comando genera la salida JSON como en el ejemplo siguiente:

¿Tiene problemas? Consulte primero la Guía de solución de problemas y, si eso no funciona, háganoslo saber.
4.2 Configuración de variables de entorno para conectar la base de datos
Con el código ahora implementado en App Service, el paso siguiente consiste en conectar la aplicación a la base de datos de Postgres en Azure.
El código de la aplicación espera encontrar la información de la base de datos en cuatro variables de entorno llamadas DBHOST, DBNAME, DBUSER y DBPASS.
Para establecer variables de entorno en App Service, cree "valores de aplicación" mediante el comando az webapp config appsettings set siguiente.
az webapp config appsettings set --settings DBHOST="<postgres-server-name>" DBUSER="<username>" DBPASS="<password>" DBNAME="pollsdb"
- Reemplace <postgres-server-name> por el nombre que usó anteriormente con el comando
az postgres up. El código de azuresite/production.py anexa automáticamente.postgres.database.azure.compara crear la dirección URL completa del servidor Postgres. - Reemplace <username> y <password> por las credenciales de administrador que usó con el comando
az postgres upanterior, o por las que generó automáticamente el comandoaz postgres up. El código de azuresite/production.py construye automáticamente el nombre de usuario de Postgres completo a partir deDBUSERyDBHOST, así que no incluya la parte@server. (Además, como se indicó anteriormente, no debe usar el carácter$en ninguno de los dos valores, ya que tiene un significado especial para las variables de entorno de Linux). - El grupo de recursos y el nombre de la aplicación se extraen de los valores almacenados en caché en el archivo .azure/config.
az webapp config appsettings set --settings DBHOST="<host>" DBUSER="<username>" DBPASS="<password>" DBNAME="flexibleserverdb"
Reemplace los valores de host, nombre de usuario y contraseña por los de la salida del comando az postgres flexible-server create anterior. El host debe ser una dirección URL, tipo server383813186.postgres.database.azure.com.
Reemplace también flexibleserverdb por el nombre de la base de datos si lo cambió con el comando az postgres flexible-server create.
En el código de Python, tiene acceso a esta configuración como variables de entorno con instrucciones como os.environ.get('DBHOST'). Para obtener más información, consulte Acceso a variables de entorno.
¿Tiene problemas? Consulte primero la Guía de solución de problemas y, si eso no funciona, háganoslo saber.
4.3 Ejecución de migraciones de la base de datos de Django
Las migraciones de bases de datos de Django aseguran que el esquema de la base de datos de PostgreSQL en Azure coincida con las descritas en el código.
Ejecute
az webpp sshpara abrir una sesión SSH para la aplicación web en el explorador:az webapp sshSi no puede conectarse a la sesión SSH, significa que no se pudo iniciar la propia aplicación. Compruebe los registros de diagnóstico para más información. Por ejemplo, si no ha creado la configuración de la aplicación necesaria en la sección anterior, los registros indicarán
KeyError: 'DBNAME'.En la sesión de SSH, ejecute los siguientes comandos (puede pegar los comandos con CTRL+Mayús+V):
# Run database migrations python manage.py migrate # Create the super user (follow prompts) python manage.py createsuperuserSi encuentra algún error relacionado con la conexión a la base de datos, compruebe los valores de la configuración de la aplicación creada en la sección anterior.
El comando
createsuperuserle pide las credenciales de superusuario. A los efectos de este tutorial, use el nombre de usuario predeterminadoroot, presione ENTRAR en la dirección de correo electrónico para que quede en blanco y escribaPollsdb1como contraseña.Si aparece un error que indica que la base de datos está bloqueada, asegúrese de haber ejecutado el comando
az webapp settingsen la sección anterior. Sin esa configuración, el comando Migrate no se puede comunicar con la base de datos, y esto provoca el error.
¿Tiene problemas? Consulte primero la Guía de solución de problemas y, si eso no funciona, háganoslo saber.
4.4 Creación de una pregunta de sondeo en la aplicación
Abra el sitio web de la aplicación. La aplicación debe mostrar los mensajes "Polls app" (Aplicación de sondeos) y "No polls are available" (No hay sondeos disponibles) porque todavía no hay sondeos específicos en la base de datos.
az webapp browseSi ve el mensaje "Application Error" (Error de aplicación), es probable que no haya creado la configuración necesaria en el paso anterior, Configuración de las variables de entorno para conectarse a la base de datos, o que dichos valores contengan errores. Ejecute el comando
az webapp config appsettings listpara comprobar la configuración. También puede comprobar los registros de diagnóstico para ver errores específicos durante el inicio de la aplicación. Por ejemplo, si no ha creado la configuración, los registros mostrarán el errorKeyError: 'DBNAME'.Después de actualizar la configuración para corregir los errores, espere un minuto para que la aplicación se reinicie y, después, actualice el explorador.
Vaya a la página de administración de la aplicación web; para ello, anexe
/admina la dirección URL, como enhttp://<app-name>.azurewebsites.net/admin. Inicie sesión con las credenciales de superusuario de Django de la sección anterior (rootyPollsdb1). En Polls (Sondeos), seleccione Add (Agregar) junto a Questions (Preguntas) y cree una pregunta de sondeo con algunas opciones.Vuelva al sitio web principal (
http://<app-name>.azurewebsites.net) para confirmar que las preguntas se presentan ahora al usuario. Responda a las preguntas como desee para generar algunos datos en la base de datos.
¡Enhorabuena! Está ejecutando una aplicación web de Django de Python en Azure App Service para Linux, con una base de datos de Postgres activa.
¿Tiene problemas? Póngase en contacto con nosotros.
Nota
App Service detecta un proyecto de Django mediante la búsqueda de un archivo wsgi.py en cada subcarpeta, que manage.py startproject crea de forma predeterminada. Cuando App Service encuentra ese archivo, carga la aplicación web de Django. Para obtener más información, consulte Configuración de una imagen de Python integrada.
5. Cambios en el código y reimplementación
En esta sección, realizará cambios locales en la aplicación y volverá a implementar el código en App Service. En el proceso, se configura un entorno virtual de Python que admite el trabajo en curso.
5.1 Ejecución de la aplicación de forma local
Ejecute los siguientes comandos en una ventana de terminal. Asegúrese de seguir las indicaciones al crear el superusuario:
# Configure the Python virtual environment
python3 -m venv venv
source venv/bin/activate
# Install dependencies
pip install -r requirements.txt
# Run Django migrations
python manage.py migrate
# Create Django superuser (follow prompts)
python manage.py createsuperuser
# Run the dev server
python manage.py runserver
Una vez que la aplicación web esté completamente cargada, el servidor de desarrollo de Django proporcionará la dirección URL de la aplicación local en el mensaje "Starting development server at http://127.0.0.1:8000/. Quit the server with CTRL-BREAK" (Iniciando el servidor de desarrollo en https… Salga del servidor con Ctrl+Interrumpir).

Pruebe la aplicación localmente con los pasos siguientes:
Vaya a
http://localhost:8000en un explorador, que debería mostrar un mensaje que indica que no hay sondeos disponibles.Vaya a
http://localhost:8000/admine inicie sesión con el usuario administrador que creó previamente. En Sondeos, vuelva a seleccionar Agregar junto a Preguntas y cree una pregunta de sondeo con opciones.Vaya a
http://localhost:8000de nuevo y responda a la pregunta para probar la aplicación.Detenga el servidor de Django presionando CTRL+C.
Cuando se ejecute localmente, la aplicación usará una base de datos de Sqlite3 local y no interferirá con la base de datos de producción. También puede usar una base de datos de PostgreSQL local, si lo desea, para simular mejor el entorno de producción.
¿Tiene problemas? Póngase en contacto con nosotros.
5.2 Actualización de la aplicación
En polls/models.py, busque la línea que comienza con choice_text y cambie el parámetro max_length a 100:
# Find this line of code and set max_length to 100 instead of 200
choice_text = models.CharField(max_length=100)
Dado que ha cambiado el modelo de datos, cree una nueva migración de Django y migre la base de datos:
python manage.py makemigrations
python manage.py migrate
Vuelva a ejecutar el servidor de desarrollo con python manage.py runserver y pruebe la aplicación en http://localhost:8000/admin:
Vuelva a detener el servidor web de Django con CTRL+C.
¿Tiene problemas? Consulte primero la Guía de solución de problemas y, si eso no funciona, háganoslo saber.
5.3 Nueva implementación del código en Azure
Ejecute el comando siguiente en la raíz del repositorio:
az webapp up
Este comando usa los parámetros almacenados en la memoria caché del archivo .azure/config. Dado que App Service detecta que la aplicación ya existe, simplemente vuelve a implementar el código.
¿Tiene problemas? Consulte primero la Guía de solución de problemas y, si eso no funciona, háganoslo saber.
5.4 Nueva ejecución de migraciones en Azure
Dado que ha realizado cambios en el modelo de datos, debe volver a ejecutar las migraciones de base de datos en App Service.
Abra una sesión de SSH de nuevo en el explorador. Para ello, vaya a https://<app-name>.scm.azurewebsites.net/webssh/host. Luego, ejecute el siguiente comando:
python manage.py migrate
¿Tiene problemas? Consulte primero la Guía de solución de problemas y, si eso no funciona, háganoslo saber.
5.5 Revisión de la aplicación en producción
Vaya a la aplicación de nuevo (con az webapp browse o vaya a http://<app-name>.azurewebsites.net) y vuelva a probar la aplicación en producción. (Dado que solo ha cambiado la longitud de un campo de la base de datos, el cambio solo se aprecia si intenta especificar una respuesta más larga al crear una pregunta).
¿Tiene problemas? Consulte primero la Guía de solución de problemas y, si eso no funciona, háganoslo saber.
6. Transmisión de registros de diagnóstico
Puede acceder a los registros de la consola generados desde dentro del contenedor que hospeda la aplicación en Azure.
Ejecute el siguiente comando de la CLI de Azure para ver la secuencia de registro. Este comando usa los parámetros almacenados en la memoria caché del archivo .azure/config.
az webapp log tail
Si no ve los registros de la consola de inmediato, vuelve a comprobarlo en 30 segundos.
Para detener el streaming de registro en cualquier momento, escriba Ctrl+C.
¿Tiene problemas? Póngase en contacto con nosotros.
Nota
También puede inspeccionar los archivos de registro desde el explorador en https://<app-name>.scm.azurewebsites.net/api/logs/docker.
az webapp up activa el registro predeterminado. Por motivos de rendimiento, este registro se desactiva después de un tiempo, pero vuelve a activarse cada vez que se vuelve a ejecutar az webapp up. Para activarlo manualmente, ejecute el siguiente comando:
az webapp log config --docker-container-logging filesystem
7. Administración de una aplicación en Azure Portal
En Azure Portal, busque el nombre de la aplicación y seleccione la aplicación en los resultados.

De forma predeterminada, el portal muestra la página Información general de la aplicación, que proporciona una vista del rendimiento general. En ella puede también realizar tareas de administración básicas como examinar, detener, reiniciar y eliminar. Las pestañas del lado izquierdo de la página muestran las diferentes páginas de configuración que puede abrir.

¿Tiene problemas? Consulte primero la Guía de solución de problemas y, si eso no funciona, háganoslo saber.
8. Limpieza de recursos
Si desea mantener la aplicación o continuar con los tutoriales adicionales, vaya a Pasos siguientes. De lo contrario, para evitar incurrir en cargos adicionales, puede eliminar la creación del grupo de recursos para este tutorial:
az group delete --name Python-Django-PGFlex-rg --no-wait
Al eliminar el grupo de recursos, también se desasignan y eliminan todos los recursos que contiene. Asegúrese de que ya no necesita los recursos del grupo antes de usar el comando.
La eliminación de todos los recursos puede llevar tiempo. El argumento --no-wait permite que el comando devuelva resultados inmediatamente.
¿Tiene problemas? Póngase en contacto con nosotros.
Pasos siguientes
Obtenga información sobre cómo asignar un nombre DNS personalizado a la aplicación:
Obtenga información sobre cómo App Service ejecuta una aplicación de Python: