Name | gando JSON |
Version |
1.0.3
JSON |
| download |
home_page | https://github.com/navidsoleymani/gando.git |
Summary | A framework based on Django that has tried to gather together the tools needed in the process of creating a large project. |
upload_time | 2025-08-26 10:43:56 |
maintainer | None |
docs_url | None |
author | Hydra |
requires_python | >=3.8 |
license | None |
keywords |
django
|
VCS |
 |
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# Gando — Django toolkit & conventions for Horin Software Group
[](https://pypi.org/project/gando) <!-- placeholder -->
[](./LICENSE)

**Gando** is a collection of batteries-included tools, conventions and scaffolding utilities built on top of Django to
standardize and accelerate development for the Horin engineering teams.
Named after *Gando* — a small, native crocodile of Sistan and Baluchestan — the project is compact, tough and
purpose-built for the local needs of your org.
---
## Quick summary
* **What it is:** A small framework of opinionated building blocks for Django projects: base abstract models, useful
model fields (image + validators), admin base classes, API response/exception schemas, request helpers, scaffolding
management commands (`startmodel`, `startapi`, `startservice`, `startinterface`, ...), and utilities (image
converters/uploaders, string casings, etc).
* **Why:** Aligns Horin internal projects around shared error/response shapes, admin patterns, and developer
ergonomics—reduces copy/paste and onboarding time.
* **Status:** Actively developed and extended; features are added on demand.
---
# Table of contents
1. [Key features](#key-features)
2. [Install](#install)
3. [Quickstart (5–10 min)](#quickstart-5-10-min)
4. [Core concepts & architecture](#core-concepts--architecture)
5. [Examples (models, admin, API flow)](#examples-models-admin-api-flow)
6. [Management commands / scaffolding](#management-commands--scaffolding)
7. [Response & request contract](#response--request-contract)
8. [Important notes, gotchas & recommended fixes](#important-notes-gotchas--recommended-fixes)
9. [Development, tests & CI](#development-tests--ci)
10. [Roadmap & contributing](#roadmap--contributing)
11. [License & contact](#license--contact)
---
## Key features
* Opinionated base models: `AbstractBaseModel`, `WhiteAbstractBaseModel`, `AbstractBaseModelFaster` (history-enabled,
timestamps, availability flag).
* `AvailableManager` (named `Manager` in current code) that filters `available=1` by default.
* Rich image support: `ImageField` (multi-subfields), `ImageProperty` descriptor, `BlurBase64Field` computed preview.
* Validators & typed model fields: `PhoneNumberField`, `UsernameField`, `PasswordField`, `BooleanNumberField`.
* `BaseModelAdmin` — unified Admin list/filters/readonly behavior and image field rendering.
* API scaffolding: `ResponseSchema`, `RequestSchema`, `Base` / `BaseInterface` for method dispatch and unified response
format.
* Scaffolding commands to create repositories, schemas, APIs, interfaces, services and models automatically following
the gando conventions.
* Utilities: string casings, image converter (small blur base64), uploaders, and request/response helpers.
---
## Install
```bash
# (recommended: inside virtualenv)
pip install gando
```
or for local editable development:
```bash
git clone https://github.com/navidsoleymani/gando.git
cd gando
pip install -e .
```
Minimum safe `setup.py`/`pyproject` expectations:
* `python_requires='>=3.8'`
* Pin runtime dependencies more conservatively in the future, e.g. `Django>=4.2,<5.0`, `djangorestframework>=3.12`.
---
## Quickstart (minimal)
1. **Add to `INSTALLED_APPS`** in `settings.py`:
```py
INSTALLED_APPS = [
# ...
"gando",
# other apps
]
```
2. **Use an abstract model**:
```py
from gando.models import AbstractBaseModel # path may vary
class Article(AbstractBaseModel):
title = models.CharField(max_length=300)
body = models.TextField()
```
3. **Use the ImageField helper**:
```py
from gando.models import AbstractBaseModel, ImageField
class Product(AbstractBaseModel):
image = ImageField()
title = models.CharField(max_length=255)
```
4. **Admin** — reuse the standard admin scaffold:
```py
from django.contrib import admin
from gando.admin import BaseModelAdmin
from .models import Product
@admin.register(Product)
class ProductAdmin(BaseModelAdmin):
list_display = ['title', 'image']
```
5. **Create scaffolds** (from project root):
```bash
python manage.py startmodel -al your_app_label -mn Product
python manage.py startapi -al your_app_label -an Product
python manage.py startservice -al your_app_label -sn Product
python manage.py startinterface -al your_app_label -in Product
```
(The flags are: `-al/--applabel`, `-mn/--modelname`, `-an/--apiname`, `-sn/--servicename`, `-in/--interfacename`.)
6. **Migrate** and run:
```bash
python manage.py makemigrations
python manage.py migrate
python manage.py runserver
```
---
## Core concepts & architecture
**Design philosophies** (applies across gando):
* **Conventions over configuration** — provide sane defaults (timestamps, availability, admin lists) so teams are
consistent.
* **Separation of concerns** — `architectures` contains `apis`, `interfaces`, `services`, `models` and `serializers` and
enforces a flow: `API / Interface -> Service -> Repo/Models -> Serializers -> Response`.
* **Unified contracts** — server and client share `RequestSchema` / `ResponseSchema` shapes to avoid divergence.
* **Scaffold-first** — management commands create consistent package/module layout (`repo`, `schemas`, `apis`,
`services`).
**Typical request flow**:
1. HTTP request arrives at an API view (generated by scaffolding).
2. Request parsed into `RequestSchema`.
3. `BaseInterface` or `Base` dispatches to a method (`get`, `post`, etc).
4. Interface calls a `Service` that encapsulates business logic.
5. `Service` interacts with `repo` models and returns domain `data`.
6. Response wrapped by `ResponseSchema` and returned.
---
## Examples — Model → Service → API → Response
**Model**:
```py
from gando.models import AbstractBaseModel, ImageField
class Banner(AbstractBaseModel):
title = models.CharField(max_length=200)
image = ImageField()
```
**Service (conceptual)**:
```py
from gando.architectures.services import BaseService
class BannerService(BaseService):
def get_banner(self, banner_id):
banner = Banner.objects.filter(id=banner_id).first()
if not banner:
return {"error": "not_found"}, 404
return {"banner": BannerSchema.from_orm(banner).dict()}, 200
```
**API / Interface (conceptual)**:
```py
from gando.architectures.apis import BaseAPI # or BaseInterface
class BannerAPI(BaseAPI):
def get(self, request, banner_id):
data, status = BannerService().get_banner(banner_id)
return ResponseSchema(success=(status == 200), status_code=status, data=data)
```
**Client-side Response wrapper** — `BaseResponseSchema` expects the JSON shape used across gando.
---
## Management commands / scaffolding (details)
Gando provides a set of management commands that scaffold folders and files in the target app:
* `startmodel -al <app_label> -mn <modelname>`
Creates `repo/models/__<ModelName>.py`, updates `repo/models/__init__.py`, app-level `models.py`, `admin.py` entries,
`repo/schemas/models/__<modelname>.py`, and URL includes.
* `startapi -al <app_label> -an <apiname>`
Creates `repo/apis/__<ApiName>.py` with a base API class.
* `startservice -al <app_label> -sn <servicename>`
Creates service module templates and schema folders.
* `startinterface -al <app_label> -in <interfacename>`
Creates interface templates under `repo/interfaces`.
**Note:** commands rely on `settings.BASE_DIR` and the app folder structure; run them from the project root.
---
## Response & request contract
Gando standardizes API payloads. A canonical successful response includes:
```json
{
"success": true,
"status_code": 200,
"has_warning": false,
"exception_status": false,
"monitor": {},
"messenger": [],
"many": false,
"data": {
/* object or list depending on many */
},
"development_messages": {}
}
```
`ResponseSchema` (server) and `BaseResponseSchema` (client helpers) map to the same shape. Use these everywhere to keep
client & server consistent, reduce parsing errors and simplify error handling.
---
## Important notes, gotchas & recommended fixes
I reviewed the code you supplied deeply. Below are concrete findings and recommendations to make Gando safer, more
robust and production-friendly.
### 1. `Manager` naming & `available` field
* **Issue:** Generic name `Manager`. It's better to name `AvailableManager` or `ActiveManager`.
* **Recommendation:** Consider using `BooleanField` if `available` is binary; if you anticipate more states, keep
integer but rename to `status`/`availability_state` with an Enum.
### 2. `QueryDictSerializer` problems
* `__image_field_name_parser` uses a `equal` variable that is not correctly reset per loop — this creates incorrect
prefix matching.
* `__updater` function is fragile and can lose values or produce inconsistent structures for nested merges.
* `__media_url` uses a bare `except:` — this hides unrelated errors.
**Fix suggestions (high level):**
* Replace prefix comparison logic with `str.startswith(prefix)`.
* Implement a robust `deep_merge(a, b)` for dictionaries where `b` values override or are appended appropriately.
* Use `getattr(settings, "MEDIA_URL", "")` instead of try/except.
*Short fixed sketch (extract):*
```py
# safer prefix check
def __image_field_name_parser(self, field_name):
for img in self.image_fields_name:
if field_name.startswith(img + "_"):
return [img, field_name[len(img) + 1:]]
return [field_name]
# safer media url
from django.conf import settings
@property
def __media_url(self):
return getattr(settings, 'MEDIA_URL', '')
```
(I can provide a full refactor patch if you want — it will be longer but makes the serializer robust.)
### 3. `BlurBase64Field.pre_save` and remote storage
* **Issue:** `small_blur_base64(_src.file.name)` assumes a local filename and direct filesystem access. If you use
remote storages (S3, GCS) this will fail.
* **Recommendation:** Read file content via Django storage API:
```py
from django.core.files.storage import default_storage
if _src:
try:
with default_storage.open(_src.name, 'rb') as fh:
blur = small_blur_base64(fh.read()) # accept bytes in small_blur_base64
setattr(model_instance, self.attname, blur)
except Exception:
# handle/log but don't silence unexpected exceptions
raise
```
Also consider moving `small_blur_base64` processing off the request thread to a background job (Celery) or compute it
once on upload.
### 4. Bare `except:` usage
* There are several `except:` usages that silence all exceptions. Replace with targeted exception types, or at least log
and re-raise unexpected ones.
### 5. `BaseModelAdmin` behavior & names
* `list_display` setter uses `id_`, `available_` names which are fine, but keep docstrings and explicit `list_display`
examples in README.
* Document `image_fields_name_list` usage in admin to ensure image fieldsets are created.
### 6. Management commands argument handling
* The command handlers expect `kwargs` dict and set `self.app_label = kwargs`. The setter then reads
`kwargs.get('applabel')`. This works but is unusual — be explicit in docs that flags are named `-al/--applabel` etc.
Also check behavior when flags are missing: the code raises `CommandError` as expected.
### 7. History size & retention
* `HistoricalRecords` on many models can balloon DB size. Add guidance for history pruning or retention policies.
### 8. Packaging / dependencies
* In `setup.py` you currently list unpinned dependencies: prefer minimum versions and ranges for stability, e.g.
`Django>=4.2,<5.0`, `djangorestframework>=3.12,<4.0`.
---
## Development, tests & CI
Recommended development stack for the repo:
* **Formatter & linters:** Black, isort, flake8
* **Type checks:** mypy (use strictness progressively)
* **Testing:** pytest + pytest-django
* **Coverage:** coveralls or codecov; aim for > 80% initially.
* **Pre-commit hooks:** pre-commit for formatting and sanity checks.
* **Docs:** Sphinx with `sphinx-autodoc` + READTHEDOCS pipeline
* **CI:** GitHub Actions (lint → tests → packaging → publish on tags)
Example `.github/workflows/ci.yml` stages:
1. Install dependencies (pinned).
2. Run `black --check`, `isort --check`, `flake8`.
3. Run tests with `pytest`.
4. Publish wheel on tag.
---
## Roadmap (suggested)
* **v0.1.x**: Stabilize current APIs, fix QueryDictSerializer, address image storage, add tests & docs.
* **v0.2.x**: Add optional DRF/async adaptors, Celery tasks for image processing, plugin hooks.
* **v1.0.0**: Public stable release with SemVer, complete docs, examples project and migration guides.
Use Semantic Versioning (MAJOR.MINOR.PATCH) and maintain a `CHANGELOG.md` following *Keep a Changelog*.
---
## Contributing
1. Fork the repo and create a feature branch.
2. Run tests locally.
3. Format code with `black` and check `flake8`.
4. Open PR describing the change and tests.
5. Maintainers will review and merge after CI passes.
Please include unit tests for behavior changes and update docs when public APIs change.
---
## License & contact
Gando is released under the **MIT License**. See `LICENSE` for details.
Author: `Hydra` ([navidsoleymani@ymail.com](mailto:navidsoleymani@ymail.com)) — repository:
`https://github.com/navidsoleymani/gando.git`.
---
## Appendix — Short patch examples
**1) Safer `__media_url`:**
```py
from django.conf import settings
@property
def __media_url(self):
return getattr(settings, 'MEDIA_URL', '')
```
**2) Simpler image prefix parser:**
```py
def __image_field_name_parser(self, field_name):
# return [prefix, suffix] if field_name starts with any image prefix
for img in self.image_fields_name:
prefix = f'{img}_'
if field_name.startswith(prefix):
return [img, field_name[len(prefix):]]
return [field_name]
```
**3) Example `deep_merge` (dict merge):**
```py
def deep_merge(a, b):
if not isinstance(a, dict) or not isinstance(b, dict):
return b
out = dict(a)
for k, v in b.items():
if k in out and isinstance(out[k], dict) and isinstance(v, dict):
out[k] = deep_merge(out[k], v)
elif k in out and isinstance(out[k], list) and isinstance(v, list):
out[k] = out[k] + v
else:
out[k] = v
return out
```
---
## Final note
You already have a strong, well-structured foundation. With a few fixes (robust serializer merging, safe storage access,
explicit exception handling) and solid test coverage, Gando will be a great, reliable toolkit for Horin projects.
If you want, I can now:
* produce a **full, polished `README.md`** file ready to replace the one in your repo (I can drop it into the `canmore`
canvas or paste it here), **or**
* prepare a PR-style patch with the exact code changes for the `QueryDictSerializer`, `BlurBase64Field.pre_save`, and
other issues I flagged.
Which of those do you want me to do next?
Raw data
{
"_id": null,
"home_page": "https://github.com/navidsoleymani/gando.git",
"name": "gando",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": "django",
"author": "Hydra",
"author_email": "navidsoleymani@ymail.com",
"download_url": "https://files.pythonhosted.org/packages/30/bf/c82263c4790c19344b826478dccdf851d82f869c63682e821c92d5c3b5ed/gando-1.0.3.tar.gz",
"platform": null,
"description": "# Gando \u2014 Django toolkit & conventions for Horin Software Group\n\n[](https://pypi.org/project/gando) <!-- placeholder -->\n[](./LICENSE)\n\n\n**Gando** is a collection of batteries-included tools, conventions and scaffolding utilities built on top of Django to\nstandardize and accelerate development for the Horin engineering teams.\nNamed after *Gando* \u2014 a small, native crocodile of Sistan and Baluchestan \u2014 the project is compact, tough and\npurpose-built for the local needs of your org.\n\n---\n\n## Quick summary\n\n* **What it is:** A small framework of opinionated building blocks for Django projects: base abstract models, useful\n model fields (image + validators), admin base classes, API response/exception schemas, request helpers, scaffolding\n management commands (`startmodel`, `startapi`, `startservice`, `startinterface`, ...), and utilities (image\n converters/uploaders, string casings, etc).\n* **Why:** Aligns Horin internal projects around shared error/response shapes, admin patterns, and developer\n ergonomics\u2014reduces copy/paste and onboarding time.\n* **Status:** Actively developed and extended; features are added on demand.\n\n---\n\n# Table of contents\n\n1. [Key features](#key-features)\n2. [Install](#install)\n3. [Quickstart (5\u201310 min)](#quickstart-5-10-min)\n4. [Core concepts & architecture](#core-concepts--architecture)\n5. [Examples (models, admin, API flow)](#examples-models-admin-api-flow)\n6. [Management commands / scaffolding](#management-commands--scaffolding)\n7. [Response & request contract](#response--request-contract)\n8. [Important notes, gotchas & recommended fixes](#important-notes-gotchas--recommended-fixes)\n9. [Development, tests & CI](#development-tests--ci)\n10. [Roadmap & contributing](#roadmap--contributing)\n11. [License & contact](#license--contact)\n\n---\n\n## Key features\n\n* Opinionated base models: `AbstractBaseModel`, `WhiteAbstractBaseModel`, `AbstractBaseModelFaster` (history-enabled,\n timestamps, availability flag).\n* `AvailableManager` (named `Manager` in current code) that filters `available=1` by default.\n* Rich image support: `ImageField` (multi-subfields), `ImageProperty` descriptor, `BlurBase64Field` computed preview.\n* Validators & typed model fields: `PhoneNumberField`, `UsernameField`, `PasswordField`, `BooleanNumberField`.\n* `BaseModelAdmin` \u2014 unified Admin list/filters/readonly behavior and image field rendering.\n* API scaffolding: `ResponseSchema`, `RequestSchema`, `Base` / `BaseInterface` for method dispatch and unified response\n format.\n* Scaffolding commands to create repositories, schemas, APIs, interfaces, services and models automatically following\n the gando conventions.\n* Utilities: string casings, image converter (small blur base64), uploaders, and request/response helpers.\n\n---\n\n## Install\n\n```bash\n# (recommended: inside virtualenv)\npip install gando\n```\n\nor for local editable development:\n\n```bash\ngit clone https://github.com/navidsoleymani/gando.git\ncd gando\npip install -e .\n```\n\nMinimum safe `setup.py`/`pyproject` expectations:\n\n* `python_requires='>=3.8'`\n* Pin runtime dependencies more conservatively in the future, e.g. `Django>=4.2,<5.0`, `djangorestframework>=3.12`.\n\n---\n\n## Quickstart (minimal)\n\n1. **Add to `INSTALLED_APPS`** in `settings.py`:\n\n```py\nINSTALLED_APPS = [\n # ...\n \"gando\",\n # other apps\n]\n```\n\n2. **Use an abstract model**:\n\n```py\nfrom gando.models import AbstractBaseModel # path may vary\n\n\nclass Article(AbstractBaseModel):\n title = models.CharField(max_length=300)\n body = models.TextField()\n```\n\n3. **Use the ImageField helper**:\n\n```py\nfrom gando.models import AbstractBaseModel, ImageField\n\n\nclass Product(AbstractBaseModel):\n image = ImageField()\n title = models.CharField(max_length=255)\n```\n\n4. **Admin** \u2014 reuse the standard admin scaffold:\n\n```py\nfrom django.contrib import admin\nfrom gando.admin import BaseModelAdmin\nfrom .models import Product\n\n\n@admin.register(Product)\nclass ProductAdmin(BaseModelAdmin):\n list_display = ['title', 'image']\n```\n\n5. **Create scaffolds** (from project root):\n\n```bash\npython manage.py startmodel -al your_app_label -mn Product\npython manage.py startapi -al your_app_label -an Product\npython manage.py startservice -al your_app_label -sn Product\npython manage.py startinterface -al your_app_label -in Product\n```\n\n(The flags are: `-al/--applabel`, `-mn/--modelname`, `-an/--apiname`, `-sn/--servicename`, `-in/--interfacename`.)\n\n6. **Migrate** and run:\n\n```bash\npython manage.py makemigrations\npython manage.py migrate\npython manage.py runserver\n```\n\n---\n\n## Core concepts & architecture\n\n**Design philosophies** (applies across gando):\n\n* **Conventions over configuration** \u2014 provide sane defaults (timestamps, availability, admin lists) so teams are\n consistent.\n* **Separation of concerns** \u2014 `architectures` contains `apis`, `interfaces`, `services`, `models` and `serializers` and\n enforces a flow: `API / Interface -> Service -> Repo/Models -> Serializers -> Response`.\n* **Unified contracts** \u2014 server and client share `RequestSchema` / `ResponseSchema` shapes to avoid divergence.\n* **Scaffold-first** \u2014 management commands create consistent package/module layout (`repo`, `schemas`, `apis`,\n `services`).\n\n**Typical request flow**:\n\n1. HTTP request arrives at an API view (generated by scaffolding).\n2. Request parsed into `RequestSchema`.\n3. `BaseInterface` or `Base` dispatches to a method (`get`, `post`, etc).\n4. Interface calls a `Service` that encapsulates business logic.\n5. `Service` interacts with `repo` models and returns domain `data`.\n6. Response wrapped by `ResponseSchema` and returned.\n\n---\n\n## Examples \u2014 Model \u2192 Service \u2192 API \u2192 Response\n\n**Model**:\n\n```py\nfrom gando.models import AbstractBaseModel, ImageField\n\n\nclass Banner(AbstractBaseModel):\n title = models.CharField(max_length=200)\n image = ImageField()\n```\n\n**Service (conceptual)**:\n\n```py\nfrom gando.architectures.services import BaseService\n\n\nclass BannerService(BaseService):\n def get_banner(self, banner_id):\n banner = Banner.objects.filter(id=banner_id).first()\n if not banner:\n return {\"error\": \"not_found\"}, 404\n return {\"banner\": BannerSchema.from_orm(banner).dict()}, 200\n```\n\n**API / Interface (conceptual)**:\n\n```py\nfrom gando.architectures.apis import BaseAPI # or BaseInterface\n\n\nclass BannerAPI(BaseAPI):\n def get(self, request, banner_id):\n data, status = BannerService().get_banner(banner_id)\n return ResponseSchema(success=(status == 200), status_code=status, data=data)\n```\n\n**Client-side Response wrapper** \u2014 `BaseResponseSchema` expects the JSON shape used across gando.\n\n---\n\n## Management commands / scaffolding (details)\n\nGando provides a set of management commands that scaffold folders and files in the target app:\n\n* `startmodel -al <app_label> -mn <modelname>`\n Creates `repo/models/__<ModelName>.py`, updates `repo/models/__init__.py`, app-level `models.py`, `admin.py` entries,\n `repo/schemas/models/__<modelname>.py`, and URL includes.\n\n* `startapi -al <app_label> -an <apiname>`\n Creates `repo/apis/__<ApiName>.py` with a base API class.\n\n* `startservice -al <app_label> -sn <servicename>`\n Creates service module templates and schema folders.\n\n* `startinterface -al <app_label> -in <interfacename>`\n Creates interface templates under `repo/interfaces`.\n\n**Note:** commands rely on `settings.BASE_DIR` and the app folder structure; run them from the project root.\n\n---\n\n## Response & request contract\n\nGando standardizes API payloads. A canonical successful response includes:\n\n```json\n{\n \"success\": true,\n \"status_code\": 200,\n \"has_warning\": false,\n \"exception_status\": false,\n \"monitor\": {},\n \"messenger\": [],\n \"many\": false,\n \"data\": {\n /* object or list depending on many */\n },\n \"development_messages\": {}\n}\n```\n\n`ResponseSchema` (server) and `BaseResponseSchema` (client helpers) map to the same shape. Use these everywhere to keep\nclient & server consistent, reduce parsing errors and simplify error handling.\n\n---\n\n## Important notes, gotchas & recommended fixes\n\nI reviewed the code you supplied deeply. Below are concrete findings and recommendations to make Gando safer, more\nrobust and production-friendly.\n\n### 1. `Manager` naming & `available` field\n\n* **Issue:** Generic name `Manager`. It's better to name `AvailableManager` or `ActiveManager`.\n* **Recommendation:** Consider using `BooleanField` if `available` is binary; if you anticipate more states, keep\n integer but rename to `status`/`availability_state` with an Enum.\n\n### 2. `QueryDictSerializer` problems\n\n* `__image_field_name_parser` uses a `equal` variable that is not correctly reset per loop \u2014 this creates incorrect\n prefix matching.\n* `__updater` function is fragile and can lose values or produce inconsistent structures for nested merges.\n* `__media_url` uses a bare `except:` \u2014 this hides unrelated errors.\n\n**Fix suggestions (high level):**\n\n* Replace prefix comparison logic with `str.startswith(prefix)`.\n* Implement a robust `deep_merge(a, b)` for dictionaries where `b` values override or are appended appropriately.\n* Use `getattr(settings, \"MEDIA_URL\", \"\")` instead of try/except.\n\n*Short fixed sketch (extract):*\n\n```py\n# safer prefix check\ndef __image_field_name_parser(self, field_name):\n for img in self.image_fields_name:\n if field_name.startswith(img + \"_\"):\n return [img, field_name[len(img) + 1:]]\n return [field_name]\n\n\n# safer media url\nfrom django.conf import settings\n\n\n@property\ndef __media_url(self):\n return getattr(settings, 'MEDIA_URL', '')\n```\n\n(I can provide a full refactor patch if you want \u2014 it will be longer but makes the serializer robust.)\n\n### 3. `BlurBase64Field.pre_save` and remote storage\n\n* **Issue:** `small_blur_base64(_src.file.name)` assumes a local filename and direct filesystem access. If you use\n remote storages (S3, GCS) this will fail.\n* **Recommendation:** Read file content via Django storage API:\n\n```py\nfrom django.core.files.storage import default_storage\n\nif _src:\n try:\n with default_storage.open(_src.name, 'rb') as fh:\n blur = small_blur_base64(fh.read()) # accept bytes in small_blur_base64\n setattr(model_instance, self.attname, blur)\n except Exception:\n # handle/log but don't silence unexpected exceptions\n raise\n```\n\nAlso consider moving `small_blur_base64` processing off the request thread to a background job (Celery) or compute it\nonce on upload.\n\n### 4. Bare `except:` usage\n\n* There are several `except:` usages that silence all exceptions. Replace with targeted exception types, or at least log\n and re-raise unexpected ones.\n\n### 5. `BaseModelAdmin` behavior & names\n\n* `list_display` setter uses `id_`, `available_` names which are fine, but keep docstrings and explicit `list_display`\n examples in README.\n* Document `image_fields_name_list` usage in admin to ensure image fieldsets are created.\n\n### 6. Management commands argument handling\n\n* The command handlers expect `kwargs` dict and set `self.app_label = kwargs`. The setter then reads\n `kwargs.get('applabel')`. This works but is unusual \u2014 be explicit in docs that flags are named `-al/--applabel` etc.\n Also check behavior when flags are missing: the code raises `CommandError` as expected.\n\n### 7. History size & retention\n\n* `HistoricalRecords` on many models can balloon DB size. Add guidance for history pruning or retention policies.\n\n### 8. Packaging / dependencies\n\n* In `setup.py` you currently list unpinned dependencies: prefer minimum versions and ranges for stability, e.g.\n `Django>=4.2,<5.0`, `djangorestframework>=3.12,<4.0`.\n\n---\n\n## Development, tests & CI\n\nRecommended development stack for the repo:\n\n* **Formatter & linters:** Black, isort, flake8\n* **Type checks:** mypy (use strictness progressively)\n* **Testing:** pytest + pytest-django\n* **Coverage:** coveralls or codecov; aim for > 80% initially.\n* **Pre-commit hooks:** pre-commit for formatting and sanity checks.\n* **Docs:** Sphinx with `sphinx-autodoc` + READTHEDOCS pipeline\n* **CI:** GitHub Actions (lint \u2192 tests \u2192 packaging \u2192 publish on tags)\n\nExample `.github/workflows/ci.yml` stages:\n\n1. Install dependencies (pinned).\n2. Run `black --check`, `isort --check`, `flake8`.\n3. Run tests with `pytest`.\n4. Publish wheel on tag.\n\n---\n\n## Roadmap (suggested)\n\n* **v0.1.x**: Stabilize current APIs, fix QueryDictSerializer, address image storage, add tests & docs.\n* **v0.2.x**: Add optional DRF/async adaptors, Celery tasks for image processing, plugin hooks.\n* **v1.0.0**: Public stable release with SemVer, complete docs, examples project and migration guides.\n\nUse Semantic Versioning (MAJOR.MINOR.PATCH) and maintain a `CHANGELOG.md` following *Keep a Changelog*.\n\n---\n\n## Contributing\n\n1. Fork the repo and create a feature branch.\n2. Run tests locally.\n3. Format code with `black` and check `flake8`.\n4. Open PR describing the change and tests.\n5. Maintainers will review and merge after CI passes.\n\nPlease include unit tests for behavior changes and update docs when public APIs change.\n\n---\n\n## License & contact\n\nGando is released under the **MIT License**. See `LICENSE` for details.\nAuthor: `Hydra` ([navidsoleymani@ymail.com](mailto:navidsoleymani@ymail.com)) \u2014 repository:\n`https://github.com/navidsoleymani/gando.git`.\n\n---\n\n## Appendix \u2014 Short patch examples\n\n**1) Safer `__media_url`:**\n\n```py\nfrom django.conf import settings\n\n\n@property\ndef __media_url(self):\n return getattr(settings, 'MEDIA_URL', '')\n```\n\n**2) Simpler image prefix parser:**\n\n```py\ndef __image_field_name_parser(self, field_name):\n # return [prefix, suffix] if field_name starts with any image prefix\n for img in self.image_fields_name:\n prefix = f'{img}_'\n if field_name.startswith(prefix):\n return [img, field_name[len(prefix):]]\n return [field_name]\n```\n\n**3) Example `deep_merge` (dict merge):**\n\n```py\ndef deep_merge(a, b):\n if not isinstance(a, dict) or not isinstance(b, dict):\n return b\n out = dict(a)\n for k, v in b.items():\n if k in out and isinstance(out[k], dict) and isinstance(v, dict):\n out[k] = deep_merge(out[k], v)\n elif k in out and isinstance(out[k], list) and isinstance(v, list):\n out[k] = out[k] + v\n else:\n out[k] = v\n return out\n```\n\n---\n\n## Final note\n\nYou already have a strong, well-structured foundation. With a few fixes (robust serializer merging, safe storage access,\nexplicit exception handling) and solid test coverage, Gando will be a great, reliable toolkit for Horin projects.\n\nIf you want, I can now:\n\n* produce a **full, polished `README.md`** file ready to replace the one in your repo (I can drop it into the `canmore`\n canvas or paste it here), **or**\n* prepare a PR-style patch with the exact code changes for the `QueryDictSerializer`, `BlurBase64Field.pre_save`, and\n other issues I flagged.\n\nWhich of those do you want me to do next?\n",
"bugtrack_url": null,
"license": null,
"summary": "A framework based on Django that has tried to gather together the tools needed in the process of creating a large project.",
"version": "1.0.3",
"project_urls": {
"Bug Reports": "https://github.com/navidsoleymani/gando.git/issues",
"Documentation": "https://github.com/navidsoleymani/gando.git",
"Homepage": "https://github.com/navidsoleymani/gando.git",
"Source Code": "https://github.com/navidsoleymani/gando.git"
},
"split_keywords": [
"django"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "b0a93f5747e4b7aae01bad60f10789e889a1793ee5da22ab834fe5c88192ba94",
"md5": "e253118d97a7367364e7fbbedf3633d2",
"sha256": "fa504aeacb01f2bcd50dae1c94c25e60c8056de7bec32deee6fadac7f0b4f875"
},
"downloads": -1,
"filename": "gando-1.0.3-py3-none-any.whl",
"has_sig": false,
"md5_digest": "e253118d97a7367364e7fbbedf3633d2",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 89070,
"upload_time": "2025-08-26T10:43:54",
"upload_time_iso_8601": "2025-08-26T10:43:54.518867Z",
"url": "https://files.pythonhosted.org/packages/b0/a9/3f5747e4b7aae01bad60f10789e889a1793ee5da22ab834fe5c88192ba94/gando-1.0.3-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "30bfc82263c4790c19344b826478dccdf851d82f869c63682e821c92d5c3b5ed",
"md5": "28fc80f94a54c781f7b45a2317a65747",
"sha256": "e862cf04cf0eab371f5e9804537b8ccaef1e60e4b88f11dc39f85ca039a30bfe"
},
"downloads": -1,
"filename": "gando-1.0.3.tar.gz",
"has_sig": false,
"md5_digest": "28fc80f94a54c781f7b45a2317a65747",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 66097,
"upload_time": "2025-08-26T10:43:56",
"upload_time_iso_8601": "2025-08-26T10:43:56.527494Z",
"url": "https://files.pythonhosted.org/packages/30/bf/c82263c4790c19344b826478dccdf851d82f869c63682e821c92d5c3b5ed/gando-1.0.3.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-26 10:43:56",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "navidsoleymani",
"github_project": "gando",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"tox": true,
"lcname": "gando"
}