1
- from collections import OrderedDict
2
-
3
1
from django import forms
4
2
from django .contrib .auth .models import User
5
3
from django .contrib .contenttypes .models import ContentType
6
- from django .core .exceptions import ObjectDoesNotExist
7
4
from taggit .forms import TagField
8
5
9
6
from dcim .models import DeviceRole , Platform , Region , Site
10
7
from tenancy .models import Tenant , TenantGroup
11
8
from utilities .forms import (
12
9
add_blank_choice , APISelectMultiple , BootstrapMixin , BulkEditForm , BulkEditNullBooleanSelect , ColorSelect ,
13
- CommentField , ContentTypeSelect , DatePicker , DateTimePicker , FilterChoiceField , LaxURLField , JSONField ,
14
- SlugField , StaticSelect2 , BOOLEAN_WITH_BLANK_CHOICES ,
10
+ CommentField , ContentTypeSelect , DateTimePicker , FilterChoiceField , JSONField , SlugField , StaticSelect2 ,
11
+ BOOLEAN_WITH_BLANK_CHOICES ,
15
12
)
16
13
from .choices import *
17
14
from .models import ConfigContext , CustomField , CustomFieldValue , ImageAttachment , ObjectChange , Tag
21
18
# Custom fields
22
19
#
23
20
24
- def get_custom_fields_for_model (content_type , filterable_only = False , bulk_edit = False ):
25
- """
26
- Retrieve all CustomFields applicable to the given ContentType
27
- """
28
- field_dict = OrderedDict ()
29
- custom_fields = CustomField .objects .filter (obj_type = content_type )
30
- if filterable_only :
31
- custom_fields = custom_fields .exclude (filter_logic = CustomFieldFilterLogicChoices .FILTER_DISABLED )
32
-
33
- for cf in custom_fields :
34
- field_name = 'cf_{}' .format (str (cf .name ))
35
- initial = cf .default if not bulk_edit else None
36
-
37
- # Integer
38
- if cf .type == CustomFieldTypeChoices .TYPE_INTEGER :
39
- field = forms .IntegerField (required = cf .required , initial = initial )
40
-
41
- # Boolean
42
- elif cf .type == CustomFieldTypeChoices .TYPE_BOOLEAN :
43
- choices = (
44
- (None , '---------' ),
45
- (1 , 'True' ),
46
- (0 , 'False' ),
47
- )
48
- if initial is not None and initial .lower () in ['true' , 'yes' , '1' ]:
49
- initial = 1
50
- elif initial is not None and initial .lower () in ['false' , 'no' , '0' ]:
51
- initial = 0
52
- else :
53
- initial = None
54
- field = forms .NullBooleanField (
55
- required = cf .required , initial = initial , widget = StaticSelect2 (choices = choices )
56
- )
57
-
58
- # Date
59
- elif cf .type == CustomFieldTypeChoices .TYPE_DATE :
60
- field = forms .DateField (required = cf .required , initial = initial , widget = DatePicker ())
61
-
62
- # Select
63
- elif cf .type == CustomFieldTypeChoices .TYPE_SELECT :
64
- choices = [(cfc .pk , cfc ) for cfc in cf .choices .all ()]
65
- if not cf .required or bulk_edit or filterable_only :
66
- choices = [(None , '---------' )] + choices
67
- # Check for a default choice
68
- default_choice = None
69
- if initial :
70
- try :
71
- default_choice = cf .choices .get (value = initial ).pk
72
- except ObjectDoesNotExist :
73
- pass
74
- field = forms .TypedChoiceField (
75
- choices = choices , coerce = int , required = cf .required , initial = default_choice , widget = StaticSelect2 ()
76
- )
77
-
78
- # URL
79
- elif cf .type == CustomFieldTypeChoices .TYPE_URL :
80
- field = LaxURLField (required = cf .required , initial = initial )
81
-
82
- # Text
83
- else :
84
- field = forms .CharField (max_length = 255 , required = cf .required , initial = initial )
85
-
86
- field .model = cf
87
- field .label = cf .label if cf .label else cf .name .replace ('_' , ' ' ).capitalize ()
88
- if cf .description :
89
- field .help_text = cf .description
90
-
91
- field_dict [field_name ] = field
92
-
93
- return field_dict
94
-
95
-
96
- class CustomFieldForm (forms .ModelForm ):
21
+ class CustomFieldModelForm (forms .ModelForm ):
97
22
98
23
def __init__ (self , * args , ** kwargs ):
99
24
100
- self .custom_fields = []
101
25
self .obj_type = ContentType .objects .get_for_model (self ._meta .model )
26
+ self .custom_fields = []
27
+ self .custom_field_values = {}
102
28
103
29
super ().__init__ (* args , ** kwargs )
104
30
105
- # Add all applicable CustomFields to the form
106
- custom_fields = []
107
- for name , field in get_custom_fields_for_model (self .obj_type ).items ():
108
- self .fields [name ] = field
109
- custom_fields .append (name )
110
- self .custom_fields = custom_fields
31
+ self ._append_customfield_fields ()
111
32
112
- # If editing an existing object, initialize values for all custom fields
33
+ def _append_customfield_fields (self ):
34
+ """
35
+ Append form fields for all CustomFields assigned to this model.
36
+ """
37
+ # Retrieve initial CustomField values for the instance
113
38
if self .instance .pk :
114
- existing_values = CustomFieldValue .objects .filter (
39
+ for cfv in CustomFieldValue .objects .filter (
115
40
obj_type = self .obj_type ,
116
41
obj_id = self .instance .pk
117
- ).prefetch_related ('field' )
118
- for cfv in existing_values :
119
- self .initial ['cf_{}' .format (str (cfv .field .name ))] = cfv .serialized_value
42
+ ).prefetch_related ('field' ):
43
+ self .custom_field_values [cfv .field .name ] = cfv .serialized_value
44
+
45
+ # Append form fields; assign initial values if modifying and existing object
46
+ for cf in CustomField .objects .filter (obj_type = self .obj_type ):
47
+ field_name = 'cf_{}' .format (cf .name )
48
+ if self .instance .pk :
49
+ self .fields [field_name ] = cf .to_form_field (set_initial = False )
50
+ self .fields [field_name ].initial = self .custom_field_values .get (cf .name )
51
+ else :
52
+ self .fields [field_name ] = cf .to_form_field ()
53
+
54
+ # Annotate the field in the list of CustomField form fields
55
+ self .custom_fields .append (field_name )
120
56
121
57
def _save_custom_fields (self ):
122
58
@@ -151,6 +87,19 @@ def save(self, commit=True):
151
87
return obj
152
88
153
89
90
+ class CustomFieldModelCSVForm (CustomFieldModelForm ):
91
+
92
+ def _append_customfield_fields (self ):
93
+
94
+ # Append form fields
95
+ for cf in CustomField .objects .filter (obj_type = self .obj_type ):
96
+ field_name = 'cf_{}' .format (cf .name )
97
+ self .fields [field_name ] = cf .to_form_field (for_csv_import = True )
98
+
99
+ # Annotate the field in the list of CustomField form fields
100
+ self .custom_fields .append (field_name )
101
+
102
+
154
103
class CustomFieldBulkEditForm (BulkEditForm ):
155
104
156
105
def __init__ (self , * args , ** kwargs ):
@@ -160,15 +109,14 @@ def __init__(self, *args, **kwargs):
160
109
self .obj_type = ContentType .objects .get_for_model (self .model )
161
110
162
111
# Add all applicable CustomFields to the form
163
- custom_fields = get_custom_fields_for_model ( self . obj_type , bulk_edit = True ). items ( )
164
- for name , field in custom_fields :
112
+ custom_fields = CustomField . objects . filter ( obj_type = self . obj_type )
113
+ for cf in custom_fields :
165
114
# Annotate non-required custom fields as nullable
166
- if not field .required :
167
- self .nullable_fields .append (name )
168
- field .required = False
169
- self .fields [name ] = field
115
+ if not cf .required :
116
+ self .nullable_fields .append (cf .name )
117
+ self .fields [cf .name ] = cf .to_form_field (set_initial = False , enforce_required = False )
170
118
# Annotate this as a custom field
171
- self .custom_fields .append (name )
119
+ self .custom_fields .append (cf . name )
172
120
173
121
174
122
class CustomFieldFilterForm (forms .Form ):
@@ -180,10 +128,11 @@ def __init__(self, *args, **kwargs):
180
128
super ().__init__ (* args , ** kwargs )
181
129
182
130
# Add all applicable CustomFields to the form
183
- custom_fields = get_custom_fields_for_model (self .obj_type , filterable_only = True ).items ()
184
- for name , field in custom_fields :
185
- field .required = False
186
- self .fields [name ] = field
131
+ custom_fields = CustomField .objects .filter (obj_type = self .obj_type ).exclude (
132
+ filter_logic = CustomFieldFilterLogicChoices .FILTER_DISABLED
133
+ )
134
+ for cf in custom_fields :
135
+ self .fields [cf .name ] = cf .to_form_field (set_initial = True , enforce_required = False )
187
136
188
137
189
138
#
0 commit comments