from django.contrib.auth import get_user_model from django.contrib.postgres.expressions import ArraySubquery from django.db import models from django.db.models import OuterRef from django.db.models.fields.related import RelatedField from django.db.models.functions import JSONObject from app.utils.helpers import recursive_getattr from uuid import uuid4 User = get_user_model() class BaseQuerySet(models.QuerySet): def headers(self): """Return the list of header for a list.""" def _field(field): ret = { field.name: { "text": field.verbose_name.capitalize(), "align": "", "encrypted": field.name in self.model.Encryption.fields, "editable": field.name not in self.model.Serialization.excluded_fields_edit, "field_widget": "v-textarea", "choices": None, "details": True, "dynamic_field_type": field.name in self.model.Serialization.dynamic_field_type, } } if isinstance(field, RelatedField): ret[f"{field.name}__name"] = { "text": f"{field.verbose_name.capitalize()} - Name", "align": "", "encrypted": True, } ret[f"{field.name}__custom_identifier"] = { "text": f"{field.verbose_name.capitalize()} - Identifier", "align": "", "encrypted": True, } ret[field.name].update( align=" d-none", testing=123, field_widget="v-select", ) if field.choices: ret[field.name].update( field_widget="v-select", choices=[ { "value": c[0], "text": c[1], } for c in field.choices ], ) return ret fields = {} for field in self.model._meta.fields: if field.name in self.model.Serialization.excluded_fields: continue fields.update(_field(field)) return fields def serialize(self): """Serialize a queryset.""" fields = [] for field_name, _ in self.headers().items(): fields.append(field_name) if hasattr(self.model, "history"): qs = self.annotate( history=ArraySubquery( self.model.history.model.objects.filter(id=OuterRef("id")).values( json=JSONObject( id="history_id", date="history_date", ) ) ) ) fields.append("history") else: qs = self return qs.values(*fields) class BaseManager(models.Manager.from_queryset(BaseQuerySet)): pass class BaseModel(models.Model): class Meta: abstract = True class Serialization: # Exclude fields from serialization excluded_fields = [] excluded_fields_edit = ["id", "created_at", "last_modified_at"] dynamic_field_type = [] class Encryption: fields = ["name", "description", "custom_identifier"] def serialize(self): ret = {} for field_name in self._meta.model.objects.headers().keys(): value = recursive_getattr(self, field_name) if isinstance(value, BaseModel): value = value.id ret[field_name] = value return ret id = models.UUIDField(primary_key=True, default=uuid4, editable=False) name = models.TextField(max_length=2048, blank=True, null=True) description = models.TextField(max_length=2048, blank=True, null=True) custom_identifier = models.TextField(max_length=2048, null=True, blank=True) created_at = models.DateTimeField(auto_now_add=True) last_modified_at = models.DateTimeField(auto_now=True) objects = BaseManager()