django-rclone 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. django_rclone-0.1.0/.github/dependabot.yml +11 -0
  2. django_rclone-0.1.0/.github/workflows/ci.yml +37 -0
  3. django_rclone-0.1.0/.github/workflows/publish.yml +17 -0
  4. django_rclone-0.1.0/.gitignore +32 -0
  5. django_rclone-0.1.0/.pre-commit-config.yaml +15 -0
  6. django_rclone-0.1.0/.python-version +1 -0
  7. django_rclone-0.1.0/CLAUDE.md +22 -0
  8. django_rclone-0.1.0/PKG-INFO +217 -0
  9. django_rclone-0.1.0/README.md +201 -0
  10. django_rclone-0.1.0/docs/commands.md +200 -0
  11. django_rclone-0.1.0/docs/configuration.md +216 -0
  12. django_rclone-0.1.0/docs/connectors.md +204 -0
  13. django_rclone-0.1.0/docs/getting-started.md +123 -0
  14. django_rclone-0.1.0/docs/migration-from-dbbackup.md +189 -0
  15. django_rclone-0.1.0/docs/signals.md +110 -0
  16. django_rclone-0.1.0/pyproject.toml +51 -0
  17. django_rclone-0.1.0/src/django_rclone/__init__.py +0 -0
  18. django_rclone-0.1.0/src/django_rclone/apps.py +7 -0
  19. django_rclone-0.1.0/src/django_rclone/db/__init__.py +0 -0
  20. django_rclone-0.1.0/src/django_rclone/db/base.py +49 -0
  21. django_rclone-0.1.0/src/django_rclone/db/mongodb.py +68 -0
  22. django_rclone-0.1.0/src/django_rclone/db/mysql.py +57 -0
  23. django_rclone-0.1.0/src/django_rclone/db/postgresql.py +90 -0
  24. django_rclone-0.1.0/src/django_rclone/db/registry.py +62 -0
  25. django_rclone-0.1.0/src/django_rclone/db/sqlite.py +24 -0
  26. django_rclone-0.1.0/src/django_rclone/exceptions.py +25 -0
  27. django_rclone-0.1.0/src/django_rclone/filenames.py +83 -0
  28. django_rclone-0.1.0/src/django_rclone/management/__init__.py +0 -0
  29. django_rclone-0.1.0/src/django_rclone/management/commands/__init__.py +0 -0
  30. django_rclone-0.1.0/src/django_rclone/management/commands/dbbackup.py +124 -0
  31. django_rclone-0.1.0/src/django_rclone/management/commands/dbrestore.py +119 -0
  32. django_rclone-0.1.0/src/django_rclone/management/commands/listbackups.py +85 -0
  33. django_rclone-0.1.0/src/django_rclone/management/commands/mediabackup.py +36 -0
  34. django_rclone-0.1.0/src/django_rclone/management/commands/mediarestore.py +36 -0
  35. django_rclone-0.1.0/src/django_rclone/rclone.py +105 -0
  36. django_rclone-0.1.0/src/django_rclone/settings.py +31 -0
  37. django_rclone-0.1.0/src/django_rclone/signals.py +10 -0
  38. django_rclone-0.1.0/tests/__init__.py +0 -0
  39. django_rclone-0.1.0/tests/settings.py +18 -0
  40. django_rclone-0.1.0/tests/test_commands.py +336 -0
  41. django_rclone-0.1.0/tests/test_db.py +288 -0
  42. django_rclone-0.1.0/tests/test_exceptions.py +21 -0
  43. django_rclone-0.1.0/tests/test_filenames.py +33 -0
  44. django_rclone-0.1.0/tests/test_rclone.py +186 -0
  45. django_rclone-0.1.0/tests/test_settings.py +33 -0
  46. django_rclone-0.1.0/tests/test_signals.py +32 -0
  47. django_rclone-0.1.0/uv.lock +315 -0
