gando


Namegando JSON
Version 1.0.3 PyPI version JSON
download
home_pagehttps://github.com/navidsoleymani/gando.git
SummaryA framework based on Django that has tried to gather together the tools needed in the process of creating a large project.
upload_time2025-08-26 10:43:56
maintainerNone
docs_urlNone
authorHydra
requires_python>=3.8
licenseNone
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

[![PyPI](https://img.shields.io/pypi/v/gando?label=PyPI\&logo=python)](https://pypi.org/project/gando) <!-- placeholder -->
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
![Gando Logo](https://raw.githubusercontent.com/navidsoleymani/gando/main/assets/gando.png)

**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[![PyPI](https://img.shields.io/pypi/v/gando?label=PyPI\\&logo=python)](https://pypi.org/project/gando) <!-- placeholder -->\n[![License](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)\n![Gando Logo](https://raw.githubusercontent.com/navidsoleymani/gando/main/assets/gando.png)\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"
}
        
Elapsed time: 1.02344s