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.
- django_rclone-0.1.0/.github/dependabot.yml +11 -0
- django_rclone-0.1.0/.github/workflows/ci.yml +37 -0
- django_rclone-0.1.0/.github/workflows/publish.yml +17 -0
- django_rclone-0.1.0/.gitignore +32 -0
- django_rclone-0.1.0/.pre-commit-config.yaml +15 -0
- django_rclone-0.1.0/.python-version +1 -0
- django_rclone-0.1.0/CLAUDE.md +22 -0
- django_rclone-0.1.0/PKG-INFO +217 -0
- django_rclone-0.1.0/README.md +201 -0
- django_rclone-0.1.0/docs/commands.md +200 -0
- django_rclone-0.1.0/docs/configuration.md +216 -0
- django_rclone-0.1.0/docs/connectors.md +204 -0
- django_rclone-0.1.0/docs/getting-started.md +123 -0
- django_rclone-0.1.0/docs/migration-from-dbbackup.md +189 -0
- django_rclone-0.1.0/docs/signals.md +110 -0
- django_rclone-0.1.0/pyproject.toml +51 -0
- django_rclone-0.1.0/src/django_rclone/__init__.py +0 -0
- django_rclone-0.1.0/src/django_rclone/apps.py +7 -0
- django_rclone-0.1.0/src/django_rclone/db/__init__.py +0 -0
- django_rclone-0.1.0/src/django_rclone/db/base.py +49 -0
- django_rclone-0.1.0/src/django_rclone/db/mongodb.py +68 -0
- django_rclone-0.1.0/src/django_rclone/db/mysql.py +57 -0
- django_rclone-0.1.0/src/django_rclone/db/postgresql.py +90 -0
- django_rclone-0.1.0/src/django_rclone/db/registry.py +62 -0
- django_rclone-0.1.0/src/django_rclone/db/sqlite.py +24 -0
- django_rclone-0.1.0/src/django_rclone/exceptions.py +25 -0
- django_rclone-0.1.0/src/django_rclone/filenames.py +83 -0
- django_rclone-0.1.0/src/django_rclone/management/__init__.py +0 -0
- django_rclone-0.1.0/src/django_rclone/management/commands/__init__.py +0 -0
- django_rclone-0.1.0/src/django_rclone/management/commands/dbbackup.py +124 -0
- django_rclone-0.1.0/src/django_rclone/management/commands/dbrestore.py +119 -0
- django_rclone-0.1.0/src/django_rclone/management/commands/listbackups.py +85 -0
- django_rclone-0.1.0/src/django_rclone/management/commands/mediabackup.py +36 -0
- django_rclone-0.1.0/src/django_rclone/management/commands/mediarestore.py +36 -0
- django_rclone-0.1.0/src/django_rclone/rclone.py +105 -0
- django_rclone-0.1.0/src/django_rclone/settings.py +31 -0
- django_rclone-0.1.0/src/django_rclone/signals.py +10 -0
- django_rclone-0.1.0/tests/__init__.py +0 -0
- django_rclone-0.1.0/tests/settings.py +18 -0
- django_rclone-0.1.0/tests/test_commands.py +336 -0
- django_rclone-0.1.0/tests/test_db.py +288 -0
- django_rclone-0.1.0/tests/test_exceptions.py +21 -0
- django_rclone-0.1.0/tests/test_filenames.py +33 -0
- django_rclone-0.1.0/tests/test_rclone.py +186 -0
- django_rclone-0.1.0/tests/test_settings.py +33 -0
- django_rclone-0.1.0/tests/test_signals.py +32 -0
- django_rclone-0.1.0/uv.lock +315 -0
|
@@ -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
|