@@ -0,0 +1,11 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: pip
4
+ directory: /
5
+ schedule:
6
+ interval: weekly
7
+
8
+ - package-ecosystem: github-actions
9
+ directory: /
10
+ schedule:
11
+ interval: weekly
@@ -0,0 +1,37 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+ pull_request:
7
+
8
+ jobs:
9
+ lint:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v6
13
+ - uses: astral-sh/setup-uv@v7
14
+ - run: uv sync
15
+ - run: uv run ruff check .
16
+ - run: uv run ruff format --check .
17
+
18
+ typecheck:
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - uses: actions/checkout@v6
22
+ - uses: astral-sh/setup-uv@v7
23
+ - run: uv sync
24
+ - run: uv run ty check
25
+
26
+ test:
27
+ runs-on: ubuntu-latest
28
+ strategy:
29
+ matrix:
30
+ python-version: ["3.13"]
31
+ steps:
32
+ - uses: actions/checkout@v6
33
+ - uses: astral-sh/setup-uv@v7
34
+ with:
35
+ python-version: ${{ matrix.python-version }}
36
+ - run: uv sync
37
+ - run: uv run pytest
@@ -0,0 +1,17 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags: ["v*"]
6
+
7
+ jobs:
8
+ publish:
9
+ runs-on: ubuntu-latest
10
+ environment: pypi
11
+ permissions:
12
+ id-token: write
13
+ steps:
14
+ - uses: actions/checkout@v6
15
+ - uses: astral-sh/setup-uv@v7
16
+ - run: uv build
17
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,32 @@
1
+ # Python artifacts
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ build/
6
+ dist/
7
+ wheels/
8
+
9
+ # Virtual environments
10
+ .venv/
11
+
12
+ # IDE
13
+ .idea/
14
+ .vscode/
15
+ *.swp
16
+ *.swo
17
+ *~
18
+
19
+ # OS
20
+ .DS_Store
21
+ Thumbs.db
22
+
23
+ # Coverage / test
24
+ .coverage
25
+ htmlcov/
26
+ .pytest_cache/
27
+
28
+ # Environment
29
+ .env
30
+
31
+ # rclone
32
+ rclone.conf
@@ -0,0 +1,15 @@
1
+ repos:
2
+ - repo: https://github.com/astral-sh/ruff-pre-commit
3
+ rev: v0.15.0
4
+ hooks:
5
+ - id: ruff-check
6
+ args: [--fix]
7
+ - id: ruff-format
8
+ - repo: local
9
+ hooks:
10
+ - id: ty-check
11
+ name: ty check
12
+ entry: uv run ty check
13
+ language: system
14
+ types: [python]
15
+ pass_filenames: false
@@ -0,0 +1 @@
1
+ 3.13
@@ -0,0 +1,22 @@
1
+ # django-rclone
2
+
3
+ Django package that wraps rclone for database and media file backups. Intended as a replacement for `django-dbbackup`.
4
+
5
+ The `django-dbbackup/` directory is included for reference only — it is not part of this project.
6
+
7
+ ## Document lookup
8
+ Use `context7` to check documentation of packages.
9
+
10
+ ## Development
11
+
12
+ ```bash
13
+ uv sync # Install dependencies
14
+ uv run ruff check . # Lint
15
+ uv run ruff format --check . # Check formatting
16
+ uv run ty check # Type check
17
+ uv run pytest # Run tests
18
+ ```
19
+
20
+ ## CI
21
+
22
+ GitHub Actions runs lint, type check, and tests on every push/PR. See `.github/workflows/ci.yml`.
@@ -0,0 +1,217 @@
1
+ Metadata-Version: 2.4
2
+ Name: django-rclone
3
+ Version: 0.1.0
4
+ Summary: rclone wrapper for Django database and media file backups
5
+ Project-URL: Repository, https://github.com/j/django-rclone
6
+ License-Expression: MIT
7
+ Classifier: Development Status :: 2 - Pre-Alpha
8
+ Classifier: Framework :: Django
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.13
13
+ Requires-Python: >=3.13
14
+ Requires-Dist: django>=4.2
15
+ Description-Content-Type: text/markdown
16
+
17
+ # django-rclone
18
+
19
+ Django database and media backup management commands, powered by [rclone](https://rclone.org/).
20
+
21
+ django-rclone bridges Django's database layer with rclone's file transfer layer. You get native database dumps piped directly to any of rclone's 70+ supported cloud storage backends -- no temp files, no intermediate archives, no Python reimplementations of what rclone already does.
22
+
23
+ ## Why rclone instead of Django Storages?
24
+
25
+ [django-dbbackup](https://github.com/Archmonger/django-dbbackup) is a mature and well-regarded backup solution. It wraps Django Storages for upload, implements GPG encryption in Python, handles gzip compression, and parses filenames with regex to manage backups.
26
+
27
+ django-rclone takes a different approach: **delegate everything that isn't Django-specific to rclone**.
28
+
29
+ | Concern | django-dbbackup | django-rclone |
30
+ |---|---|---|
31
+ | **Storage backends** | Django Storages (S3, GCS, etc.) | rclone (70+ backends natively) |
32
+ | **Encryption** | GPG subprocess wrapper in Python | rclone `crypt` remote |
33
+ | **Compression** | gzip in Python | rclone `compress` remote or `--compress` flag |
34
+ | **Media backup** | Tar archive, then upload | `rclone sync` (incremental, no archiving) |
35
+ | **Backup listing** | Filename regex parsing | `rclone lsjson` (structured JSON) |
36
+ | **Temp files** | `SpooledTemporaryFile` | None -- pipes directly via `rclone rcat` |
37
+ | **DB passwords** | Passed via CLI args (visible in `ps`) | Env vars for PostgreSQL/MySQL (`PGPASSWORD`, `MYSQL_PWD`) |
38
+
39
+ The result is significantly less code doing significantly less work. Storage abstraction, encryption, compression, and incremental sync are all rclone's problem -- django-rclone only owns what Django must own: database connectors, management commands, and signals.
40
+
41
+ ## Requirements
42
+
43
+ - Python 3.13+
44
+ - Django 4.2+
45
+ - [rclone](https://rclone.org/install/) installed and configured
46
+
47
+ ## Installation
48
+
49
+ ```bash
50
+ pip install django-rclone
51
+ ```
52
+
53
+ Add to your `INSTALLED_APPS`:
54
+
55
+ ```python
56
+ INSTALLED_APPS = [
57
+ # ...
58
+ "django_rclone",
59
+ ]
60
+ ```
61
+
62
+ Configure your rclone remote (see [rclone docs](https://rclone.org/docs/)):
63
+
64
+ ```bash
65
+ rclone config
66
+ ```
67
+
68
+ Then point django-rclone at it:
69
+
70
+ ```python
71
+ DJANGO_RCLONE = {
72
+ "REMOTE": "myremote:backups",
73
+ }
74
+ ```
75
+
76
+ ## Usage
77
+
78
+ ### Database backup and restore
79
+
80
+ ```bash
81
+ # Backup the default database
82
+ python manage.py dbbackup
83
+
84
+ # Backup a specific database
85
+ python manage.py dbbackup --database analytics
86
+
87
+ # Backup and clean old backups beyond retention count
88
+ python manage.py dbbackup --clean
89
+
90
+ # Restore from the latest backup
91
+ python manage.py dbrestore
92
+
93
+ # Restore a specific backup
94
+ python manage.py dbrestore --input-path default-2024-01-15-120000.dump
95
+
96
+ # Non-interactive restore (for automation)
97
+ python manage.py dbrestore --noinput --input-path default-2024-01-15-120000.dump
98
+ ```
99
+
100
+ ### Media backup and restore
101
+
102
+ ```bash
103
+ # Sync MEDIA_ROOT to remote (incremental -- only changed files transfer)
104
+ python manage.py mediabackup
105
+
106
+ # Sync remote back to MEDIA_ROOT
107
+ python manage.py mediarestore
108
+ ```
109
+
110
+ ### List backups
111
+
112
+ ```bash
113
+ # List all database backups
114
+ python manage.py listbackups
115
+
116
+ # Filter by database
117
+ python manage.py listbackups --database default
118
+
119
+ # List media files on remote
120
+ python manage.py listbackups --media
121
+ ```
122
+
123
+ ## Configuration
124
+
125
+ All settings live under the `DJANGO_RCLONE` dict in your Django settings:
126
+
127
+ ```python
128
+ DJANGO_RCLONE = {
129
+ # Required -- rclone remote and base path
130
+ "REMOTE": "myremote:backups",
131
+
132
+ # Optional -- rclone binary and config
133
+ "RCLONE_BINARY": "rclone", # Path to rclone binary
134
+ "RCLONE_CONFIG": None, # Path to rclone.conf (None uses default)
135
+ "RCLONE_FLAGS": [], # Extra flags for every rclone call
136
+
137
+ # Database backup settings
138
+ "DB_BACKUP_DIR": "db", # Subdirectory for DB backups
139
+ "DB_FILENAME_TEMPLATE": "{database}-{datetime}.{ext}", # Must start with {database}
140
+ "DB_DATE_FORMAT": "%Y-%m-%d-%H%M%S",
141
+ "DB_CLEANUP_KEEP": 10, # Keep N most recent backups per database
142
+
143
+ # Media backup settings
144
+ "MEDIA_BACKUP_DIR": "media", # Subdirectory for media backups
145
+
146
+ # Database connector overrides
147
+ "CONNECTORS": {}, # Per-database connector class overrides
148
+ "CONNECTOR_MAPPING": {}, # Engine-to-connector class overrides
149
+ }
150
+ ```
151
+
152
+ ### Encryption and compression
153
+
154
+ django-rclone does not implement encryption or compression. Instead, configure these at the rclone level where they belong:
155
+
156
+ **Encryption** -- use a [crypt remote](https://rclone.org/crypt/):
157
+
158
+ ```bash
159
+ rclone config create myremote-crypt crypt remote=myremote:backups password=your-password
160
+ ```
161
+
162
+ Then set `"REMOTE": "myremote-crypt:"` in your Django settings.
163
+
164
+ **Compression** -- use a [compress remote](https://rclone.org/compress/):
165
+
166
+ ```bash
167
+ rclone config create myremote-compressed compress remote=myremote:backups
168
+ ```
169
+
170
+ Or pass `--compress-level` via `RCLONE_FLAGS`.
171
+
172
+ ## Supported databases
173
+
174
+ | Database | Connector | Dump tool | Format |
175
+ |---|---|---|---|
176
+ | PostgreSQL | `PgDumpConnector` | `pg_dump` / `pg_restore` | Custom (binary) |
177
+ | PostGIS | `PgDumpGisConnector` | `pg_dump` / `pg_restore` | Custom (binary) |
178
+ | MySQL / MariaDB | `MysqlDumpConnector` | `mysqldump` / `mysql` | SQL text |
179
+ | SQLite | `SqliteConnector` | `sqlite3 .dump` | SQL text |
180
+ | MongoDB | `MongoDumpConnector` | `mongodump` / `mongorestore` | Archive (binary) |
181
+
182
+ GIS backends (`postgis`, `spatialite`, `gis/mysql`) and `django-prometheus` wrappers are also mapped automatically. See [connectors documentation](docs/connectors.md) for the full engine mapping table.
183
+
184
+ ## Signals
185
+
186
+ django-rclone sends Django signals before and after each operation:
187
+
188
+ ```python
189
+ from django_rclone.signals import pre_db_backup, post_db_backup
190
+
191
+ @receiver(post_db_backup)
192
+ def notify_on_backup(sender, database, path, **kwargs):
193
+ logger.info("Database %s backed up to %s", database, path)
194
+ ```
195
+
196
+ Available signals: `pre_db_backup`, `post_db_backup`, `pre_db_restore`, `post_db_restore`, `pre_media_backup`, `post_media_backup`, `pre_media_restore`, `post_media_restore`.
197
+
198
+ ## Architecture
199
+
200
+ ```
201
+ Management Commands (dbbackup, dbrestore, mediabackup, mediarestore, listbackups)
202
+ | |
203
+ DB Connectors rclone.py
204
+ (pg, mysql, sqlite, (subprocess wrapper)
205
+ mongodb)
206
+ | |
207
+ Database binary rclone binary
208
+ (70+ storage backends)
209
+ ```
210
+
211
+ Database dumps stream directly from the dump process into `rclone rcat` via Unix pipes. No intermediate files are written. Restores work in reverse: `rclone cat` streams into the database restore process.
212
+
213
+ Media backups use `rclone sync`, which is incremental by default -- only changed files are transferred.
214
+
215
+ ## License
216
+
217
+ MIT
@@ -0,0 +1,201 @@
1
+ # django-rclone
2
+
3
+ Django database and media backup management commands, powered by [rclone](https://rclone.org/).
4
+
5
+ django-rclone bridges Django's database layer with rclone's file transfer layer. You get native database dumps piped directly to any of rclone's 70+ supported cloud storage backends -- no temp files, no intermediate archives, no Python reimplementations of what rclone already does.
6
+
7
+ ## Why rclone instead of Django Storages?
8
+
9
+ [django-dbbackup](https://github.com/Archmonger/django-dbbackup) is a mature and well-regarded backup solution. It wraps Django Storages for upload, implements GPG encryption in Python, handles gzip compression, and parses filenames with regex to manage backups.
10
+
11
+ django-rclone takes a different approach: **delegate everything that isn't Django-specific to rclone**.
12
+
13
+ | Concern | django-dbbackup | django-rclone |
14
+ |---|---|---|
15
+ | **Storage backends** | Django Storages (S3, GCS, etc.) | rclone (70+ backends natively) |
16
+ | **Encryption** | GPG subprocess wrapper in Python | rclone `crypt` remote |
17
+ | **Compression** | gzip in Python | rclone `compress` remote or `--compress` flag |
18
+ | **Media backup** | Tar archive, then upload | `rclone sync` (incremental, no archiving) |
19
+ | **Backup listing** | Filename regex parsing | `rclone lsjson` (structured JSON) |
20
+ | **Temp files** | `SpooledTemporaryFile` | None -- pipes directly via `rclone rcat` |
21
+ | **DB passwords** | Passed via CLI args (visible in `ps`) | Env vars for PostgreSQL/MySQL (`PGPASSWORD`, `MYSQL_PWD`) |
22
+
23
+ The result is significantly less code doing significantly less work. Storage abstraction, encryption, compression, and incremental sync are all rclone's problem -- django-rclone only owns what Django must own: database connectors, management commands, and signals.
24
+
25
+ ## Requirements
26
+
27
+ - Python 3.13+
28
+ - Django 4.2+
29
+ - [rclone](https://rclone.org/install/) installed and configured
30
+
31
+ ## Installation
32
+
33
+ ```bash
34
+ pip install django-rclone
35
+ ```
36
+
37
+ Add to your `INSTALLED_APPS`:
38
+
39
+ ```python
40
+ INSTALLED_APPS = [
41
+ # ...
42
+ "django_rclone",
43
+ ]
44
+ ```
45
+
46
+ Configure your rclone remote (see [rclone docs](https://rclone.org/docs/)):
47
+
48
+ ```bash
49
+ rclone config
50
+ ```
51
+
52
+ Then point django-rclone at it:
53
+
54
+ ```python
55
+ DJANGO_RCLONE = {
56
+ "REMOTE": "myremote:backups",
57
+ }
58
+ ```
59
+
60
+ ## Usage
61
+
62
+ ### Database backup and restore
63
+
64
+ ```bash
65
+ # Backup the default database
66
+ python manage.py dbbackup
67
+
68
+ # Backup a specific database
69
+ python manage.py dbbackup --database analytics
70
+
71
+ # Backup and clean old backups beyond retention count
72
+ python manage.py dbbackup --clean
73
+
74
+ # Restore from the latest backup
75
+ python manage.py dbrestore
76
+
77
+ # Restore a specific backup
78
+ python manage.py dbrestore --input-path default-2024-01-15-120000.dump
79
+
80
+ # Non-interactive restore (for automation)
81
+ python manage.py dbrestore --noinput --input-path default-2024-01-15-120000.dump
82
+ ```
83
+
84
+ ### Media backup and restore
85
+
86
+ ```bash
87
+ # Sync MEDIA_ROOT to remote (incremental -- only changed files transfer)
88
+ python manage.py mediabackup
89
+
90
+ # Sync remote back to MEDIA_ROOT
91
+ python manage.py mediarestore
92
+ ```
93
+
94
+ ### List backups
95
+
96
+ ```bash
97
+ # List all database backups
98
+ python manage.py listbackups
99
+
100
+ # Filter by database
101
+ python manage.py listbackups --database default
102
+
103
+ # List media files on remote
104
+ python manage.py listbackups --media
105
+ ```
106
+
107
+ ## Configuration
108
+
109
+ All settings live under the `DJANGO_RCLONE` dict in your Django settings:
110
+
111
+ ```python
112
+ DJANGO_RCLONE = {
113
+ # Required -- rclone remote and base path
114
+ "REMOTE": "myremote:backups",
115
+
116
+ # Optional -- rclone binary and config
117
+ "RCLONE_BINARY": "rclone", # Path to rclone binary
118
+ "RCLONE_CONFIG": None, # Path to rclone.conf (None uses default)
119
+ "RCLONE_FLAGS": [], # Extra flags for every rclone call
120
+
121
+ # Database backup settings
122
+ "DB_BACKUP_DIR": "db", # Subdirectory for DB backups
123
+ "DB_FILENAME_TEMPLATE": "{database}-{datetime}.{ext}", # Must start with {database}
124
+ "DB_DATE_FORMAT": "%Y-%m-%d-%H%M%S",
125
+ "DB_CLEANUP_KEEP": 10, # Keep N most recent backups per database
126
+
127
+ # Media backup settings
128
+ "MEDIA_BACKUP_DIR": "media", # Subdirectory for media backups
129
+
130
+ # Database connector overrides
131
+ "CONNECTORS": {}, # Per-database connector class overrides
132
+ "CONNECTOR_MAPPING": {}, # Engine-to-connector class overrides
133
+ }
134
+ ```
135
+
136
+ ### Encryption and compression
137
+
138
+ django-rclone does not implement encryption or compression. Instead, configure these at the rclone level where they belong:
139
+
140
+ **Encryption** -- use a [crypt remote](https://rclone.org/crypt/):
141
+
142
+ ```bash
143
+ rclone config create myremote-crypt crypt remote=myremote:backups password=your-password
144
+ ```
145
+
146
+ Then set `"REMOTE": "myremote-crypt:"` in your Django settings.
147
+
148
+ **Compression** -- use a [compress remote](https://rclone.org/compress/):
149
+
150
+ ```bash
151
+ rclone config create myremote-compressed compress remote=myremote:backups
152
+ ```
153
+
154
+ Or pass `--compress-level` via `RCLONE_FLAGS`.
155
+
156
+ ## Supported databases
157
+
158
+ | Database | Connector | Dump tool | Format |
159
+ |---|---|---|---|
160
+ | PostgreSQL | `PgDumpConnector` | `pg_dump` / `pg_restore` | Custom (binary) |
161
+ | PostGIS | `PgDumpGisConnector` | `pg_dump` / `pg_restore` | Custom (binary) |
162
+ | MySQL / MariaDB | `MysqlDumpConnector` | `mysqldump` / `mysql` | SQL text |
163
+ | SQLite | `SqliteConnector` | `sqlite3 .dump` | SQL text |
164
+ | MongoDB | `MongoDumpConnector` | `mongodump` / `mongorestore` | Archive (binary) |
165
+
166
+ GIS backends (`postgis`, `spatialite`, `gis/mysql`) and `django-prometheus` wrappers are also mapped automatically. See [connectors documentation](docs/connectors.md) for the full engine mapping table.
167
+
168
+ ## Signals
169
+
170
+ django-rclone sends Django signals before and after each operation:
171
+
172
+ ```python
173
+ from django_rclone.signals import pre_db_backup, post_db_backup
174
+
175
+ @receiver(post_db_backup)
176
+ def notify_on_backup(sender, database, path, **kwargs):
177
+ logger.info("Database %s backed up to %s", database, path)
178
+ ```
179
+
180
+ Available signals: `pre_db_backup`, `post_db_backup`, `pre_db_restore`, `post_db_restore`, `pre_media_backup`, `post_media_backup`, `pre_media_restore`, `post_media_restore`.
181
+
182
+ ## Architecture
183
+
184
+ ```
185
+ Management Commands (dbbackup, dbrestore, mediabackup, mediarestore, listbackups)
186
+ | |
187
+ DB Connectors rclone.py
188
+ (pg, mysql, sqlite, (subprocess wrapper)
189
+ mongodb)
190
+ | |
191
+ Database binary rclone binary
192
+ (70+ storage backends)
193
+ ```
194
+
195
+ Database dumps stream directly from the dump process into `rclone rcat` via Unix pipes. No intermediate files are written. Restores work in reverse: `rclone cat` streams into the database restore process.
196
+
197
+ Media backups use `rclone sync`, which is incremental by default -- only changed files are transferred.
198
+
199
+ ## License
200
+
201
+ MIT