diff --git a/netbox/extras/forms.py b/netbox/extras/forms.py index a7d354939..55fef2995 100644 --- a/netbox/extras/forms.py +++ b/netbox/extras/forms.py @@ -44,7 +44,7 @@ def get_custom_fields_for_model(content_type, bulk_editing=False): # Text else: - field = forms.CharField(max_length=100, required=cf.required, initial=cf.default) + field = forms.CharField(max_length=255, required=cf.required, initial=cf.default) field.model = cf field.label = cf.label if cf.label else cf.name.capitalize() diff --git a/netbox/extras/migrations/0002_custom_fields.py b/netbox/extras/migrations/0002_custom_fields.py index 361ca1363..e43067610 100644 --- a/netbox/extras/migrations/0002_custom_fields.py +++ b/netbox/extras/migrations/0002_custom_fields.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Generated by Django 1.10 on 2016-08-15 19:18 +# Generated by Django 1.10 on 2016-08-17 18:42 from __future__ import unicode_literals from django.db import migrations, models @@ -47,9 +47,7 @@ class Migration(migrations.Migration): fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('obj_id', models.PositiveIntegerField()), - ('val_int', models.BigIntegerField(blank=True, null=True)), - ('val_char', models.CharField(blank=True, max_length=100)), - ('val_date', models.DateField(blank=True, null=True)), + ('serialized_value', models.CharField(max_length=255)), ('field', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='values', to='extras.CustomField')), ('obj_type', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='+', to='contenttypes.ContentType')), ], diff --git a/netbox/extras/models.py b/netbox/extras/models.py index 1896421fc..06f6ba5af 100644 --- a/netbox/extras/models.py +++ b/netbox/extras/models.py @@ -1,3 +1,5 @@ +from datetime import date + from django.contrib.auth.models import User from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.models import ContentType @@ -97,15 +99,45 @@ class CustomField(models.Model): def __unicode__(self): return self.label or self.name.capitalize() + def serialize_value(self, value): + """ + Serialize the given value to a string suitable for storage as a CustomFieldValue + """ + if value is None: + return '' + if self.type == CF_TYPE_BOOLEAN: + return str(int(bool(value))) + if self.type == CF_TYPE_DATE: + return value.strftime('%Y-%m-%d') + if self.type == CF_TYPE_SELECT: + # Could be ModelChoiceField or TypedChoiceField + return str(value.id) if hasattr(value, 'id') else str(value) + return str(value) + + def deserialize_value(self, serialized_value): + """ + Convert a string into the object it represents depending on the type of field + """ + if serialized_value is '': + return None + if self.type == CF_TYPE_INTEGER: + return int(serialized_value) + if self.type == CF_TYPE_BOOLEAN: + return bool(int(serialized_value)) + if self.type == CF_TYPE_DATE: + # Read date as YYYY-MM-DD + return date(*[int(n) for n in serialized_value.split('-')]) + if self.type == CF_TYPE_SELECT: + return CustomFieldChoice.objects.get(pk=int(serialized_value)) + return serialized_value + class CustomFieldValue(models.Model): field = models.ForeignKey('CustomField', related_name='values') obj_type = models.ForeignKey(ContentType, related_name='+', on_delete=models.PROTECT) obj_id = models.PositiveIntegerField() obj = GenericForeignKey('obj_type', 'obj_id') - val_int = models.BigIntegerField(blank=True, null=True) - val_char = models.CharField(max_length=100, blank=True) - val_date = models.DateField(blank=True, null=True) + serialized_value = models.CharField(max_length=255) class Meta: ordering = ['obj_type', 'obj_id'] @@ -116,29 +148,11 @@ class CustomFieldValue(models.Model): @property def value(self): - if self.field.type == CF_TYPE_INTEGER: - return self.val_int - if self.field.type == CF_TYPE_BOOLEAN: - return bool(self.val_int) if self.val_int is not None else None - if self.field.type == CF_TYPE_DATE: - return self.val_date - if self.field.type == CF_TYPE_SELECT: - return CustomFieldChoice.objects.get(pk=self.val_int) if self.val_int else None - return self.val_char + return self.field.deserialize_value(self.serialized_value) @value.setter def value(self, value): - if self.field.type == CF_TYPE_INTEGER: - self.val_int = value - elif self.field.type == CF_TYPE_BOOLEAN: - self.val_int = int(bool(value)) if value is not None else None - elif self.field.type == CF_TYPE_DATE: - self.val_date = value - elif self.field.type == CF_TYPE_SELECT: - # Could be ModelChoiceField or TypedChoiceField - self.val_int = value.id if hasattr(value, 'id') else value - else: - self.val_char = value + self.serialized_value = self.field.serialize_value(value) def save(self, *args, **kwargs): if (self.field.type == CF_TYPE_TEXT and self.value == '') or self.value is None: