pull/10327/head
ibuler 2023-04-23 16:15:27 +08:00
parent a105748a55
commit c991a73632
2 changed files with 111 additions and 2 deletions

View File

@ -1,6 +1,5 @@
# -*- coding: utf-8 -*-
#
import json
from django.core.validators import MinValueValidator, MaxValueValidator
from django.db import models
@ -32,6 +31,7 @@ __all__ = [
"PortRangeField",
"BitChoices",
"TreeChoices",
"JSONManyToManyField",
]
@ -274,3 +274,105 @@ class PortRangeField(models.CharField):
kwargs['max_length'] = 16
super().__init__(**kwargs)
self.validators.append(PortRangeValidator())
from django.db.models import Q
from django.apps import apps
from django.db import models
from django.core.exceptions import ValidationError
import json
class JSONManyToManyDescriptor:
def __init__(self, field):
self.field = field
self._is_setting = False
def __get__(self, instance, owner=None):
if instance is None:
return self
if not hasattr(instance, "_related_manager_cache"):
instance._related_manager_cache = {}
current_value = getattr(instance, self.field.attname, {})
if self.field.name not in instance._related_manager_cache or instance._related_manager_cache[
self.field.name]._is_value_stale(current_value):
manager = RelatedManager(instance, self.field)
instance._related_manager_cache[self.field.name] = manager
return instance._related_manager_cache[self.field.name]
def __set__(self, instance, value):
if instance is None:
return
if not hasattr(instance, "_is_setting"):
instance._is_setting = {}
if self.field.name not in instance._is_setting or not instance._is_setting[self.field.name]:
instance._is_setting[self.field.name] = True
manager = self.__get__(instance, instance.__class__)
manager.set(value)
serialized_value = manager.serialize()
instance.__dict__[self.field.attname] = serialized_value
instance._is_setting[self.field.name] = False
class JSONManyToManyField(models.JSONField):
def __init__(self, related_model, *args, **kwargs):
self.related_model = related_model
super().__init__(*args, **kwargs)
def contribute_to_class(self, cls, name, **kwargs):
super().contribute_to_class(cls, name, **kwargs)
setattr(cls, self.name, JSONManyToManyDescriptor(self))
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
kwargs['related_model'] = self.related_model
return name, path, args, kwargs
def validate(self, value, model_instance):
super().validate(value, model_instance)
if not isinstance(value, list) or not all(isinstance(item, int) for item in value):
raise ValidationError("Invalid JSON data for JSONManyToManyField.")
class RelatedManager:
def __init__(self, instance, field):
self.instance = instance
self.field = field
def _is_value_stale(self, current_value):
return self.serialize() != current_value
def set(self, value):
self.field.value = value
def serialize(self):
return self.field.value
def _get_queryset(self):
model = apps.get_model(self.field.to)
value = self.field.value
if value["type"] == "all":
return model.objects.all()
elif value["type"] == "ids":
return model.objects.filter(id__in=value["ids"])
elif value["type"] == "attrs":
filters = Q()
for attr in value["attrs"]:
if attr["match"] == "exact":
filters &= Q(**{attr["attr"]: attr["value"]})
return model.objects.filter(filters)
def all(self):
return self._get_queryset()
def filter(self, *args, **kwargs):
queryset = self._get_queryset()
return queryset.filter(*args, **kwargs)

View File

@ -2,12 +2,19 @@ from django.db import models
from django.db.models import F, TextChoices
from django.utils.translation import ugettext_lazy as _
from assets.models import Asset, Node, FamilyMixin
from accounts.models import Account
from assets.models import Asset, Node, FamilyMixin
from common.db.fields import JSONManyToManyField
from common.utils import lazyproperty
from orgs.mixins.models import JMSOrgBaseModel
class TestPermission2(models.Model):
name = models.CharField(max_length=128, verbose_name=_('Name'))
users = JSONManyToManyField("users.User")
assets = JSONManyToManyField("assets.Asset")
class NodeFrom(TextChoices):
granted = 'granted', 'Direct node granted'
child = 'child', 'Have children node'