backup Django. dgango.. dgango. django.. dgango. django. python.. dgango. django. python. искусственный интеллект.. dgango. django. python. искусственный интеллект. нейросети.. dgango. django. python. искусственный интеллект. нейросети. сайт.. dgango. django. python. искусственный интеллект. нейросети. сайт. сайтостроение.. dgango. django. python. искусственный интеллект. нейросети. сайт. сайтостроение. сайты.. dgango. django. python. искусственный интеллект. нейросети. сайт. сайтостроение. сайты. сервисы.

Короче, начал делать проект на Django с нуля, и вообще впервые с ним работаю (noob). Соответственно с нейронками в паре, так как сам в Django не особо шарю, и они делают почти всё за меня (условно). И поскольку нейросети любят переписывать код по-своему, периодически всё ломается: и код, и база, и остальная разная нечисть🌚

В итоге решил делать бэкапы вместе с нейронками — может, кому-то пригодится.

Да, я в курсе, что есть django-dbbackup, контроль версий и куча других тем, но мне пока так удобнее. Дальше — больше. Делюсь этим скорее для таких же новичков, как я. Вдруг будет полезно⤵️

import os
import shutil
import sqlite3
import datetime
import zipfile
import argparse


# === Конфигурация для бэкапа ===

# Папка, в которую будут сохраняться резервные копии
BACKUP_DIR = "backups"

# Папки, которые нужно исключить из бэкапа
# Обычно сюда попадают временные, кэшированные или неважные данные
EXCLUDE_DIRS = ['__pycache__', '.git', 'venv']  # __pycache__ — кэш Python, .git — история гита, venv — виртуальное окружение

# Отдельные файлы, которые обязательно нужно включить в бэкап
# Например, база данных SQLite и список зависимостей
INCLUDE_FILES = ['db.sqlite3', 'requirements.txt']

# Папки проекта, которые нужно включить в бэкап
# Указываем те директории, в которых находится основной код
INCLUDE_DIRS = ['telegraph', 'telegra_ph_generator']


def create_backup():
    """Создание резервной копии проекта с возможностью задать имя"""
    user_input = input("Введите название резервной копии (оставьте пустым для имени по умолчанию): ").strip()
    custom_name = user_input.strip("()") if user_input else None

    timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
    base_name = custom_name if custom_name else f"backup"
    backup_name = f"{base_name}_{timestamp}"
    backup_path = os.path.join(BACKUP_DIR, backup_name)
    os.makedirs(backup_path, exist_ok=True)

    print(f"Создание резервной копии в {backup_path}...")

    # Копируем файлы
    for item in INCLUDE_FILES:
        if os.path.exists(item):
            shutil.copy2(item, backup_path)

    # Копируем папки
    for dir_name in INCLUDE_DIRS:
        if os.path.exists(dir_name):
            shutil.copytree(
                dir_name,
                os.path.join(backup_path, dir_name),
                ignore=shutil.ignore_patterns(*EXCLUDE_DIRS)
            )

    # Дамп SQLite
    if os.path.exists('db.sqlite3'):
        db_backup_path = os.path.join(backup_path, 'db_dump.sql')
        with sqlite3.connect('db.sqlite3') as conn:
            with open(db_backup_path, 'w', encoding='utf-8') as f:
                for line in conn.iterdump():
                    f.write(f'{line}n')

    # ZIP архив
    zip_path = f"{backup_path}.zip"
    with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
        for root, dirs, files in os.walk(backup_path):
            for file in files:
                file_path = os.path.join(root, file)
                arcname = os.path.relpath(file_path, os.path.dirname(backup_path))
                zipf.write(file_path, arcname)

    shutil.rmtree(backup_path)
    print(f"✔ Резервная копия создана: {zip_path}")


def restore_backup(backup_file):
    """Восстановление проекта из резервной копии"""
    if not os.path.exists(backup_file):
        print(f"Файл {backup_file} не найден!")
        return

    print(f"Восстановление из {backup_file}...")

    # Удаляем текущие папки
    for dir_name in INCLUDE_DIRS:
        if os.path.exists(dir_name):
            shutil.rmtree(dir_name)

    # Распаковываем архив
    temp_dir = "temp_restore"
    with zipfile.ZipFile(backup_file, 'r') as zip_ref:
        zip_ref.extractall(temp_dir)

    # Определяем путь к данным
    backup_name = os.path.splitext(os.path.basename(backup_file))[0]
    source_path = os.path.join(temp_dir, backup_name)

    # Копируем файлы обратно
    for item in os.listdir(source_path):
        src = os.path.join(source_path, item)
        dst = os.path.join('.', item)
        if os.path.isdir(src):
            shutil.copytree(src, dst)
        else:
            shutil.copy2(src, dst)

    # Восстанавливаем базу данных
    db_dump = os.path.join(source_path, 'db_dump.sql')
    if os.path.exists(db_dump):
        if os.path.exists('db.sqlite3'):
            os.remove('db.sqlite3')
        with sqlite3.connect('db.sqlite3') as conn:
            with open(db_dump, 'r', encoding='utf-8') as f:
                sql = f.read()
            conn.executescript(sql)

    shutil.rmtree(temp_dir)
    print("✔ Восстановление завершено!")


def list_backups():
    """Список доступных резервных копий"""
    if not os.path.exists(BACKUP_DIR):
        print("Папка с резервными копиями пуста!")
        return

    backups = sorted(
        [f for f in os.listdir(BACKUP_DIR) if f.endswith('.zip')],
        reverse=True
    )

    if not backups:
        print("Резервные копии не найдены!")
        return

    print("📦 Доступные резервные копии:")
    for i, backup in enumerate(backups, 1):
        print(f"{i}. {backup}")


def main():
    parser = argparse.ArgumentParser(description="Резервное копирование Django-проекта")
    subparsers = parser.add_subparsers(dest='command')

    subparsers.add_parser('backup', help='Создать резервную копию')

    restore_parser = subparsers.add_parser('restore', help='Восстановить из резервной копии')
    restore_parser.add_argument('backup', nargs='?', help='Имя zip-файла резервной копии')

    subparsers.add_parser('list', help='Показать список резервных копий')

    args = parser.parse_args()

    os.makedirs(BACKUP_DIR, exist_ok=True)

    if args.command == 'backup':
        create_backup()
    elif args.command == 'restore':
        if args.backup:
            restore_backup(os.path.join(BACKUP_DIR, args.backup))
        else:
            list_backups()
            choice = input("Введите номер резервной копии для восстановления: ")
            try:
                backups = sorted(
                    [f for f in os.listdir(BACKUP_DIR) if f.endswith('.zip')],
                    reverse=True
                )
                selected = backups[int(choice) - 1]
                restore_backup(os.path.join(BACKUP_DIR, selected))
            except (IndexError, ValueError):
                print("Неверный выбор!")
    elif args.command == 'list':
        list_backups()
    else:
        parser.print_help()


if __name__ == "__main__":
    main()


"""
Создать резервную копию:
python backup_restore.py backup

Показать список бэкапов:
python backup_restore.py list

Восстановить проект (по номеру или имени):
python backup_restore.py restore backup_20240515_143022.zip  
python backup_restore.py restore backup_20250417_212905.zip
python backup_restore.py restore backup_20250417_212905.zip

или
python backup_restore.py restore
# Затем выберите номер из списка

"""

Вкратце, делаем файл рядом с manage.py:
1. Сделали топ версию: python backup_restore.py backup
2. Сделали после топ версии хавно, откат в секунду: python backup_restore.py restore

Мой канал: @jollyPython
Maximum free skill: @pythonNb

Автор: sunPython

Источник

Rambler's Top100