{"id":458206,"date":"2025-04-30T09:00:46","date_gmt":"2025-04-30T09:00:46","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=458206"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=458206","title":{"rendered":"<span>backup Django<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<h2>\u0420\u0435\u0437\u0435\u0440\u0432\u043d\u043e\u0435 \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 Django<\/h2>\n<p>\u041a\u043e\u0440\u043e\u0447\u0435, \u043d\u0430\u0447\u0430\u043b \u0434\u0435\u043b\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430 Django \u0441 \u043d\u0443\u043b\u044f, \u0438 \u0432\u043e\u043e\u0431\u0449\u0435 \u0432\u043f\u0435\u0440\u0432\u044b\u0435 \u0441 \u043d\u0438\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u044e <em>(noob)<\/em>. \u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0441 \u043d\u0435\u0439\u0440\u043e\u043d\u043a\u0430\u043c\u0438 \u0432 \u043f\u0430\u0440\u0435, \u0442\u0430\u043a \u043a\u0430\u043a \u0441\u0430\u043c \u0432 Django \u043d\u0435 \u043e\u0441\u043e\u0431\u043e \u0448\u0430\u0440\u044e, \u0438 \u043e\u043d\u0438 \u0434\u0435\u043b\u0430\u044e\u0442 \u043f\u043e\u0447\u0442\u0438 \u0432\u0441\u0451 \u0437\u0430 \u043c\u0435\u043d\u044f <em>(\u0443\u0441\u043b\u043e\u0432\u043d\u043e)<\/em>. \u0418 \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043d\u0435\u0439\u0440\u043e\u0441\u0435\u0442\u0438 \u043b\u044e\u0431\u044f\u0442 \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u043a\u043e\u0434 \u043f\u043e-\u0441\u0432\u043e\u0435\u043c\u0443, \u043f\u0435\u0440\u0438\u043e\u0434\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u0441\u0451 \u043b\u043e\u043c\u0430\u0435\u0442\u0441\u044f: \u0438 \u043a\u043e\u0434, \u0438 \u0431\u0430\u0437\u0430, \u0438 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u0430\u044f \u0440\u0430\u0437\u043d\u0430\u044f \u043d\u0435\u0447\u0438\u0441\u0442\u044c\ud83c\udf1a<\/p>\n<p>*<em>\u041f\u0440\u0438\u043c\u0435\u0447\u0430\u043d\u0438\u0435: \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0434\u043b\u044f db.sqlite3 (\u0447\u0442\u043e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442 \u0434\u043b\u044f Dj, \u0438 \u0431\u044b\u0432\u0430\u0435\u0442 \u043c\u043d\u043e\u0433\u043e\u0435), \u043d\u043e \u0441 \u043b\u0451\u0433\u043a\u043e\u0441\u0442\u044c\u044e \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u043f\u043e\u0434 \u0434\u0440\u0443\u0433\u0443\u044e \u0431\u0434<\/em><\/p>\n<p>\u0412 \u0438\u0442\u043e\u0433\u0435 \u0440\u0435\u0448\u0438\u043b \u0434\u0435\u043b\u0430\u0442\u044c \u0431\u044d\u043a\u0430\u043f\u044b \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u043d\u0435\u0439\u0440\u043e\u043d\u043a\u0430\u043c\u0438 \u2014 \u043c\u043e\u0436\u0435\u0442, \u043a\u043e\u043c\u0443-\u0442\u043e \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u0442\u0441\u044f.<\/p>\n<p>\u0414\u0430, \u044f \u0432 \u043a\u0443\u0440\u0441\u0435, \u0447\u0442\u043e \u0435\u0441\u0442\u044c <code>django-dbbackup<\/code>, \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u0432\u0435\u0440\u0441\u0438\u0439 \u0438 \u043a\u0443\u0447\u0430 \u0434\u0440\u0443\u0433\u0438\u0445 \u0442\u0435\u043c, \u043d\u043e \u043c\u043d\u0435 \u043f\u043e\u043a\u0430 \u0442\u0430\u043a \u0443\u0434\u043e\u0431\u043d\u0435\u0435. \u0414\u0430\u043b\u044c\u0448\u0435 \u2014 \u0431\u043e\u043b\u044c\u0448\u0435. \u0414\u0435\u043b\u044e\u0441\u044c \u044d\u0442\u0438\u043c \u0441\u043a\u043e\u0440\u0435\u0435 \u0434\u043b\u044f \u0442\u0430\u043a\u0438\u0445 \u0436\u0435 \u043d\u043e\u0432\u0438\u0447\u043a\u043e\u0432, \u043a\u0430\u043a \u044f. \u0412\u0434\u0440\u0443\u0433 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0435\u0437\u043d\u043e\u2935\ufe0f:<\/p>\n<h2>\u0427\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u043c<\/h2>\n<ol>\n<li>\n<p>\u041b\u0435\u0433\u043a\u043e \u0438 \u0438\u0437\u044f\u0449\u043d\u043e \u043f\u0438\u0448\u0435\u043c \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c \u043f\u0440\u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435<\/p>\n<\/li>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u0432\u0441\u0451 \u043f\u043e\u0448\u043b\u043e \u043d\u0435 \u0442\u0435\u043c \u043f\u0443\u0442\u0451\u043c \u043a\u0443\u0434\u0430 \u0445\u043e\u0442\u0435\u043b\u0438 \u043f\u0440\u0438\u0439\u0442\u0438, \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0432\u0441\u0451 \u043e\u0431\u0440\u0430\u0442\u043d\u043e \u0432 1 \u0441\u0435\u043a\u0443\u043d\u0434\u0443 <\/p>\n<\/li>\n<\/ol>\n<pre><code>import os import shutil import sqlite3 import datetime import zipfile import argparse   # === \u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0434\u043b\u044f \u0431\u044d\u043a\u0430\u043f\u0430 ===  # \u041f\u0430\u043f\u043a\u0430, \u0432 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0431\u0443\u0434\u0443\u0442 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c\u0441\u044f \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u044b\u0435 \u043a\u043e\u043f\u0438\u0438 BACKUP_DIR = \"backups\"  # \u041f\u0430\u043f\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0443\u0436\u043d\u043e \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0438\u0437 \u0431\u044d\u043a\u0430\u043f\u0430 # \u041e\u0431\u044b\u0447\u043d\u043e \u0441\u044e\u0434\u0430 \u043f\u043e\u043f\u0430\u0434\u0430\u044e\u0442 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435, \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0438\u043b\u0438 \u043d\u0435\u0432\u0430\u0436\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 EXCLUDE_DIRS = ['__pycache__', '.git', 'venv']  # __pycache__ \u2014 \u043a\u044d\u0448 Python, .git \u2014 \u0438\u0441\u0442\u043e\u0440\u0438\u044f \u0433\u0438\u0442\u0430, venv \u2014 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435  # \u041e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u0443\u0436\u043d\u043e \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0432 \u0431\u044d\u043a\u0430\u043f # \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0431\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 SQLite \u0438 \u0441\u043f\u0438\u0441\u043e\u043a \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 INCLUDE_FILES = ['db.sqlite3', 'requirements.txt']  # \u041f\u0430\u043f\u043a\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0443\u0436\u043d\u043e \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0432 \u0431\u044d\u043a\u0430\u043f # \u0423\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u0442\u0435 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 (\u043f\u0430\u043f\u043a\u0438 noob), \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043a\u043e\u0434 INCLUDE_DIRS = ['fish1', 'fish2']   def create_backup():     \"\"\"\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u043e\u0439 \u043a\u043e\u043f\u0438\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0441 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c\u044e \u0437\u0430\u0434\u0430\u0442\u044c \u0438\u043c\u044f\"\"\"     user_input = input(\"\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u043e\u0439 \u043a\u043e\u043f\u0438\u0438 (\u043e\u0441\u0442\u0430\u0432\u044c\u0442\u0435 \u043f\u0443\u0441\u0442\u044b\u043c \u0434\u043b\u044f \u0438\u043c\u0435\u043d\u0438 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e): \").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\"\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u043e\u0439 \u043a\u043e\u043f\u0438\u0438 \u0432 {backup_path}...\")      # \u041a\u043e\u043f\u0438\u0440\u0443\u0435\u043c \u0444\u0430\u0439\u043b\u044b     for item in INCLUDE_FILES:         if os.path.exists(item):             shutil.copy2(item, backup_path)      # \u041a\u043e\u043f\u0438\u0440\u0443\u0435\u043c \u043f\u0430\u043f\u043a\u0438     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)             )      # \u0414\u0430\u043c\u043f 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 \u0430\u0440\u0445\u0438\u0432     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\"\u2714 \u0420\u0435\u0437\u0435\u0440\u0432\u043d\u0430\u044f \u043a\u043e\u043f\u0438\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0430: {zip_path}\")   def restore_backup(backup_file):     \"\"\"\u0412\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0438\u0437 \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u043e\u0439 \u043a\u043e\u043f\u0438\u0438\"\"\"     if not os.path.exists(backup_file):         print(f\"\u0424\u0430\u0439\u043b {backup_file} \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d!\")         return      print(f\"\u0412\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0438\u0437 {backup_file}...\")      # \u0423\u0434\u0430\u043b\u044f\u0435\u043c \u0442\u0435\u043a\u0443\u0449\u0438\u0435 \u043f\u0430\u043f\u043a\u0438     for dir_name in INCLUDE_DIRS:         if os.path.exists(dir_name):             shutil.rmtree(dir_name)      # \u0420\u0430\u0441\u043f\u0430\u043a\u043e\u0432\u044b\u0432\u0430\u0435\u043c \u0430\u0440\u0445\u0438\u0432     temp_dir = \"temp_restore\"     with zipfile.ZipFile(backup_file, 'r') as zip_ref:         zip_ref.extractall(temp_dir)      # \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u043f\u0443\u0442\u044c \u043a \u0434\u0430\u043d\u043d\u044b\u043c     backup_name = os.path.splitext(os.path.basename(backup_file))[0]     source_path = os.path.join(temp_dir, backup_name)      # \u041a\u043e\u043f\u0438\u0440\u0443\u0435\u043c \u0444\u0430\u0439\u043b\u044b \u043e\u0431\u0440\u0430\u0442\u043d\u043e     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)      # \u0412\u043e\u0441\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445     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(\"\u2714 \u0412\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u043e!\")   def list_backups():     \"\"\"\u0421\u043f\u0438\u0441\u043e\u043a \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u044b\u0445 \u043a\u043e\u043f\u0438\u0439\"\"\"     if not os.path.exists(BACKUP_DIR):         print(\"\u041f\u0430\u043f\u043a\u0430 \u0441 \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u044b\u043c\u0438 \u043a\u043e\u043f\u0438\u044f\u043c\u0438 \u043f\u0443\u0441\u0442\u0430!\")         return      backups = sorted(         [f for f in os.listdir(BACKUP_DIR) if f.endswith('.zip')],         reverse=True     )      if not backups:         print(\"\u0420\u0435\u0437\u0435\u0440\u0432\u043d\u044b\u0435 \u043a\u043e\u043f\u0438\u0438 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u044b!\")         return      print(\"\ud83d\udce6 \u0414\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0435 \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u044b\u0435 \u043a\u043e\u043f\u0438\u0438:\")     for i, backup in enumerate(backups, 1):         print(f\"{i}. {backup}\")   def main():     parser = argparse.ArgumentParser(description=\"\u0420\u0435\u0437\u0435\u0440\u0432\u043d\u043e\u0435 \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 Django-\u043f\u0440\u043e\u0435\u043a\u0442\u0430\")     subparsers = parser.add_subparsers(dest='command')      subparsers.add_parser('backup', help='\u0421\u043e\u0437\u0434\u0430\u0442\u044c \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u0443\u044e \u043a\u043e\u043f\u0438\u044e')      restore_parser = subparsers.add_parser('restore', help='\u0412\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0438\u0437 \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u043e\u0439 \u043a\u043e\u043f\u0438\u0438')     restore_parser.add_argument('backup', nargs='?', help='\u0418\u043c\u044f zip-\u0444\u0430\u0439\u043b\u0430 \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u043e\u0439 \u043a\u043e\u043f\u0438\u0438')      subparsers.add_parser('list', help='\u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u044b\u0445 \u043a\u043e\u043f\u0438\u0439')      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(\"\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u043d\u043e\u043c\u0435\u0440 \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u043e\u0439 \u043a\u043e\u043f\u0438\u0438 \u0434\u043b\u044f \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f: \")             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(\"\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u0432\u044b\u0431\u043e\u0440!\")     elif args.command == 'list':         list_backups()     else:         parser.print_help()   if __name__ == \"__main__\":     main()   \"\"\" \u0421\u043e\u0437\u0434\u0430\u0442\u044c \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u0443\u044e \u043a\u043e\u043f\u0438\u044e: python backup_restore.py backup  \u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0431\u044d\u043a\u0430\u043f\u043e\u0432: python backup_restore.py list  \u0412\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442 (\u043f\u043e \u043d\u043e\u043c\u0435\u0440\u0443 \u0438\u043b\u0438 \u0438\u043c\u0435\u043d\u0438): 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  \u0438\u043b\u0438 python backup_restore.py restore # \u0417\u0430\u0442\u0435\u043c \u0432\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u043d\u043e\u043c\u0435\u0440 \u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430  \"\"\"<\/code><\/pre>\n<p>\u0412\u043a\u0440\u0430\u0442\u0446\u0435 \u0438 \u0432 \u0433\u0440\u0430\u0446\u0438\u0438\u2764\ufe0f\u200d\ud83d\udd25, \u0434\u0435\u043b\u0430\u0435\u043c \u0444\u0430\u0439\u043b \u0440\u044f\u0434\u043e\u043c \u0441  <a href=\"http:\/\/manage.py\" rel=\"noopener noreferrer nofollow\">manage.py<\/a> <em>(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0441 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c \u00abbackup_<\/em><a href=\"http:\/\/restore.py\" rel=\"noopener noreferrer nofollow\"><em>restore.py<\/em><\/a><em>\u00bb)<\/em>, \u0434\u0430\u043b\u0435\u0435:<\/p>\n<p>1. \u0421\u0434\u0435\u043b\u0430\u043b\u0438 \u0442\u043e\u043f \u0440\u0430\u0431\u043e\u0447\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e:<strong> python backup_<\/strong><a href=\"http:\/\/restore.py\" rel=\"noopener noreferrer nofollow\"><strong>restore.py<\/strong><\/a><strong> backup <\/strong><em>(\u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u0430 \u043f\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u0443, \u043d\u0430\u0437\u044b\u0432\u0430\u0439\u0442\u0435 \u0444\u0430\u0439\u043b \u043b\u044e\u0431\u044b\u043c \u0434\u0440\u0443\u0433\u0438\u043c \u0441\u043b\u043e\u0432\u043e\u043c, \u043a\u0430\u043a \u0445\u043e\u0442\u0438\u0442\u0435, \u0438 <\/em><strong><em>backup <\/em><\/strong><em>\u0434\u0435\u043b\u0430\u0435\u043c \u043f\u043e \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044e \u0444\u0430\u0439\u043b\u0430)<\/em><br \/>2. \u0421\u0434\u0435\u043b\u0430\u043b\u0438 <strong>\u043f\u043e\u0441\u043b\u0435 \u0442\u043e\u043f \u0432\u0435\u0440\u0441\u0438\u0438 \u2014 \u0445\u0430\u0432\u043d\u043e <em>(\u0433\u0434\u0435 \u0432\u0441\u0451 \u043b\u043e\u043c\u0430\u0435\u0442\u0441\u044f)<\/em><\/strong>, \u043e\u0442\u043a\u0430\u0442 \u0432 \u0441\u0435\u043a\u0443\u043d\u0434\u0443: <strong>python backup_<\/strong><a href=\"http:\/\/restore.py\" rel=\"noopener noreferrer nofollow\"><strong>restore.py<\/strong><\/a><strong> restore<\/strong><br \/>2.1. \u0420\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u0434\u0430\u043b\u044c\u0448\u0435\ud83c\udfaf<\/p>\n<p><strong>\u041c\u043e\u0439 \u043a\u0430\u043d\u0430\u043b: <\/strong><a href=\"https:\/\/t.me\/jollyPython\" rel=\"noopener noreferrer nofollow\">https:\/\/t.me\/jollyPython<\/a><br \/><strong>Maximum free skill Python<em> <\/em><\/strong><em>(\u0433\u043b\u0443\u0431\u0438\u043d\u0430 Python, \u0434\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043d\u0435 \u0434\u043e\u0442\u044f\u043d\u0435\u0442\u0441\u044f \u043d\u0438 \u043e\u0434\u043d\u0430 \u0441\u0438\u0441\u0442\u0435\u043c\u0430)<\/em>: <a href=\"https:\/\/t.me\/pythonNb\" rel=\"noopener noreferrer nofollow\">https:\/\/t.me\/pythonNb<\/a><\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/905768\/\"> https:\/\/habr.com\/ru\/articles\/905768\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<h2>\u0420\u0435\u0437\u0435\u0440\u0432\u043d\u043e\u0435 \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 Django<\/h2>\n<p>\u041a\u043e\u0440\u043e\u0447\u0435, \u043d\u0430\u0447\u0430\u043b \u0434\u0435\u043b\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430 Django \u0441 \u043d\u0443\u043b\u044f, \u0438 \u0432\u043e\u043e\u0431\u0449\u0435 \u0432\u043f\u0435\u0440\u0432\u044b\u0435 \u0441 \u043d\u0438\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u044e <em>(noob)<\/em>. \u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0441 \u043d\u0435\u0439\u0440\u043e\u043d\u043a\u0430\u043c\u0438 \u0432 \u043f\u0430\u0440\u0435, \u0442\u0430\u043a \u043a\u0430\u043a \u0441\u0430\u043c \u0432 Django \u043d\u0435 \u043e\u0441\u043e\u0431\u043e \u0448\u0430\u0440\u044e, \u0438 \u043e\u043d\u0438 \u0434\u0435\u043b\u0430\u044e\u0442 \u043f\u043e\u0447\u0442\u0438 \u0432\u0441\u0451 \u0437\u0430 \u043c\u0435\u043d\u044f <em>(\u0443\u0441\u043b\u043e\u0432\u043d\u043e)<\/em>. \u0418 \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043d\u0435\u0439\u0440\u043e\u0441\u0435\u0442\u0438 \u043b\u044e\u0431\u044f\u0442 \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u043a\u043e\u0434 \u043f\u043e-\u0441\u0432\u043e\u0435\u043c\u0443, \u043f\u0435\u0440\u0438\u043e\u0434\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u0441\u0451 \u043b\u043e\u043c\u0430\u0435\u0442\u0441\u044f: \u0438 \u043a\u043e\u0434, \u0438 \u0431\u0430\u0437\u0430, \u0438 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u0430\u044f \u0440\u0430\u0437\u043d\u0430\u044f \u043d\u0435\u0447\u0438\u0441\u0442\u044c\ud83c\udf1a<\/p>\n<p>*<em>\u041f\u0440\u0438\u043c\u0435\u0447\u0430\u043d\u0438\u0435: \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0434\u043b\u044f db.sqlite3 (\u0447\u0442\u043e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442 \u0434\u043b\u044f Dj, \u0438 \u0431\u044b\u0432\u0430\u0435\u0442 \u043c\u043d\u043e\u0433\u043e\u0435), \u043d\u043e \u0441 \u043b\u0451\u0433\u043a\u043e\u0441\u0442\u044c\u044e \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u043f\u043e\u0434 \u0434\u0440\u0443\u0433\u0443\u044e \u0431\u0434<\/em><\/p>\n<p>\u0412 \u0438\u0442\u043e\u0433\u0435 \u0440\u0435\u0448\u0438\u043b \u0434\u0435\u043b\u0430\u0442\u044c \u0431\u044d\u043a\u0430\u043f\u044b \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u043d\u0435\u0439\u0440\u043e\u043d\u043a\u0430\u043c\u0438 \u2014 \u043c\u043e\u0436\u0435\u0442, \u043a\u043e\u043c\u0443-\u0442\u043e \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u0442\u0441\u044f.<\/p>\n<p>\u0414\u0430, \u044f \u0432 \u043a\u0443\u0440\u0441\u0435, \u0447\u0442\u043e \u0435\u0441\u0442\u044c <code>django-dbbackup<\/code>, \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u0432\u0435\u0440\u0441\u0438\u0439 \u0438 \u043a\u0443\u0447\u0430 \u0434\u0440\u0443\u0433\u0438\u0445 \u0442\u0435\u043c, \u043d\u043e \u043c\u043d\u0435 \u043f\u043e\u043a\u0430 \u0442\u0430\u043a \u0443\u0434\u043e\u0431\u043d\u0435\u0435. \u0414\u0430\u043b\u044c\u0448\u0435 \u2014 \u0431\u043e\u043b\u044c\u0448\u0435. \u0414\u0435\u043b\u044e\u0441\u044c \u044d\u0442\u0438\u043c \u0441\u043a\u043e\u0440\u0435\u0435 \u0434\u043b\u044f \u0442\u0430\u043a\u0438\u0445 \u0436\u0435 \u043d\u043e\u0432\u0438\u0447\u043a\u043e\u0432, \u043a\u0430\u043a \u044f. \u0412\u0434\u0440\u0443\u0433 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0435\u0437\u043d\u043e\u2935\ufe0f:<\/p>\n<h2>\u0427\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u043c<\/h2>\n<ol>\n<li>\n<p>\u041b\u0435\u0433\u043a\u043e \u0438 \u0438\u0437\u044f\u0449\u043d\u043e \u043f\u0438\u0448\u0435\u043c \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c \u043f\u0440\u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435<\/p>\n<\/li>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u0432\u0441\u0451 \u043f\u043e\u0448\u043b\u043e \u043d\u0435 \u0442\u0435\u043c \u043f\u0443\u0442\u0451\u043c \u043a\u0443\u0434\u0430 \u0445\u043e\u0442\u0435\u043b\u0438 \u043f\u0440\u0438\u0439\u0442\u0438, \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0432\u0441\u0451 \u043e\u0431\u0440\u0430\u0442\u043d\u043e \u0432 1 \u0441\u0435\u043a\u0443\u043d\u0434\u0443 <\/p>\n<\/li>\n<\/ol>\n<pre><code>import os import shutil import sqlite3 import datetime import zipfile import argparse   # === \u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0434\u043b\u044f \u0431\u044d\u043a\u0430\u043f\u0430 ===  # \u041f\u0430\u043f\u043a\u0430, \u0432 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0431\u0443\u0434\u0443\u0442 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c\u0441\u044f \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u044b\u0435 \u043a\u043e\u043f\u0438\u0438 BACKUP_DIR = \"backups\"  # \u041f\u0430\u043f\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0443\u0436\u043d\u043e \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0438\u0437 \u0431\u044d\u043a\u0430\u043f\u0430 # \u041e\u0431\u044b\u0447\u043d\u043e \u0441\u044e\u0434\u0430 \u043f\u043e\u043f\u0430\u0434\u0430\u044e\u0442 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435, \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0438\u043b\u0438 \u043d\u0435\u0432\u0430\u0436\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 EXCLUDE_DIRS = ['__pycache__', '.git', 'venv']  # __pycache__ \u2014 \u043a\u044d\u0448 Python, .git \u2014 \u0438\u0441\u0442\u043e\u0440\u0438\u044f \u0433\u0438\u0442\u0430, venv \u2014 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435  # \u041e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u0443\u0436\u043d\u043e \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0432 \u0431\u044d\u043a\u0430\u043f # \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0431\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 SQLite \u0438 \u0441\u043f\u0438\u0441\u043e\u043a \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 INCLUDE_FILES = ['db.sqlite3', 'requirements.txt']  # \u041f\u0430\u043f\u043a\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0443\u0436\u043d\u043e \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0432 \u0431\u044d\u043a\u0430\u043f # \u0423\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u0442\u0435 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 (\u043f\u0430\u043f\u043a\u0438 noob), \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043a\u043e\u0434 INCLUDE_DIRS = ['fish1', 'fish2']   def create_backup():     \"\"\"\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u043e\u0439 \u043a\u043e\u043f\u0438\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0441 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c\u044e \u0437\u0430\u0434\u0430\u0442\u044c \u0438\u043c\u044f\"\"\"     user_input = input(\"\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u043e\u0439 \u043a\u043e\u043f\u0438\u0438 (\u043e\u0441\u0442\u0430\u0432\u044c\u0442\u0435 \u043f\u0443\u0441\u0442\u044b\u043c \u0434\u043b\u044f \u0438\u043c\u0435\u043d\u0438 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e): \").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\"\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u043e\u0439 \u043a\u043e\u043f\u0438\u0438 \u0432 {backup_path}...\")      # \u041a\u043e\u043f\u0438\u0440\u0443\u0435\u043c \u0444\u0430\u0439\u043b\u044b     for item in INCLUDE_FILES:         if os.path.exists(item):             shutil.copy2(item, backup_path)      # \u041a\u043e\u043f\u0438\u0440\u0443\u0435\u043c \u043f\u0430\u043f\u043a\u0438     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)             )      # \u0414\u0430\u043c\u043f 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 \u0430\u0440\u0445\u0438\u0432     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\"\u2714 \u0420\u0435\u0437\u0435\u0440\u0432\u043d\u0430\u044f \u043a\u043e\u043f\u0438\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0430: {zip_path}\")   def restore_backup(backup_file):     \"\"\"\u0412\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0438\u0437 \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u043e\u0439 \u043a\u043e\u043f\u0438\u0438\"\"\"     if not os.path.exists(backup_file):         print(f\"\u0424\u0430\u0439\u043b {backup_file} \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d!\")         return      print(f\"\u0412\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0438\u0437 {backup_file}...\")      # \u0423\u0434\u0430\u043b\u044f\u0435\u043c \u0442\u0435\u043a\u0443\u0449\u0438\u0435 \u043f\u0430\u043f\u043a\u0438     for dir_name in INCLUDE_DIRS:         if os.path.exists(dir_name):             shutil.rmtree(dir_name)      # \u0420\u0430\u0441\u043f\u0430\u043a\u043e\u0432\u044b\u0432\u0430\u0435\u043c \u0430\u0440\u0445\u0438\u0432     temp_dir = \"temp_restore\"     with zipfile.ZipFile(backup_file, 'r') as zip_ref:         zip_ref.extractall(temp_dir)      # \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u043f\u0443\u0442\u044c \u043a \u0434\u0430\u043d\u043d\u044b\u043c     backup_name = os.path.splitext(os.path.basename(backup_file))[0]     source_path = os.path.join(temp_dir, backup_name)      # \u041a\u043e\u043f\u0438\u0440\u0443\u0435\u043c \u0444\u0430\u0439\u043b\u044b \u043e\u0431\u0440\u0430\u0442\u043d\u043e     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)      # \u0412\u043e\u0441\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445     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(\"\u2714 \u0412\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u043e!\")   def list_backups():     \"\"\"\u0421\u043f\u0438\u0441\u043e\u043a \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u044b\u0445 \u043a\u043e\u043f\u0438\u0439\"\"\"     if not os.path.exists(BACKUP_DIR):         print(\"\u041f\u0430\u043f\u043a\u0430 \u0441 \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u044b\u043c\u0438 \u043a\u043e\u043f\u0438\u044f\u043c\u0438 \u043f\u0443\u0441\u0442\u0430!\")         return      backups = sorted(         [f for f in os.listdir(BACKUP_DIR) if f.endswith('.zip')],         reverse=True     )      if not backups:         print(\"\u0420\u0435\u0437\u0435\u0440\u0432\u043d\u044b\u0435 \u043a\u043e\u043f\u0438\u0438 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u044b!\")         return      print(\"\ud83d\udce6 \u0414\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0435 \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u044b\u0435 \u043a\u043e\u043f\u0438\u0438:\")     for i, backup in enumerate(backups, 1):         print(f\"{i}. {backup}\")   def main():     parser = argparse.ArgumentParser(description=\"\u0420\u0435\u0437\u0435\u0440\u0432\u043d\u043e\u0435 \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 Django-\u043f\u0440\u043e\u0435\u043a\u0442\u0430\")     subparsers = parser.add_subparsers(dest='command')      subparsers.add_parser('backup', help='\u0421\u043e\u0437\u0434\u0430\u0442\u044c \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u0443\u044e \u043a\u043e\u043f\u0438\u044e')      restore_parser = subparsers.add_parser('restore', help='\u0412\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0438\u0437 \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u043e\u0439 \u043a\u043e\u043f\u0438\u0438')     restore_parser.add_argument('backup', nargs='?', help='\u0418\u043c\u044f zip-\u0444\u0430\u0439\u043b\u0430 \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u043e\u0439 \u043a\u043e\u043f\u0438\u0438')      subparsers.add_parser('list', help='\u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u044b\u0445 \u043a\u043e\u043f\u0438\u0439')      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(\"\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u043d\u043e\u043c\u0435\u0440 \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u043e\u0439 \u043a\u043e\u043f\u0438\u0438 \u0434\u043b\u044f \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f: \")             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(\"\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u0432\u044b\u0431\u043e\u0440!\")     elif args.command == 'list':         list_backups()     else:         parser.print_help()   if __name__ == \"__main__\":     main()   \"\"\" \u0421\u043e\u0437\u0434\u0430\u0442\u044c \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u0443\u044e \u043a\u043e\u043f\u0438\u044e: python backup_restore.py backup  \u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0431\u044d\u043a\u0430\u043f\u043e\u0432: python backup_restore.py list  \u0412\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442 (\u043f\u043e \u043d\u043e\u043c\u0435\u0440\u0443 \u0438\u043b\u0438 \u0438\u043c\u0435\u043d\u0438): 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  \u0438\u043b\u0438 python backup_restore.py restore # \u0417\u0430\u0442\u0435\u043c \u0432\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u043d\u043e\u043c\u0435\u0440 \u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430  \"\"\"<\/code><\/pre>\n<p>\u0412\u043a\u0440\u0430\u0442\u0446\u0435 \u0438 \u0432 \u0433\u0440\u0430\u0446\u0438\u0438\u2764\ufe0f\u200d\ud83d\udd25, \u0434\u0435\u043b\u0430\u0435\u043c \u0444\u0430\u0439\u043b \u0440\u044f\u0434\u043e\u043c \u0441  <a href=\"http:\/\/manage.py\" rel=\"noopener noreferrer nofollow\">manage.py<\/a> <em>(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0441 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c \u00abbackup_<\/em><a href=\"http:\/\/restore.py\" rel=\"noopener noreferrer nofollow\"><em>restore.py<\/em><\/a><em>\u00bb)<\/em>, \u0434\u0430\u043b\u0435\u0435:<\/p>\n<p>1. \u0421\u0434\u0435\u043b\u0430\u043b\u0438 \u0442\u043e\u043f \u0440\u0430\u0431\u043e\u0447\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e:<strong> python backup_<\/strong><a href=\"http:\/\/restore.py\" rel=\"noopener noreferrer nofollow\"><strong>restore.py<\/strong><\/a><strong> backup <\/strong><em>(\u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u0430 \u043f\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u0443, \u043d\u0430\u0437\u044b\u0432\u0430\u0439\u0442\u0435 \u0444\u0430\u0439\u043b \u043b\u044e\u0431\u044b\u043c \u0434\u0440\u0443\u0433\u0438\u043c \u0441\u043b\u043e\u0432\u043e\u043c, \u043a\u0430\u043a \u0445\u043e\u0442\u0438\u0442\u0435, \u0438 <\/em><strong><em>backup <\/em><\/strong><em>\u0434\u0435\u043b\u0430\u0435\u043c \u043f\u043e \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044e \u0444\u0430\u0439\u043b\u0430)<\/em><br \/>2. \u0421\u0434\u0435\u043b\u0430\u043b\u0438 <strong>\u043f\u043e\u0441\u043b\u0435 \u0442\u043e\u043f \u0432\u0435\u0440\u0441\u0438\u0438 \u2014 \u0445\u0430\u0432\u043d\u043e <em>(\u0433\u0434\u0435 \u0432\u0441\u0451 \u043b\u043e\u043c\u0430\u0435\u0442\u0441\u044f)<\/em><\/strong>, \u043e\u0442\u043a\u0430\u0442 \u0432 \u0441\u0435\u043a\u0443\u043d\u0434\u0443: <strong>python backup_<\/strong><a href=\"http:\/\/restore.py\" rel=\"noopener noreferrer nofollow\"><strong>restore.py<\/strong><\/a><strong> restore<\/strong><br \/>2.1. \u0420\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u0434\u0430\u043b\u044c\u0448\u0435\ud83c\udfaf<\/p>\n<p><strong>\u041c\u043e\u0439 \u043a\u0430\u043d\u0430\u043b: <\/strong><a href=\"https:\/\/t.me\/jollyPython\" rel=\"noopener noreferrer nofollow\">https:\/\/t.me\/jollyPython<\/a><br \/><strong>Maximum free skill Python<em> <\/em><\/strong><em>(\u0433\u043b\u0443\u0431\u0438\u043d\u0430 Python, \u0434\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043d\u0435 \u0434\u043e\u0442\u044f\u043d\u0435\u0442\u0441\u044f \u043d\u0438 \u043e\u0434\u043d\u0430 \u0441\u0438\u0441\u0442\u0435\u043c\u0430)<\/em>: <a href=\"https:\/\/t.me\/pythonNb\" rel=\"noopener noreferrer nofollow\">https:\/\/t.me\/pythonNb<\/a><\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/905768\/\"> https:\/\/habr.com\/ru\/articles\/905768\/<\/a><br \/><\/br><\/br><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-458206","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/458206","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=458206"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/458206\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=458206"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=458206"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=458206"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}