mirror of https://github.com/jumpserver/jumpserver
perf: 修改 model
parent
4947b0d8fd
commit
d7d9fe2718
|
@ -77,7 +77,7 @@ class Migration(migrations.Migration):
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='platform',
|
model_name='platform',
|
||||||
name='su_method',
|
name='su_method',
|
||||||
field=models.TextField(blank=True, max_length=32, null=True, verbose_name='SU method'),
|
field=models.CharField(blank=True, max_length=32, null=True, verbose_name='SU method'),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='platform',
|
model_name='platform',
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
# Generated by Django 3.2.14 on 2022-09-01 02:34
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('assets', '0107_alter_accountbackupplan_types'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='platform',
|
||||||
|
name='create_account_enabled',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='platform',
|
||||||
|
name='create_account_method',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='platform',
|
||||||
|
name='domain_default',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='platform',
|
||||||
|
name='domain_enabled',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='platform',
|
||||||
|
name='ping_enabled',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='platform',
|
||||||
|
name='ping_method',
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,30 @@
|
||||||
|
# Generated by Django 3.2.14 on 2022-09-01 06:31
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('assets', '0108_auto_20220901_1034'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='host',
|
||||||
|
name='device_info',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='asset',
|
||||||
|
name='info',
|
||||||
|
field=models.JSONField(blank=True, default=dict, verbose_name='Info'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='database',
|
||||||
|
name='version',
|
||||||
|
field=models.CharField(blank=True, max_length=16, verbose_name='Version'),
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='DeviceInfo',
|
||||||
|
),
|
||||||
|
]
|
|
@ -16,7 +16,7 @@ __all__ = ['SystemUser']
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class SystemUser(ProtocolMixin, BaseAccount):
|
class SystemUser(BaseAccount, ProtocolMixin):
|
||||||
LOGIN_AUTO = 'auto'
|
LOGIN_AUTO = 'auto'
|
||||||
LOGIN_MANUAL = 'manual'
|
LOGIN_MANUAL = 'manual'
|
||||||
LOGIN_MODE_CHOICES = (
|
LOGIN_MODE_CHOICES = (
|
||||||
|
@ -44,6 +44,7 @@ class SystemUser(ProtocolMixin, BaseAccount):
|
||||||
# linux su 命令 (switch user)
|
# linux su 命令 (switch user)
|
||||||
su_enabled = models.BooleanField(default=False, verbose_name=_('User switch'))
|
su_enabled = models.BooleanField(default=False, verbose_name=_('User switch'))
|
||||||
su_from = models.ForeignKey('self', on_delete=models.SET_NULL, related_name='su_to', null=True, verbose_name=_("Switch from"))
|
su_from = models.ForeignKey('self', on_delete=models.SET_NULL, related_name='su_to', null=True, verbose_name=_("Switch from"))
|
||||||
|
privileged = None
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['name']
|
ordering = ['name']
|
||||||
|
|
|
@ -2,14 +2,12 @@ from django.db import models
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from simple_history.models import HistoricalRecords
|
from simple_history.models import HistoricalRecords
|
||||||
|
|
||||||
from common.db import fields
|
|
||||||
from .base import BaseAccount, AbsConnectivity
|
from .base import BaseAccount, AbsConnectivity
|
||||||
|
|
||||||
__all__ = ['Account', 'AccountTemplate']
|
__all__ = ['Account', 'AccountTemplate']
|
||||||
|
|
||||||
|
|
||||||
class Account(BaseAccount, AbsConnectivity):
|
class Account(BaseAccount, AbsConnectivity):
|
||||||
token = fields.EncryptTextField(blank=True, null=True, verbose_name=_('Token'))
|
|
||||||
privileged = models.BooleanField(verbose_name=_("Privileged account"), default=False)
|
privileged = models.BooleanField(verbose_name=_("Privileged account"), default=False)
|
||||||
asset = models.ForeignKey('assets.Asset', on_delete=models.CASCADE, verbose_name=_('Asset'))
|
asset = models.ForeignKey('assets.Asset', on_delete=models.CASCADE, verbose_name=_('Asset'))
|
||||||
version = models.IntegerField(default=0, verbose_name=_('Version'))
|
version = models.IntegerField(default=0, verbose_name=_('Version'))
|
||||||
|
@ -30,7 +28,6 @@ class Account(BaseAccount, AbsConnectivity):
|
||||||
|
|
||||||
|
|
||||||
class AccountTemplate(BaseAccount, AbsConnectivity):
|
class AccountTemplate(BaseAccount, AbsConnectivity):
|
||||||
token = fields.EncryptTextField(blank=True, null=True, verbose_name=_('Token'))
|
|
||||||
privileged = models.BooleanField(verbose_name=_("Privileged account"), default=False)
|
privileged = models.BooleanField(verbose_name=_("Privileged account"), default=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
|
@ -11,7 +11,6 @@ from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from common.utils import lazyproperty
|
from common.utils import lazyproperty
|
||||||
from orgs.mixins.models import OrgManager, JMSOrgBaseModel
|
from orgs.mixins.models import OrgManager, JMSOrgBaseModel
|
||||||
from ...const import Category
|
|
||||||
from ..platform import Platform
|
from ..platform import Platform
|
||||||
from ..base import AbsConnectivity
|
from ..base import AbsConnectivity
|
||||||
|
|
||||||
|
@ -82,7 +81,7 @@ class Asset(AbsConnectivity, NodesRelationMixin, JMSOrgBaseModel):
|
||||||
|
|
||||||
labels = models.ManyToManyField('assets.Label', blank=True, related_name='assets', verbose_name=_("Labels"))
|
labels = models.ManyToManyField('assets.Label', blank=True, related_name='assets', verbose_name=_("Labels"))
|
||||||
comment = models.TextField(default='', blank=True, verbose_name=_('Comment'))
|
comment = models.TextField(default='', blank=True, verbose_name=_('Comment'))
|
||||||
|
info = models.JSONField(verbose_name='Info', default=dict, blank=True)
|
||||||
objects = AssetManager.from_queryset(AssetQuerySet)()
|
objects = AssetManager.from_queryset(AssetQuerySet)()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
|
|
@ -6,6 +6,7 @@ from .common import Asset
|
||||||
|
|
||||||
class Database(Asset):
|
class Database(Asset):
|
||||||
db_name = models.CharField(max_length=1024, verbose_name=_("Database"), blank=True)
|
db_name = models.CharField(max_length=1024, verbose_name=_("Database"), blank=True)
|
||||||
|
version = models.CharField(max_length=16, verbose_name=_("Version"), blank=True)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return '{}({}://{}/{})'.format(self.name, self.type, self.ip, self.db_name)
|
return '{}({}://{}/{})'.format(self.name, self.type, self.ip, self.db_name)
|
||||||
|
|
|
@ -1,61 +1,8 @@
|
||||||
from django.db import models
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
|
||||||
|
|
||||||
from common.mixins.models import CommonModelMixin
|
|
||||||
from assets.const import Category
|
from assets.const import Category
|
||||||
from .common import Asset
|
from .common import Asset
|
||||||
|
|
||||||
|
|
||||||
class Host(Asset):
|
class Host(Asset):
|
||||||
device_info = models.OneToOneField('DeviceInfo', null=True, on_delete=models.SET_NULL, verbose_name=_("Host"))
|
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
self.category = Category.HOST
|
self.category = Category.HOST
|
||||||
return super().save(*args, **kwargs)
|
return super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class DeviceInfo(CommonModelMixin):
|
|
||||||
# Collect
|
|
||||||
vendor = models.CharField(max_length=64, null=True, blank=True, verbose_name=_('Vendor'))
|
|
||||||
model = models.CharField(max_length=54, null=True, blank=True, verbose_name=_('Model'))
|
|
||||||
sn = models.CharField(max_length=128, null=True, blank=True, verbose_name=_('Serial number'))
|
|
||||||
|
|
||||||
cpu_model = models.CharField(max_length=64, null=True, blank=True, verbose_name=_('CPU model'))
|
|
||||||
cpu_count = models.IntegerField(null=True, verbose_name=_('CPU count'))
|
|
||||||
cpu_cores = models.IntegerField(null=True, verbose_name=_('CPU cores'))
|
|
||||||
cpu_vcpus = models.IntegerField(null=True, verbose_name=_('CPU vcpus'))
|
|
||||||
memory = models.CharField(max_length=64, null=True, blank=True, verbose_name=_('Memory'))
|
|
||||||
disk_total = models.CharField(max_length=1024, null=True, blank=True, verbose_name=_('Disk total'))
|
|
||||||
disk_info = models.CharField(max_length=1024, null=True, blank=True, verbose_name=_('Disk info'))
|
|
||||||
|
|
||||||
os = models.CharField(max_length=128, null=True, blank=True, verbose_name=_('OS'))
|
|
||||||
os_version = models.CharField(max_length=16, null=True, blank=True, verbose_name=_('OS version'))
|
|
||||||
os_arch = models.CharField(max_length=16, blank=True, null=True, verbose_name=_('OS arch'))
|
|
||||||
hostname_raw = models.CharField(max_length=128, blank=True, null=True, verbose_name=_('Hostname raw'))
|
|
||||||
number = models.CharField(max_length=128, null=True, blank=True, verbose_name=_('Asset number'))
|
|
||||||
|
|
||||||
@property
|
|
||||||
def cpu_info(self):
|
|
||||||
info = ""
|
|
||||||
if self.cpu_model:
|
|
||||||
info += self.cpu_model
|
|
||||||
if self.cpu_count and self.cpu_cores:
|
|
||||||
info += "{}*{}".format(self.cpu_count, self.cpu_cores)
|
|
||||||
return info
|
|
||||||
|
|
||||||
@property
|
|
||||||
def hardware_info(self):
|
|
||||||
if self.cpu_count:
|
|
||||||
return '{} Core {} {}'.format(
|
|
||||||
self.cpu_vcpus or self.cpu_count * self.cpu_cores,
|
|
||||||
self.memory, self.disk_total
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
return ''
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return '{} of {}'.format(self.hardware_info, self.host.name)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
verbose_name = _("DeviceInfo")
|
|
||||||
|
|
||||||
|
|
|
@ -176,7 +176,7 @@ class BaseAccount(OrgModelMixin, AuthMixin):
|
||||||
password = fields.EncryptCharField(max_length=256, blank=True, null=True, verbose_name=_('Password'))
|
password = fields.EncryptCharField(max_length=256, blank=True, null=True, verbose_name=_('Password'))
|
||||||
private_key = fields.EncryptTextField(blank=True, null=True, verbose_name=_('SSH private key'))
|
private_key = fields.EncryptTextField(blank=True, null=True, verbose_name=_('SSH private key'))
|
||||||
public_key = fields.EncryptTextField(blank=True, null=True, verbose_name=_('SSH public key'))
|
public_key = fields.EncryptTextField(blank=True, null=True, verbose_name=_('SSH public key'))
|
||||||
# token = fields.EncryptTextField(blank=True, null=True, verbose_name=_('Token'))
|
token = fields.EncryptTextField(blank=True, null=True, verbose_name=_('Token'))
|
||||||
comment = models.TextField(blank=True, verbose_name=_('Comment'))
|
comment = models.TextField(blank=True, verbose_name=_('Comment'))
|
||||||
date_created = models.DateTimeField(auto_now_add=True, verbose_name=_("Date created"))
|
date_created = models.DateTimeField(auto_now_add=True, verbose_name=_("Date created"))
|
||||||
date_updated = models.DateTimeField(auto_now=True, verbose_name=_("Date updated"))
|
date_updated = models.DateTimeField(auto_now=True, verbose_name=_("Date updated"))
|
||||||
|
|
|
@ -22,8 +22,7 @@ class Domain(OrgModelMixin):
|
||||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
||||||
name = models.CharField(max_length=128, verbose_name=_('Name'))
|
name = models.CharField(max_length=128, verbose_name=_('Name'))
|
||||||
comment = models.TextField(blank=True, verbose_name=_('Comment'))
|
comment = models.TextField(blank=True, verbose_name=_('Comment'))
|
||||||
date_created = models.DateTimeField(auto_now_add=True, null=True,
|
date_created = models.DateTimeField(auto_now_add=True, null=True, verbose_name=_('Date created'))
|
||||||
verbose_name=_('Date created'))
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("Domain")
|
verbose_name = _("Domain")
|
||||||
|
@ -64,6 +63,7 @@ class Gateway(BaseAccount):
|
||||||
domain = models.ForeignKey(Domain, on_delete=models.CASCADE, verbose_name=_("Domain"))
|
domain = models.ForeignKey(Domain, on_delete=models.CASCADE, verbose_name=_("Domain"))
|
||||||
comment = models.CharField(max_length=128, blank=True, null=True, verbose_name=_("Comment"))
|
comment = models.CharField(max_length=128, blank=True, null=True, verbose_name=_("Comment"))
|
||||||
is_active = models.BooleanField(default=True, verbose_name=_("Is active"))
|
is_active = models.BooleanField(default=True, verbose_name=_("Is active"))
|
||||||
|
token = None
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from assets.const import Category, AllTypes
|
from assets.const import AllTypes
|
||||||
from common.db.fields import JsonDictTextField
|
from common.db.fields import JsonDictTextField
|
||||||
|
|
||||||
|
|
||||||
|
@ -30,23 +30,14 @@ class Platform(models.Model):
|
||||||
meta = JsonDictTextField(blank=True, null=True, verbose_name=_("Meta"))
|
meta = JsonDictTextField(blank=True, null=True, verbose_name=_("Meta"))
|
||||||
internal = models.BooleanField(default=False, verbose_name=_("Internal"))
|
internal = models.BooleanField(default=False, verbose_name=_("Internal"))
|
||||||
comment = models.TextField(blank=True, null=True, verbose_name=_("Comment"))
|
comment = models.TextField(blank=True, null=True, verbose_name=_("Comment"))
|
||||||
domain_enabled = models.BooleanField(default=True, verbose_name=_("Domain enabled"))
|
|
||||||
domain_default = models.ForeignKey(
|
|
||||||
'assets.Domain', null=True, on_delete=models.SET_NULL,
|
|
||||||
verbose_name=_("Domain default")
|
|
||||||
)
|
|
||||||
protocols_enabled = models.BooleanField(default=True, verbose_name=_("Protocols enabled"))
|
protocols_enabled = models.BooleanField(default=True, verbose_name=_("Protocols enabled"))
|
||||||
protocols = models.ManyToManyField(PlatformProtocol, blank=True, verbose_name=_("Protocols"))
|
protocols = models.ManyToManyField(PlatformProtocol, blank=True, verbose_name=_("Protocols"))
|
||||||
# Accounts
|
# Accounts
|
||||||
# 这应该和账号有关
|
# 这应该和账号有关
|
||||||
su_enabled = models.BooleanField(default=False, verbose_name=_("Su enabled"))
|
su_enabled = models.BooleanField(default=False, verbose_name=_("Su enabled"))
|
||||||
su_method = models.CharField(max_length=32, blank=True, null=True, verbose_name=_("SU method"))
|
su_method = models.CharField(max_length=32, blank=True, null=True, verbose_name=_("SU method"))
|
||||||
ping_enabled = models.BooleanField(default=False)
|
|
||||||
ping_method = models.TextField(max_length=32, blank=True, null=True, verbose_name=_("Ping method"))
|
|
||||||
verify_account_enabled = models.BooleanField(default=False, verbose_name=_("Verify account enabled"))
|
verify_account_enabled = models.BooleanField(default=False, verbose_name=_("Verify account enabled"))
|
||||||
verify_account_method = models.TextField(max_length=32, blank=True, null=True, verbose_name=_("Verify account method"))
|
verify_account_method = models.TextField(max_length=32, blank=True, null=True, verbose_name=_("Verify account method"))
|
||||||
create_account_enabled = models.BooleanField(default=False, verbose_name=_("Create account enabled"))
|
|
||||||
create_account_method = models.TextField(max_length=32, blank=True, null=True, verbose_name=_("Create account method"))
|
|
||||||
change_password_enabled = models.BooleanField(default=False, verbose_name=_("Change password enabled"))
|
change_password_enabled = models.BooleanField(default=False, verbose_name=_("Change password enabled"))
|
||||||
change_password_method = models.TextField(max_length=32, blank=True, null=True, verbose_name=_("Change password method"))
|
change_password_method = models.TextField(max_length=32, blank=True, null=True, verbose_name=_("Change password method"))
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,8 @@ from .common import BaseAccountSerializer
|
||||||
|
|
||||||
|
|
||||||
class AccountSerializer(
|
class AccountSerializer(
|
||||||
AccountTemplateSerializerMixin, AuthSerializerMixin,
|
AccountTemplateSerializerMixin,
|
||||||
|
AuthSerializerMixin,
|
||||||
BulkOrgResourceModelSerializer
|
BulkOrgResourceModelSerializer
|
||||||
):
|
):
|
||||||
ip = serializers.ReadOnlyField(label=_("IP"))
|
ip = serializers.ReadOnlyField(label=_("IP"))
|
||||||
|
|
|
@ -1,226 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
|
||||||
from rest_framework import serializers
|
|
||||||
from django.core.validators import RegexValidator
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
|
||||||
|
|
||||||
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
|
|
||||||
from ..models import Asset, Node, Platform, SystemUser
|
|
||||||
|
|
||||||
__all__ = [
|
|
||||||
'AssetSerializer', 'AssetSimpleSerializer', 'MiniAssetSerializer',
|
|
||||||
'ProtocolsField', 'PlatformSerializer',
|
|
||||||
'AssetTaskSerializer', 'AssetsTaskSerializer', 'ProtocolsField',
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class ProtocolField(serializers.RegexField):
|
|
||||||
protocols = '|'.join(dict(Asset.Protocol.choices).keys())
|
|
||||||
default_error_messages = {
|
|
||||||
'invalid': _('Protocol format should {}/{}').format(protocols, '1-65535')
|
|
||||||
}
|
|
||||||
regex = r'^(%s)/(\d{1,5})$' % protocols
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super().__init__(self.regex, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
def validate_duplicate_protocols(values):
|
|
||||||
errors = []
|
|
||||||
names = []
|
|
||||||
|
|
||||||
for value in values:
|
|
||||||
if not value or '/' not in value:
|
|
||||||
continue
|
|
||||||
name = value.split('/')[0]
|
|
||||||
if name in names:
|
|
||||||
errors.append(_("Protocol duplicate: {}").format(name))
|
|
||||||
names.append(name)
|
|
||||||
errors.append('')
|
|
||||||
if any(errors):
|
|
||||||
raise serializers.ValidationError(errors)
|
|
||||||
|
|
||||||
|
|
||||||
class ProtocolsField(serializers.ListField):
|
|
||||||
default_validators = [validate_duplicate_protocols]
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
kwargs['child'] = ProtocolField()
|
|
||||||
kwargs['allow_null'] = True
|
|
||||||
kwargs['allow_empty'] = True
|
|
||||||
kwargs['min_length'] = 1
|
|
||||||
kwargs['max_length'] = 4
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
def to_representation(self, value):
|
|
||||||
if not value:
|
|
||||||
return []
|
|
||||||
return value.split(' ')
|
|
||||||
|
|
||||||
|
|
||||||
class AssetSerializer(BulkOrgResourceModelSerializer):
|
|
||||||
platform = serializers.SlugRelatedField(
|
|
||||||
slug_field='name', queryset=Platform.objects.all(), label=_("Platform")
|
|
||||||
)
|
|
||||||
protocols = ProtocolsField(label=_('Protocols'), required=False, default=['ssh/22'])
|
|
||||||
domain_display = serializers.ReadOnlyField(source='domain.name', label=_('Domain name'))
|
|
||||||
nodes_display = serializers.ListField(
|
|
||||||
child=serializers.CharField(), label=_('Nodes name'), required=False
|
|
||||||
)
|
|
||||||
labels_display = serializers.ListField(
|
|
||||||
child=serializers.CharField(), label=_('Labels name'), required=False, read_only=True
|
|
||||||
)
|
|
||||||
|
|
||||||
"""
|
|
||||||
资产的数据结构
|
|
||||||
"""
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = Asset
|
|
||||||
fields_mini = ['id', 'hostname', 'ip', 'platform', 'protocols']
|
|
||||||
fields_small = fields_mini + [
|
|
||||||
'protocol', 'port', 'protocols', 'is_active',
|
|
||||||
'public_ip', 'number', 'comment',
|
|
||||||
]
|
|
||||||
fields_hardware = [
|
|
||||||
'vendor', 'model', 'sn', 'cpu_model', 'cpu_count',
|
|
||||||
'cpu_cores', 'cpu_vcpus', 'memory', 'disk_total', 'disk_info',
|
|
||||||
'os', 'os_version', 'os_arch', 'hostname_raw',
|
|
||||||
'cpu_info', 'hardware_info',
|
|
||||||
]
|
|
||||||
fields_fk = [
|
|
||||||
'domain', 'domain_display', 'platform', 'admin_user', 'admin_user_display'
|
|
||||||
]
|
|
||||||
fields_m2m = [
|
|
||||||
'nodes', 'nodes_display', 'labels', 'labels_display',
|
|
||||||
]
|
|
||||||
read_only_fields = [
|
|
||||||
'connectivity', 'date_verified', 'cpu_info', 'hardware_info',
|
|
||||||
'created_by', 'date_created',
|
|
||||||
]
|
|
||||||
fields = fields_small + fields_hardware + fields_fk + fields_m2m + read_only_fields
|
|
||||||
extra_kwargs = {
|
|
||||||
'protocol': {'write_only': True},
|
|
||||||
'port': {'write_only': True},
|
|
||||||
'hardware_info': {'label': _('Hardware info'), 'read_only': True},
|
|
||||||
'admin_user_display': {'label': _('Admin user display'), 'read_only': True},
|
|
||||||
'cpu_info': {'label': _('CPU info')},
|
|
||||||
}
|
|
||||||
|
|
||||||
def get_fields(self):
|
|
||||||
fields = super().get_fields()
|
|
||||||
|
|
||||||
admin_user_field = fields.get('admin_user')
|
|
||||||
# 因为 mixin 中对 fields 有处理,可能不需要返回 admin_user
|
|
||||||
if admin_user_field:
|
|
||||||
admin_user_field.queryset = SystemUser.objects.filter(type=SystemUser.Type.admin)
|
|
||||||
return fields
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def setup_eager_loading(cls, queryset):
|
|
||||||
""" Perform necessary eager loading of data. """
|
|
||||||
queryset = queryset.prefetch_related('domain', 'platform', 'admin_user')
|
|
||||||
queryset = queryset.prefetch_related('nodes', 'labels')
|
|
||||||
return queryset
|
|
||||||
|
|
||||||
def compatible_with_old_protocol(self, validated_data):
|
|
||||||
protocols_data = validated_data.pop("protocols", [])
|
|
||||||
|
|
||||||
# 兼容老的api
|
|
||||||
name = validated_data.get("protocol")
|
|
||||||
port = validated_data.get("port")
|
|
||||||
if not protocols_data and name and port:
|
|
||||||
protocols_data.insert(0, '/'.join([name, str(port)]))
|
|
||||||
elif not name and not port and protocols_data:
|
|
||||||
protocol = protocols_data[0].split('/')
|
|
||||||
validated_data["protocol"] = protocol[0]
|
|
||||||
validated_data["port"] = int(protocol[1])
|
|
||||||
if protocols_data:
|
|
||||||
validated_data["protocols"] = ' '.join(protocols_data)
|
|
||||||
|
|
||||||
def perform_nodes_display_create(self, instance, nodes_display):
|
|
||||||
if not nodes_display:
|
|
||||||
return
|
|
||||||
nodes_to_set = []
|
|
||||||
for full_value in nodes_display:
|
|
||||||
node = Node.objects.filter(full_value=full_value).first()
|
|
||||||
if node:
|
|
||||||
nodes_to_set.append(node)
|
|
||||||
else:
|
|
||||||
node = Node.create_node_by_full_value(full_value)
|
|
||||||
nodes_to_set.append(node)
|
|
||||||
instance.nodes.set(nodes_to_set)
|
|
||||||
|
|
||||||
def create(self, validated_data):
|
|
||||||
self.compatible_with_old_protocol(validated_data)
|
|
||||||
nodes_display = validated_data.pop('nodes_display', '')
|
|
||||||
instance = super().create(validated_data)
|
|
||||||
self.perform_nodes_display_create(instance, nodes_display)
|
|
||||||
return instance
|
|
||||||
|
|
||||||
def update(self, instance, validated_data):
|
|
||||||
nodes_display = validated_data.pop('nodes_display', '')
|
|
||||||
self.compatible_with_old_protocol(validated_data)
|
|
||||||
instance = super().update(instance, validated_data)
|
|
||||||
self.perform_nodes_display_create(instance, nodes_display)
|
|
||||||
return instance
|
|
||||||
|
|
||||||
|
|
||||||
class MiniAssetSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = Asset
|
|
||||||
fields = AssetSerializer.Meta.fields_mini
|
|
||||||
|
|
||||||
|
|
||||||
class PlatformSerializer(serializers.ModelSerializer):
|
|
||||||
meta = serializers.DictField(required=False, allow_null=True, label=_('Meta'))
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
# TODO 修复 drf SlugField RegexValidator bug,之后记得删除
|
|
||||||
validators = self.fields['name'].validators
|
|
||||||
if isinstance(validators[-1], RegexValidator):
|
|
||||||
validators.pop()
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = Platform
|
|
||||||
fields = [
|
|
||||||
'id', 'name', 'base', 'charset',
|
|
||||||
'internal', 'meta', 'comment'
|
|
||||||
]
|
|
||||||
extra_kwargs = {
|
|
||||||
'internal': {'read_only': True},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class AssetSimpleSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = Asset
|
|
||||||
fields = ['id', 'hostname', 'ip', 'port', 'connectivity', 'date_verified']
|
|
||||||
|
|
||||||
|
|
||||||
class AssetsTaskSerializer(serializers.Serializer):
|
|
||||||
ACTION_CHOICES = (
|
|
||||||
('refresh', 'refresh'),
|
|
||||||
('test', 'test'),
|
|
||||||
)
|
|
||||||
task = serializers.CharField(read_only=True)
|
|
||||||
action = serializers.ChoiceField(choices=ACTION_CHOICES, write_only=True)
|
|
||||||
assets = serializers.PrimaryKeyRelatedField(
|
|
||||||
queryset=Asset.objects, required=False, allow_empty=True, many=True
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class AssetTaskSerializer(AssetsTaskSerializer):
|
|
||||||
ACTION_CHOICES = tuple(list(AssetsTaskSerializer.ACTION_CHOICES) + [
|
|
||||||
('push_system_user', 'push_system_user'),
|
|
||||||
('test_system_user', 'test_system_user')
|
|
||||||
])
|
|
||||||
action = serializers.ChoiceField(choices=ACTION_CHOICES, write_only=True)
|
|
||||||
asset = serializers.PrimaryKeyRelatedField(
|
|
||||||
queryset=Asset.objects, required=False, allow_empty=True, many=False
|
|
||||||
)
|
|
||||||
system_users = serializers.PrimaryKeyRelatedField(
|
|
||||||
queryset=SystemUser.objects, required=False, allow_empty=True, many=True
|
|
||||||
)
|
|
|
@ -1,2 +1,6 @@
|
||||||
from .common import *
|
from .common import *
|
||||||
from .category import *
|
from .host import *
|
||||||
|
from .database import *
|
||||||
|
from .networking import *
|
||||||
|
from .cloud import *
|
||||||
|
from .web import *
|
||||||
|
|
|
@ -1,49 +1,7 @@
|
||||||
from rest_framework import serializers
|
from assets.models import Networking
|
||||||
|
|
||||||
from assets.models import DeviceInfo, Host, Database, Networking, Cloud, Web
|
|
||||||
from .common import AssetSerializer
|
from .common import AssetSerializer
|
||||||
|
|
||||||
__all__ = [
|
__all__ = ['NetworkingSerializer']
|
||||||
'DeviceSerializer', 'HostSerializer', 'DatabaseSerializer',
|
|
||||||
'NetworkingSerializer', 'CloudSerializer', 'WebSerializer',
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class DeviceSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = DeviceInfo
|
|
||||||
fields = [
|
|
||||||
'id', 'vendor', 'model', 'sn', 'cpu_model', 'cpu_count',
|
|
||||||
'cpu_cores', 'cpu_vcpus', 'memory', 'disk_total', 'disk_info',
|
|
||||||
'os', 'os_version', 'os_arch', 'hostname_raw', 'number',
|
|
||||||
'cpu_info', 'hardware_info', 'date_updated'
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class HostSerializer(AssetSerializer):
|
|
||||||
device_info = DeviceSerializer(read_only=True, allow_null=True)
|
|
||||||
|
|
||||||
class Meta(AssetSerializer.Meta):
|
|
||||||
model = Host
|
|
||||||
fields = AssetSerializer.Meta.fields + ['device_info']
|
|
||||||
|
|
||||||
|
|
||||||
class DatabaseSerializer(AssetSerializer):
|
|
||||||
class Meta(AssetSerializer.Meta):
|
|
||||||
model = Database
|
|
||||||
fields = AssetSerializer.Meta.fields + ['db_name']
|
|
||||||
|
|
||||||
|
|
||||||
class WebSerializer(AssetSerializer):
|
|
||||||
class Meta(AssetSerializer.Meta):
|
|
||||||
model = Web
|
|
||||||
fields = AssetSerializer.Meta.fields + ['url']
|
|
||||||
|
|
||||||
|
|
||||||
class CloudSerializer(AssetSerializer):
|
|
||||||
class Meta(AssetSerializer.Meta):
|
|
||||||
model = Cloud
|
|
||||||
fields = AssetSerializer.Meta.fields + ['cluster']
|
|
||||||
|
|
||||||
|
|
||||||
class NetworkingSerializer(AssetSerializer):
|
class NetworkingSerializer(AssetSerializer):
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
from assets.models import Cloud
|
||||||
|
from .common import AssetSerializer
|
||||||
|
|
||||||
|
__all__ = ['CloudSerializer']
|
||||||
|
|
||||||
|
|
||||||
|
class CloudSerializer(AssetSerializer):
|
||||||
|
class Meta(AssetSerializer.Meta):
|
||||||
|
model = Cloud
|
||||||
|
fields = AssetSerializer.Meta.fields + ['cluster']
|
||||||
|
|
|
@ -6,7 +6,7 @@ from django.db.transaction import atomic
|
||||||
from django.db.models import F
|
from django.db.models import F
|
||||||
|
|
||||||
from common.drf.serializers import JMSWritableNestedModelSerializer
|
from common.drf.serializers import JMSWritableNestedModelSerializer
|
||||||
from common.drf.fields import ChoiceDisplayField
|
from common.drf.fields import LabeledChoiceField, ObjectedRelatedField
|
||||||
from ..account import AccountSerializer
|
from ..account import AccountSerializer
|
||||||
from ...models import Asset, Node, Platform, Protocol, Label, Domain
|
from ...models import Asset, Node, Platform, Protocol, Label, Domain
|
||||||
from ...const import Category, AllTypes
|
from ...const import Category, AllTypes
|
||||||
|
@ -42,33 +42,15 @@ class AssetPlatformSerializer(serializers.ModelSerializer):
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class AssetDomainSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = Domain
|
|
||||||
fields = ['id', 'name']
|
|
||||||
extra_kwargs = {
|
|
||||||
'name': {'required': False}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class AssetNodesSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = Node
|
|
||||||
fields = ['id', 'value']
|
|
||||||
extra_kwargs = {
|
|
||||||
'value': {'required': False}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class AssetSerializer(JMSWritableNestedModelSerializer):
|
class AssetSerializer(JMSWritableNestedModelSerializer):
|
||||||
category = ChoiceDisplayField(choices=Category.choices, read_only=True, label=_('Category'))
|
category = LabeledChoiceField(choices=Category.choices, read_only=True, label=_('Category'))
|
||||||
type = ChoiceDisplayField(choices=AllTypes.choices, read_only=True, label=_('Type'))
|
type = LabeledChoiceField(choices=AllTypes.choices, read_only=True, label=_('Type'))
|
||||||
domain = AssetDomainSerializer(required=False)
|
domain = ObjectedRelatedField(required=False, queryset=Domain.objects, label=_('Domain'))
|
||||||
platform = AssetPlatformSerializer(required=False)
|
platform = ObjectedRelatedField(required=False, queryset=Platform.objects, label=_('Platform'))
|
||||||
labels = AssetLabelSerializer(many=True, required=False)
|
nodes = ObjectedRelatedField(many=True, required=False, queryset=Node.objects, label=_('Nodes'))
|
||||||
nodes = AssetNodesSerializer(many=True, required=False)
|
labels = AssetLabelSerializer(many=True, required=False, label=_('Labels'))
|
||||||
accounts = AccountSerializer(many=True, required=False)
|
accounts = AccountSerializer(many=True, required=False, label=_('Accounts'))
|
||||||
protocols = AssetProtocolsSerializer(many=True, required=False)
|
protocols = AssetProtocolsSerializer(many=True, required=False, label=_('Protocols'))
|
||||||
|
|
||||||
"""
|
"""
|
||||||
资产的数据结构
|
资产的数据结构
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
|
||||||
|
from assets.models import Database
|
||||||
|
from .common import AssetSerializer
|
||||||
|
|
||||||
|
__all__ = ['DatabaseSerializer']
|
||||||
|
|
||||||
|
|
||||||
|
class DatabaseSerializer(AssetSerializer):
|
||||||
|
class Meta(AssetSerializer.Meta):
|
||||||
|
model = Database
|
||||||
|
fields = AssetSerializer.Meta.fields + ['db_name']
|
|
@ -0,0 +1,37 @@
|
||||||
|
from rest_framework import serializers
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from assets.models import Host
|
||||||
|
from .common import AssetSerializer
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ['HostInfoSerializer', 'HostSerializer']
|
||||||
|
|
||||||
|
|
||||||
|
class HostInfoSerializer(serializers.Serializer):
|
||||||
|
vendor = serializers.CharField(max_length=64, required=False, allow_blank=True, label=_('Vendor'))
|
||||||
|
model = serializers.CharField(max_length=54, required=False, allow_blank=True, label=_('Model'))
|
||||||
|
sn = serializers.CharField(max_length=128, required=False, allow_blank=True, label=_('Serial number'))
|
||||||
|
|
||||||
|
cpu_model = serializers.CharField(max_length=64, required=False, allow_blank=True, label=_('CPU model'))
|
||||||
|
cpu_count = serializers.IntegerField(required=False, label=_('CPU count'))
|
||||||
|
cpu_cores = serializers.IntegerField(required=False, label=_('CPU cores'))
|
||||||
|
cpu_vcpus = serializers.IntegerField(required=False, label=_('CPU vcpus'))
|
||||||
|
memory = serializers.CharField(max_length=64, allow_blank=True, required=False, label=_('Memory'))
|
||||||
|
disk_total = serializers.CharField(max_length=1024, allow_blank=True, required=False, label=_('Disk total'))
|
||||||
|
disk_info = serializers.CharField(max_length=1024, allow_blank=True, required=False, label=_('Disk info'))
|
||||||
|
|
||||||
|
os = serializers.CharField(max_length=128, allow_blank=True, required=False, label=_('OS'))
|
||||||
|
os_version = serializers.CharField(max_length=16, allow_blank=True, required=False, label=_('OS version'))
|
||||||
|
os_arch = serializers.CharField(max_length=16, allow_blank=True, required=False, label=_('OS arch'))
|
||||||
|
hostname_raw = serializers.CharField(max_length=128, allow_blank=True, required=False, label=_('Hostname raw'))
|
||||||
|
number = serializers.CharField(max_length=128, allow_blank=True, required=False, label=_('Asset number'))
|
||||||
|
|
||||||
|
|
||||||
|
class HostSerializer(AssetSerializer):
|
||||||
|
info = HostInfoSerializer(allow_null=True)
|
||||||
|
|
||||||
|
class Meta(AssetSerializer.Meta):
|
||||||
|
model = Host
|
||||||
|
fields = AssetSerializer.Meta.fields + ['info']
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
|
||||||
|
from assets.models import Networking
|
||||||
|
from .common import AssetSerializer
|
||||||
|
|
||||||
|
__all__ = ['NetworkingSerializer']
|
||||||
|
|
||||||
|
|
||||||
|
class NetworkingSerializer(AssetSerializer):
|
||||||
|
class Meta(AssetSerializer.Meta):
|
||||||
|
model = Networking
|
|
@ -0,0 +1,11 @@
|
||||||
|
|
||||||
|
from assets.models import Web
|
||||||
|
from .common import AssetSerializer
|
||||||
|
|
||||||
|
__all__ = ['WebSerializer']
|
||||||
|
|
||||||
|
|
||||||
|
class WebSerializer(AssetSerializer):
|
||||||
|
class Meta(AssetSerializer.Meta):
|
||||||
|
model = Web
|
||||||
|
fields = AssetSerializer.Meta.fields + ['url']
|
|
@ -1,7 +1,7 @@
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from common.drf.fields import ChoiceDisplayField
|
from common.drf.fields import LabeledChoiceField
|
||||||
from common.drf.serializers import JMSWritableNestedModelSerializer
|
from common.drf.serializers import JMSWritableNestedModelSerializer
|
||||||
from ..models import Platform, PlatformProtocol
|
from ..models import Platform, PlatformProtocol
|
||||||
from ..const import Category, AllTypes
|
from ..const import Category, AllTypes
|
||||||
|
@ -30,11 +30,11 @@ class PlatformProtocolsSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
|
|
||||||
class PlatformSerializer(JMSWritableNestedModelSerializer):
|
class PlatformSerializer(JMSWritableNestedModelSerializer):
|
||||||
type = ChoiceDisplayField(choices=AllTypes.choices, label=_("Type"))
|
type = LabeledChoiceField(choices=AllTypes.choices, label=_("Type"))
|
||||||
category = ChoiceDisplayField(choices=Category.choices, label=_("Category"))
|
category = LabeledChoiceField(choices=Category.choices, label=_("Category"))
|
||||||
protocols = PlatformProtocolsSerializer(label=_('Protocols'), many=True, required=False)
|
protocols = PlatformProtocolsSerializer(label=_('Protocols'), many=True, required=False)
|
||||||
type_constraints = serializers.ReadOnlyField(required=False, read_only=True)
|
type_constraints = serializers.ReadOnlyField(required=False, read_only=True)
|
||||||
su_method = ChoiceDisplayField(
|
su_method = LabeledChoiceField(
|
||||||
choices=[('sudo', 'sudo su -'), ('su', 'su - ')],
|
choices=[('sudo', 'sudo su -'), ('su', 'su - ')],
|
||||||
label='切换方式', required=False, default='sudo'
|
label='切换方式', required=False, default='sudo'
|
||||||
)
|
)
|
||||||
|
@ -54,6 +54,8 @@ class PlatformSerializer(JMSWritableNestedModelSerializer):
|
||||||
]
|
]
|
||||||
extra_kwargs = {
|
extra_kwargs = {
|
||||||
'su_enabled': {'label': '启用切换账号'},
|
'su_enabled': {'label': '启用切换账号'},
|
||||||
|
'domain_enabled': {'label': "启用网域"},
|
||||||
|
'domain_default': {'label': "默认网域"},
|
||||||
'verify_account_enabled': {'label': '启用校验账号'},
|
'verify_account_enabled': {'label': '启用校验账号'},
|
||||||
'verify_account_method': {'label': '校验账号方式'},
|
'verify_account_method': {'label': '校验账号方式'},
|
||||||
'create_account_enabled': {'label': '启用创建账号'},
|
'create_account_enabled': {'label': '启用创建账号'},
|
||||||
|
|
|
@ -4,11 +4,13 @@ import six
|
||||||
|
|
||||||
from rest_framework.fields import ChoiceField
|
from rest_framework.fields import ChoiceField
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
|
|
||||||
from common.utils import decrypt_password
|
from common.utils import decrypt_password
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'ReadableHiddenField', 'EncryptedField', 'ChoiceDisplayField'
|
'ReadableHiddenField', 'EncryptedField', 'LabeledChoiceField',
|
||||||
|
'ObjectedRelatedField',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,9 +42,9 @@ class EncryptedField(serializers.CharField):
|
||||||
return decrypt_password(value)
|
return decrypt_password(value)
|
||||||
|
|
||||||
|
|
||||||
class ChoiceDisplayField(ChoiceField):
|
class LabeledChoiceField(ChoiceField):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(ChoiceDisplayField, self).__init__(*args, **kwargs)
|
super(LabeledChoiceField, self).__init__(*args, **kwargs)
|
||||||
self.choice_mapper = {
|
self.choice_mapper = {
|
||||||
six.text_type(key): value for key, value in self.choices.items()
|
six.text_type(key): value for key, value in self.choices.items()
|
||||||
}
|
}
|
||||||
|
@ -58,4 +60,31 @@ class ChoiceDisplayField(ChoiceField):
|
||||||
def to_internal_value(self, data):
|
def to_internal_value(self, data):
|
||||||
if isinstance(data, dict):
|
if isinstance(data, dict):
|
||||||
return data.get('value')
|
return data.get('value')
|
||||||
return super(ChoiceDisplayField, self).to_internal_value(data)
|
return super(LabeledChoiceField, self).to_internal_value(data)
|
||||||
|
|
||||||
|
|
||||||
|
class ObjectedRelatedField(serializers.RelatedField):
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
self.attrs = kwargs.pop('attrs', None) or ('id', 'name')
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
|
def to_representation(self, value):
|
||||||
|
data = {}
|
||||||
|
for attr in self.attrs:
|
||||||
|
data[attr] = getattr(value, attr)
|
||||||
|
return data
|
||||||
|
|
||||||
|
def to_internal_value(self, data):
|
||||||
|
if isinstance(data, dict):
|
||||||
|
pk = data.get(self.attrs[0])
|
||||||
|
else:
|
||||||
|
pk = data
|
||||||
|
queryset = self.get_queryset()
|
||||||
|
try:
|
||||||
|
if isinstance(data, bool):
|
||||||
|
raise TypeError
|
||||||
|
return queryset.get(pk=pk)
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
self.fail('does_not_exist', pk_value=pk)
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
self.fail('incorrect_type', data_type=type(pk).__name__)
|
||||||
|
|
|
@ -85,13 +85,13 @@ class SimpleMetadataWithFilters(SimpleMetadata):
|
||||||
field_info['choices'] = [
|
field_info['choices'] = [
|
||||||
{
|
{
|
||||||
'value': choice_value,
|
'value': choice_value,
|
||||||
'display_name': force_text(choice_name, strings_only=True)
|
'label': force_text(choice_name, strings_only=True)
|
||||||
}
|
}
|
||||||
for choice_value, choice_name in dict(field.choices).items()
|
for choice_value, choice_name in dict(field.choices).items()
|
||||||
]
|
]
|
||||||
|
|
||||||
if field.__class__.__name__ == 'ChoiceDisplayField':
|
if field.__class__.__name__ == 'LabeledChoiceField':
|
||||||
field_info['type'] = 'display_choice'
|
field_info['type'] = 'labeled_choice'
|
||||||
return field_info
|
return field_info
|
||||||
|
|
||||||
def get_filters_fields(self, request, view):
|
def get_filters_fields(self, request, view):
|
||||||
|
|
Loading…
Reference in New Issue