Corrección importación CSV, robustez en restore_feeds y scripts de instalación para PostgreSQL
This commit is contained in:
parent
72dd972352
commit
0442d3fc0e
6 changed files with 119 additions and 68 deletions
54
app.py
54
app.py
|
|
@ -1,11 +1,7 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""Flask RSS aggregator — versión PostgreSQL
|
"""Flask RSS aggregator — versión PostgreSQL
|
||||||
|
|
||||||
Cambios principales respecto al original (MySQL):
|
(Copyright tuyo 😉, soporte robusto de importación desde CSV)
|
||||||
- mysql.connector → psycopg2
|
|
||||||
- DB_CONFIG con claves PostgreSQL
|
|
||||||
- Función auxiliar get_conn() para abrir conexiones
|
|
||||||
- Reemplazo de INSERT IGNORE / ON DUPLICATE KEY UPDATE por ON CONFLICT
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from flask import Flask, render_template, request, redirect, url_for, Response
|
from flask import Flask, render_template, request, redirect, url_for, Response
|
||||||
|
|
@ -32,12 +28,10 @@ DB_CONFIG = {
|
||||||
"password": "x",
|
"password": "x",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def get_conn():
|
def get_conn():
|
||||||
"""Devuelve una conexión nueva usando psycopg2 y el diccionario DB_CONFIG."""
|
"""Devuelve una conexión nueva usando psycopg2 y el diccionario DB_CONFIG."""
|
||||||
return psycopg2.connect(**DB_CONFIG)
|
return psycopg2.connect(**DB_CONFIG)
|
||||||
|
|
||||||
|
|
||||||
MAX_FALLOS = 5 # Número máximo de fallos antes de desactivar el feed
|
MAX_FALLOS = 5 # Número máximo de fallos antes de desactivar el feed
|
||||||
|
|
||||||
# ======================================
|
# ======================================
|
||||||
|
|
@ -109,7 +103,6 @@ def home():
|
||||||
pais_id=int(pais_id) if pais_id else None,
|
pais_id=int(pais_id) if pais_id else None,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# ======================================
|
# ======================================
|
||||||
# Gestión de feeds en /feeds
|
# Gestión de feeds en /feeds
|
||||||
# ======================================
|
# ======================================
|
||||||
|
|
@ -152,7 +145,6 @@ def feeds():
|
||||||
paises=paises,
|
paises=paises,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# Añadir feed
|
# Añadir feed
|
||||||
@app.route("/add", methods=["POST"])
|
@app.route("/add", methods=["POST"])
|
||||||
def add_feed():
|
def add_feed():
|
||||||
|
|
@ -180,7 +172,6 @@ def add_feed():
|
||||||
conn.close()
|
conn.close()
|
||||||
return redirect(url_for("feeds"))
|
return redirect(url_for("feeds"))
|
||||||
|
|
||||||
|
|
||||||
# Editar feed
|
# Editar feed
|
||||||
@app.route("/edit/<int:feed_id>", methods=["GET", "POST"])
|
@app.route("/edit/<int:feed_id>", methods=["GET", "POST"])
|
||||||
def edit_feed(feed_id):
|
def edit_feed(feed_id):
|
||||||
|
|
@ -230,7 +221,6 @@ def edit_feed(feed_id):
|
||||||
conn.close()
|
conn.close()
|
||||||
return render_template("edit_feed.html", feed=feed, categorias=categorias, paises=paises)
|
return render_template("edit_feed.html", feed=feed, categorias=categorias, paises=paises)
|
||||||
|
|
||||||
|
|
||||||
# Eliminar feed
|
# Eliminar feed
|
||||||
@app.route("/delete/<int:feed_id>")
|
@app.route("/delete/<int:feed_id>")
|
||||||
def delete_feed(feed_id):
|
def delete_feed(feed_id):
|
||||||
|
|
@ -247,7 +237,6 @@ def delete_feed(feed_id):
|
||||||
conn.close()
|
conn.close()
|
||||||
return redirect(url_for("feeds"))
|
return redirect(url_for("feeds"))
|
||||||
|
|
||||||
|
|
||||||
# Backup de feeds a CSV
|
# Backup de feeds a CSV
|
||||||
@app.route("/backup_feeds")
|
@app.route("/backup_feeds")
|
||||||
def backup_feeds():
|
def backup_feeds():
|
||||||
|
|
@ -285,8 +274,7 @@ def backup_feeds():
|
||||||
headers={"Content-Disposition": "attachment;filename=feeds_backup.csv"},
|
headers={"Content-Disposition": "attachment;filename=feeds_backup.csv"},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Restaurar feeds desde CSV (robusto: bool/int/None/códigos)
|
||||||
# Restaurar feeds desde CSV
|
|
||||||
@app.route("/restore_feeds", methods=["GET", "POST"])
|
@app.route("/restore_feeds", methods=["GET", "POST"])
|
||||||
def restore_feeds():
|
def restore_feeds():
|
||||||
msg = ""
|
msg = ""
|
||||||
|
|
@ -301,8 +289,23 @@ def restore_feeds():
|
||||||
conn = get_conn()
|
conn = get_conn()
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
n_ok = 0
|
n_ok = 0
|
||||||
for row in rows:
|
msg_lines = []
|
||||||
|
for i, row in enumerate(rows, 1):
|
||||||
try:
|
try:
|
||||||
|
# -- robusto para activo (admite True/False/1/0/t/f/yes/no/vacío)
|
||||||
|
activo_val = str(row.get("activo", "")).strip().lower()
|
||||||
|
if activo_val in ["1", "true", "t", "yes"]:
|
||||||
|
activo = True
|
||||||
|
elif activo_val in ["0", "false", "f", "no"]:
|
||||||
|
activo = False
|
||||||
|
else:
|
||||||
|
activo = True # valor por defecto
|
||||||
|
|
||||||
|
idioma = row.get("idioma", None)
|
||||||
|
idioma = idioma.strip() if idioma else None
|
||||||
|
if idioma == "":
|
||||||
|
idioma = None
|
||||||
|
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"""
|
"""
|
||||||
INSERT INTO feeds (
|
INSERT INTO feeds (
|
||||||
|
|
@ -320,35 +323,35 @@ def restore_feeds():
|
||||||
fallos = EXCLUDED.fallos;
|
fallos = EXCLUDED.fallos;
|
||||||
""",
|
""",
|
||||||
{
|
{
|
||||||
"id": row.get("id"),
|
"id": int(row.get("id")),
|
||||||
"nombre": row["nombre"],
|
"nombre": row["nombre"],
|
||||||
"descripcion": row.get("descripcion") or "",
|
"descripcion": row.get("descripcion") or "",
|
||||||
"url": row["url"],
|
"url": row["url"],
|
||||||
"categoria_id": row["categoria_id"],
|
"categoria_id": int(row["categoria_id"]) if row["categoria_id"] else None,
|
||||||
"pais_id": row["pais_id"],
|
"pais_id": int(row["pais_id"]) if row["pais_id"] else None,
|
||||||
"idioma": row.get("idioma"),
|
"idioma": idioma,
|
||||||
"activo": bool(int(row["activo"])),
|
"activo": activo,
|
||||||
"fallos": int(row.get("fallos", 0)),
|
"fallos": int(row.get("fallos", 0)),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
n_ok += 1
|
n_ok += 1
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
app.logger.error(f"Error insertando feed {row}: {e}")
|
app.logger.error(f"Error insertando feed fila {i}: {e}")
|
||||||
|
msg_lines.append(f"Error en fila {i}: {e}")
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
msg = f"Feeds restaurados correctamente: {n_ok}"
|
msg = f"Feeds restaurados correctamente: {n_ok}"
|
||||||
|
if msg_lines:
|
||||||
|
msg += "<br>" + "<br>".join(msg_lines)
|
||||||
return render_template("restore_feeds.html", msg=msg)
|
return render_template("restore_feeds.html", msg=msg)
|
||||||
|
|
||||||
|
|
||||||
@app.route("/noticias")
|
@app.route("/noticias")
|
||||||
def show_noticias():
|
def show_noticias():
|
||||||
return home()
|
return home()
|
||||||
|
|
||||||
|
|
||||||
# ================================
|
# ================================
|
||||||
# Lógica de procesado de feeds con control de fallos
|
# Lógica de procesado de feeds con control de fallos
|
||||||
# ================================
|
# ================================
|
||||||
|
|
||||||
def sumar_fallo_feed(cursor, feed_id):
|
def sumar_fallo_feed(cursor, feed_id):
|
||||||
cursor.execute("UPDATE feeds SET fallos = fallos + 1 WHERE id = %s", (feed_id,))
|
cursor.execute("UPDATE feeds SET fallos = fallos + 1 WHERE id = %s", (feed_id,))
|
||||||
cursor.execute("SELECT fallos FROM feeds WHERE id = %s", (feed_id,))
|
cursor.execute("SELECT fallos FROM feeds WHERE id = %s", (feed_id,))
|
||||||
|
|
@ -357,11 +360,9 @@ def sumar_fallo_feed(cursor, feed_id):
|
||||||
cursor.execute("UPDATE feeds SET activo = FALSE WHERE id = %s", (feed_id,))
|
cursor.execute("UPDATE feeds SET activo = FALSE WHERE id = %s", (feed_id,))
|
||||||
return fallos
|
return fallos
|
||||||
|
|
||||||
|
|
||||||
def resetear_fallos_feed(cursor, feed_id):
|
def resetear_fallos_feed(cursor, feed_id):
|
||||||
cursor.execute("UPDATE feeds SET fallos = 0 WHERE id = %s", (feed_id,))
|
cursor.execute("UPDATE feeds SET fallos = 0 WHERE id = %s", (feed_id,))
|
||||||
|
|
||||||
|
|
||||||
def fetch_and_store():
|
def fetch_and_store():
|
||||||
conn = None
|
conn = None
|
||||||
try:
|
try:
|
||||||
|
|
@ -459,7 +460,6 @@ def fetch_and_store():
|
||||||
conn.close()
|
conn.close()
|
||||||
app.logger.info(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] Feeds procesados.")
|
app.logger.info(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] Feeds procesados.")
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Lanzador de la aplicación + scheduler
|
# Lanzador de la aplicación + scheduler
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
INSERT IGNORE INTO categorias_estandar (nombre) VALUES
|
INSERT INTO categorias (nombre) VALUES
|
||||||
('Ciencia'),
|
('Ciencia'),
|
||||||
('Cultura'),
|
('Cultura'),
|
||||||
('Deportes'),
|
('Deportes'),
|
||||||
|
|
@ -13,5 +13,6 @@ INSERT IGNORE INTO categorias_estandar (nombre) VALUES
|
||||||
('Salud'),
|
('Salud'),
|
||||||
('Sociedad'),
|
('Sociedad'),
|
||||||
('Tecnología'),
|
('Tecnología'),
|
||||||
('Viajes');
|
('Viajes')
|
||||||
|
ON CONFLICT DO NOTHING;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
INSERT IGNORE INTO continentes (id, nombre) VALUES
|
INSERT INTO continentes (id, nombre) VALUES
|
||||||
(1, 'África'),
|
(1, 'África'),
|
||||||
(2, 'América'),
|
(2, 'América'),
|
||||||
(3, 'Asia'),
|
(3, 'Asia'),
|
||||||
(4, 'Europa'),
|
(4, 'Europa'),
|
||||||
(5, 'Oceanía'),
|
(5, 'Oceanía'),
|
||||||
(6, 'Antártida');
|
(6, 'Antártida')
|
||||||
|
ON CONFLICT (id) DO NOTHING;
|
||||||
|
|
||||||
|
|
|
||||||
107
install.sh
107
install.sh
|
|
@ -1,62 +1,103 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
# ========= CONFIGURACIÓN =========
|
# ========= CONFIGURACIÓN =========
|
||||||
APP_NAME="rss"
|
APP_NAME="rss"
|
||||||
USER=$(whoami)
|
APP_DIR="$(cd "$(dirname "$0")" && pwd)" # SIEMPRE el directorio del script
|
||||||
APP_DIR="/home/$USER/rss"
|
|
||||||
PYTHON_ENV="$APP_DIR/venv"
|
PYTHON_ENV="$APP_DIR/venv"
|
||||||
SERVICE_FILE="/etc/systemd/system/$APP_NAME.service"
|
SERVICE_FILE="/etc/systemd/system/$APP_NAME.service"
|
||||||
FLASK_FILE="app.py"
|
FLASK_FILE="app.py"
|
||||||
|
|
||||||
DB_NAME="noticiasrss"
|
DB_NAME="rss"
|
||||||
MYSQL_USER="root"
|
DB_USER="rss"
|
||||||
|
DB_PASS="x"
|
||||||
|
|
||||||
# ========= PEDIR CONTRASEÑA MYSQL =========
|
# ========= INSTALAR POSTGRESQL (ÚLTIMA VERSIÓN RECOMENDADA) =========
|
||||||
read -s -p "Introduce la contraseña MySQL para '$MYSQL_USER': " MYSQL_PASS
|
echo "🟢 Instalando PostgreSQL (repositorio oficial)..."
|
||||||
echo
|
sudo apt update
|
||||||
|
sudo apt install -y wget ca-certificates
|
||||||
|
|
||||||
# ========= BASE DE DATOS Y TABLAS =========
|
# Añade el repositorio oficial de PostgreSQL (ajusta para tu distro si hace falta)
|
||||||
echo "🛠️ Verificando/creando base de datos '$DB_NAME'..."
|
echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" | sudo tee /etc/apt/sources.list.d/pgdg.list
|
||||||
mysql -u"$MYSQL_USER" -p"$MYSQL_PASS" -e "CREATE DATABASE IF NOT EXISTS $DB_NAME DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
|
wget -qO - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install -y postgresql postgresql-contrib
|
||||||
|
|
||||||
echo "📐 Verificando tablas necesarias..."
|
# ========= CAMBIAR AUTENTICACIÓN DE peer A md5 =========
|
||||||
mysql -u"$MYSQL_USER" -p"$MYSQL_PASS" "$DB_NAME" <<EOF
|
PG_HBA=$(find /etc/postgresql -name pg_hba.conf | head -1)
|
||||||
|
if grep -q "local\s\+all\s\+all\s\+peer" "$PG_HBA"; then
|
||||||
|
echo "📝 Ajustando pg_hba.conf para autenticación md5 (contraseña)..."
|
||||||
|
sudo sed -i 's/local\s\+all\s\+all\s\+peer/local all all md5/' "$PG_HBA"
|
||||||
|
sudo systemctl restart postgresql
|
||||||
|
else
|
||||||
|
echo "✅ pg_hba.conf ya configurado para md5."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ========= CONFIGURAR BASE DE DATOS Y USUARIO =========
|
||||||
|
echo "🛠️ Configurando PostgreSQL: usuario y base de datos..."
|
||||||
|
|
||||||
|
sudo -u postgres psql <<EOF
|
||||||
|
DO \$\$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (
|
||||||
|
SELECT FROM pg_catalog.pg_user WHERE usename = '$DB_USER'
|
||||||
|
) THEN
|
||||||
|
CREATE USER $DB_USER WITH PASSWORD '$DB_PASS';
|
||||||
|
END IF;
|
||||||
|
END
|
||||||
|
\$\$;
|
||||||
|
|
||||||
|
CREATE DATABASE $DB_NAME OWNER $DB_USER;
|
||||||
|
GRANT ALL PRIVILEGES ON DATABASE $DB_NAME TO $DB_USER;
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# ========= CREAR TABLAS =========
|
||||||
|
echo "📐 Creando tablas en PostgreSQL..."
|
||||||
|
|
||||||
|
export PGPASSWORD="$DB_PASS"
|
||||||
|
psql -U "$DB_USER" -h localhost -d "$DB_NAME" <<EOF
|
||||||
CREATE TABLE IF NOT EXISTS continentes (
|
CREATE TABLE IF NOT EXISTS continentes (
|
||||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
nombre VARCHAR(255)
|
nombre VARCHAR(50) NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS categorias_estandar (
|
CREATE TABLE IF NOT EXISTS categorias (
|
||||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
nombre VARCHAR(255)
|
nombre VARCHAR(100) NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS paises (
|
CREATE TABLE IF NOT EXISTS paises (
|
||||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
nombre VARCHAR(255),
|
nombre VARCHAR(100) NOT NULL,
|
||||||
continente_id INT
|
continente_id INTEGER REFERENCES continentes(id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS feeds (
|
CREATE TABLE IF NOT EXISTS feeds (
|
||||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
nombre VARCHAR(255),
|
nombre VARCHAR(255),
|
||||||
url TEXT,
|
descripcion TEXT,
|
||||||
categoria_id INT,
|
url TEXT NOT NULL,
|
||||||
pais_id INT,
|
categoria_id INTEGER REFERENCES categorias(id),
|
||||||
activo BOOLEAN DEFAULT TRUE
|
pais_id INTEGER REFERENCES paises(id),
|
||||||
|
idioma CHAR(2),
|
||||||
|
activo BOOLEAN DEFAULT TRUE,
|
||||||
|
fallos INTEGER DEFAULT 0,
|
||||||
|
CONSTRAINT feeds_idioma_chk CHECK (idioma ~* '^[a-z]{2}$' OR idioma IS NULL)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS noticias (
|
CREATE TABLE IF NOT EXISTS noticias (
|
||||||
id CHAR(32) PRIMARY KEY,
|
id VARCHAR(32) PRIMARY KEY,
|
||||||
titulo TEXT,
|
titulo TEXT,
|
||||||
resumen TEXT,
|
resumen TEXT,
|
||||||
url TEXT,
|
url TEXT,
|
||||||
fecha DATETIME,
|
fecha TIMESTAMP,
|
||||||
imagen_url TEXT,
|
imagen_url TEXT,
|
||||||
categoria_id INT,
|
categoria_id INTEGER REFERENCES categorias(id),
|
||||||
pais_id INT
|
pais_id INTEGER REFERENCES paises(id)
|
||||||
);
|
);
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
echo "✅ Tablas creadas/verificadas correctamente."
|
echo "✅ Tablas creadas/verificadas correctamente."
|
||||||
|
|
||||||
# ========= DATOS INICIALES =========
|
# ========= DATOS INICIALES =========
|
||||||
|
|
@ -64,7 +105,7 @@ echo "✅ Tablas creadas/verificadas correctamente."
|
||||||
# Continentes
|
# Continentes
|
||||||
if [ -f "$APP_DIR/continentes.sql" ]; then
|
if [ -f "$APP_DIR/continentes.sql" ]; then
|
||||||
echo "🌎 Insertando continentes..."
|
echo "🌎 Insertando continentes..."
|
||||||
mysql -u"$MYSQL_USER" -p"$MYSQL_PASS" "$DB_NAME" < "$APP_DIR/continentes.sql"
|
psql -U "$DB_USER" -h localhost -d "$DB_NAME" -f "$APP_DIR/continentes.sql"
|
||||||
else
|
else
|
||||||
echo "⚠️ No se encontró $APP_DIR/continentes.sql"
|
echo "⚠️ No se encontró $APP_DIR/continentes.sql"
|
||||||
fi
|
fi
|
||||||
|
|
@ -72,7 +113,7 @@ fi
|
||||||
# Países
|
# Países
|
||||||
if [ -f "$APP_DIR/paises.sql" ]; then
|
if [ -f "$APP_DIR/paises.sql" ]; then
|
||||||
echo "🌐 Insertando países..."
|
echo "🌐 Insertando países..."
|
||||||
mysql -u"$MYSQL_USER" -p"$MYSQL_PASS" "$DB_NAME" < "$APP_DIR/paises.sql"
|
psql -U "$DB_USER" -h localhost -d "$DB_NAME" -f "$APP_DIR/paises.sql"
|
||||||
else
|
else
|
||||||
echo "⚠️ No se encontró $APP_DIR/paises.sql"
|
echo "⚠️ No se encontró $APP_DIR/paises.sql"
|
||||||
fi
|
fi
|
||||||
|
|
@ -80,7 +121,7 @@ fi
|
||||||
# Categorías
|
# Categorías
|
||||||
if [ -f "$APP_DIR/categorias.sql" ]; then
|
if [ -f "$APP_DIR/categorias.sql" ]; then
|
||||||
echo "🏷️ Insertando categorías estándar..."
|
echo "🏷️ Insertando categorías estándar..."
|
||||||
mysql -u"$MYSQL_USER" -p"$MYSQL_PASS" "$DB_NAME" < "$APP_DIR/categorias.sql"
|
psql -U "$DB_USER" -h localhost -d "$DB_NAME" -f "$APP_DIR/categorias.sql"
|
||||||
else
|
else
|
||||||
echo "⚠️ No se encontró $APP_DIR/categorias.sql"
|
echo "⚠️ No se encontró $APP_DIR/categorias.sql"
|
||||||
fi
|
fi
|
||||||
|
|
@ -118,7 +159,7 @@ echo "🔁 Recargando systemd y activando servicio"
|
||||||
sudo systemctl daemon-reexec
|
sudo systemctl daemon-reexec
|
||||||
sudo systemctl daemon-reload
|
sudo systemctl daemon-reload
|
||||||
sudo systemctl enable "$APP_NAME"
|
sudo systemctl enable "$APP_NAME"
|
||||||
sudo systemctl start "$APP_NAME"
|
sudo systemctl restart "$APP_NAME"
|
||||||
|
|
||||||
# ========= ESTADO =========
|
# ========= ESTADO =========
|
||||||
echo "✅ Servicio '$APP_NAME' instalado y funcionando."
|
echo "✅ Servicio '$APP_NAME' instalado y funcionando."
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
INSERT IGNORE INTO paises (nombre, continente_id) VALUES
|
INSERT INTO paises (nombre, continente_id) VALUES
|
||||||
('Afganistán', 3),
|
('Afganistán', 3),
|
||||||
('Albania', 4),
|
('Albania', 4),
|
||||||
('Alemania', 4),
|
('Alemania', 4),
|
||||||
|
|
@ -193,5 +193,6 @@ INSERT IGNORE INTO paises (nombre, continente_id) VALUES
|
||||||
('Yemen', 3),
|
('Yemen', 3),
|
||||||
('Yibuti', 1),
|
('Yibuti', 1),
|
||||||
('Zambia', 1),
|
('Zambia', 1),
|
||||||
('Zimbabue', 1);
|
('Zimbabue', 1)
|
||||||
|
ON CONFLICT DO NOTHING;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,11 @@
|
||||||
</form>
|
</form>
|
||||||
{% if msg %}
|
{% if msg %}
|
||||||
<div style="margin:15px 0;">
|
<div style="margin:15px 0;">
|
||||||
<strong>{{ msg }}</strong>
|
{% if "Error" in msg or "Error en fila" in msg %}
|
||||||
|
<div style="color:#c00; font-weight:bold;">{{ msg|safe }}</div>
|
||||||
|
{% else %}
|
||||||
|
<div style="color:#198754; font-weight:bold;">{{ msg|safe }}</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<p style="font-size:0.92em;color:#64748b;">
|
<p style="font-size:0.92em;color:#64748b;">
|
||||||
|
|
@ -18,9 +22,12 @@
|
||||||
<code>id, nombre, [descripcion,] url, categoria_id, categoria, pais_id, pais, idioma, activo, fallos</code><br>
|
<code>id, nombre, [descripcion,] url, categoria_id, categoria, pais_id, pais, idioma, activo, fallos</code><br>
|
||||||
<small>
|
<small>
|
||||||
Las columnas <b>descripcion</b> e <b>idioma</b> son opcionales.<br>
|
Las columnas <b>descripcion</b> e <b>idioma</b> son opcionales.<br>
|
||||||
<b>idioma</b> debe ser el código ISO 639-1 de dos letras (ej: es, en, fr...).
|
<b>activo</b> puede ser: <code>True</code>, <code>False</code>, <code>1</code> o <code>0</code>.<br>
|
||||||
|
<b>idioma</b> debe ser el código ISO 639-1 de dos letras (<i>ej:</i> <code>es</code>, <code>en</code>, <code>fr</code>...).<br>
|
||||||
|
Si falta alguna columna, la restauración puede fallar o ignorar ese campo.
|
||||||
</small>
|
</small>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<a href="/feeds" class="top-link">← Volver a feeds</a>
|
<a href="/feeds" class="top-link">← Volver a feeds</a>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue