Metadata-Version: 2.1
Name: django_utilitybox
Version: 0.1.4
Summary: Utilidades para Django REST Framework: manejo de errores HTTP, vistas base, filtros Q dinámicos, dropdowns genéricos y registro de URLs.
Home-page: https://github.com/Josecolin99/
Author: Jose Angel Colin Najera
Author-email: josecolin99@gmail.com
License: MIT
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Build Tools
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Description-Content-Type: text/markdown
License-File: LICENSE

# Django Utilitybox

![Logo](https://i.imgur.com/KXosc2D.png)

[![PyPI version](https://img.shields.io/pypi/v/django-utilitybox)](https://pypi.org/project/django-utilitybox/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/)

Colección de utilidades para proyectos **Django REST Framework**: manejo de errores, vistas base, filtros dinámicos, dropdowns genéricos y registro de URLs.

---

## Instalación

```bash
pip install django-utilitybox
```

### Dependencias
- Django >= 4.2
- djangorestframework >= 3.14.0
- termcolor >= 2.4.0

---

## Módulos

### 1. Response — Manejo de errores

Clases listas para lanzar excepciones HTTP desde cualquier vista DRF, con mensajes predeterminados y status configurables.

```python
from dj_utilitybox.response import bad as br
```

#### Clases disponibles

| Clase | Status | Mensaje por defecto |
|---|---|---|
| `CustomRaise` | 400 | Personalizado |
| `QueryParamNotFound` | 400 | `Queryparam '{field}' is required` |
| `KwargNotFound` | 400 | `Kwarg '{field}' is required` |
| `ModelNotFound` | 400 | `{field} don't exist` |
| `DjangoFieldsError` | 400 | Dict de campos con errores |

#### Parámetros comunes

| Parámetro | Tipo | Descripción |
|---|---|---|
| `field` | `str` | Campo que causó el error |
| `message` | `str` | Mensaje personalizado (opcional) |
| `code` | `str` | Código interno del error (opcional) |
| `extra_params` | `dict` | Datos adicionales en la respuesta (opcional) |
| `status` | `int` | Código HTTP (por defecto 400) |

#### Ejemplos de uso

```python
from dj_utilitybox.response import bad as br
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status as st

class MiVista(APIView):
    def get(self, request, *args, **kwargs):
        user_id = request.GET.get('user_id')
        if not user_id:
            br.QueryParamNotFound('user_id')

        obj = MiModelo.objects.filter(pk=user_id).first()
        if not obj:
            br.ModelNotFound('MiModelo')

        return Response({'message': 'OK'}, status=st.HTTP_200_OK)
```

#### Respuesta JSON estándar

```json
HTTP 400 Bad Request
{
    "status": "Queryparam 'user_id' is required"
}
```

Con `code` y `extra_params`:

```python
br.CustomRaise(
    message="Token inválido",
    code="INVALID_TOKEN",
    extra_params={"retry_after": 30}
)
```

```json
HTTP 400 Bad Request
{
    "status": "Token inválido",
    "code": "INVALID_TOKEN",
    "retry_after": 30
}
```

#### DjangoFieldsError — Errores por campo

Útil para errores de validación con el formato estándar de DRF.

```python
br.DjangoFieldsError(fields={
    "email": ["Este campo es requerido."],
    "nombre": ["Máximo 50 caracteres."]
})
```

```json
HTTP 400 Bad Request
{
    "email": ["Este campo es requerido."],
    "nombre": ["Máximo 50 caracteres."]
}
```

---

### 2. URLs — `add_path()`

Registra dinámicamente las URLs de una app Django sin importarlas directamente en el `urls.py` principal.

```python
from dj_utilitybox.urls.path import add_path
```

#### Parámetros

| Parámetro | Tipo | Descripción |
|---|---|---|
| `path_dir` | `str` | Prefijo de URL, ej: `"api/users/"` |
| `application` | `str` | Nombre del módulo de la app, ej: `"users"` |
| `namespace` | `str` | Namespace del `include()`. Por defecto usa `application` |

#### Ejemplo

```python
# urls.py principal
from django.urls import path
from dj_utilitybox.urls.path import add_path

urlpatterns = [
    add_path("api/users/", "users"),
    add_path("api/orders/", "orders", namespace="pedidos"),
]
```

Lanza `ModuleNotFoundError` con mensajes claros si la app no existe o no tiene `urls.py`.

---

### 3. Vistas — `GetBase`

Clase base para vistas GET que soporta listado con paginación y recuperación de un solo objeto.

```python
from dj_utilitybox.views.base import GetBase
```

#### Atributos configurables

| Atributo | Tipo | Por defecto | Descripción |
|---|---|---|---|
| `serializer_class` | `Serializer` | — | Serializer a usar (obligatorio) |
| `list_view` | `bool` | `False` | `True` para lista paginada, `False` para un objeto |
| `page_size` | `int` | `100` | Registros por página |
| `ordering` | `str` | `"-pk"` | Campo de ordenamiento |

#### Ejemplo

```python
from dj_utilitybox.views.base import GetBase
from myapp.serializers import ProductoSerializer
import myapp.models as m

class ProductoListView(GetBase):
    serializer_class = ProductoSerializer
    list_view = True
    page_size = 50
    ordering = "-created_at"

    def get_queryset(self):
        return m.Producto.objects.filter(activo=True)
```

- Autenticación por `TokenAuthentication` por defecto.
- Paginación con `CursorPagination`.

---

### 4. Dropdown — `GenericDropdown`

Vista genérica para endpoints de tipo dropdown. Retorna `id` y `_name` (nombre calculado) de cualquier modelo.

```python
from dj_utilitybox.dropdown.dropdown import GenericDropdown
```

#### Query params

| Param | Descripción | Ejemplo |
|---|---|---|
| `name_fields` | Campos a concatenar como nombre | `name_fields=first_name,last_name` |
| `name` | Filtro por coincidencia de texto | `name=juan` |

#### Ejemplo

```python
from dj_utilitybox.dropdown.dropdown import GenericDropdown
import myapp.models as m

class UsuarioDropdown(GenericDropdown):
    default_name_field = "username"
    dict_model = {
        "usuario": m.Usuario,
        "empresa": m.Empresa,
    }
```

```python
# urls.py
path("api/dropdown/<str:model>/", UsuarioDropdown.as_view()),
```

```
GET /api/dropdown/usuario/?name=juan&name_fields=first_name,last_name
```

```json
{
    "results": [
        {"id": 1, "_name": "Juan Pérez"},
        {"id": 2, "_name": "Juan García"}
    ]
}
```

Si el modelo tiene campo `active`, filtra automáticamente por `active=True`.

---

### 5. Filtros — `FilterGenerator`

Genera objetos `Q` de Django dinámicamente a partir de query params o datos de entrada.

```python
from dj_utilitybox.filters.generator import generate_filter, FilterGenerator
```

#### Configuración de `list_filter`

Cada elemento del listado acepta:

| Clave | Descripción |
|---|---|
| `field` | Campo del modelo |
| `value` | Clave a buscar en `data` (por defecto igual a `field`) |
| `lookfield` | Lookup de Django, ej: `icontains`, `exact`, `in` |
| `list_value` | Si `True`, convierte el valor a lista (split por coma) |
| `bool_value` | Si `True`, convierte el valor a booleano |
| `raise_exeption` | Si `True`, lanza error si el parámetro no existe |

#### Ejemplo

```python
from dj_utilitybox.filters.generator import generate_filter
from django.db.models import Q

query_params = request.GET  # {"nombre": "juan", "activo": "true"}

filters = generate_filter(
    data=query_params,
    list_filter=[
        {"field": "nombre", "lookfield": "icontains"},
        {"field": "activo", "bool_value": True},
    ],
    list_q=[Q(empresa__isnull=False)],
    mode="and"
)

queryset = MiModelo.objects.filter(filters)
```

También puedes usar la clase directamente para mayor control:

```python
from dj_utilitybox.filters.generator import FilterGenerator

generator = FilterGenerator(
    data=query_params,
    list_filter=[...],
    mode="or"
)
q = generator.generate_filter()
```

---

## Licencia

[MIT](https://choosealicense.com/licenses/mit/) — José Ángel Colin Nájera
