blob: 580bb4f4b035616a2976322841cb834a867da56c [file] [log] [blame]
Rizwan Haider30b33792016-08-18 02:11:18 -04001# models.py - Metro Network Service
2
3from django.db import models
4from core.models import Service
Rizwan Haidereb2cc772016-09-08 12:14:55 -04005from core.models import PlCoreBase
Rizwan Haidere6ffdc02016-11-08 13:43:48 -05006from core.models import Site
Rizwan Haider30b33792016-08-18 02:11:18 -04007
8METRONETWORK_KIND = "metronetwork"
9SERVICE_NAME = 'metronetwork'
Rizwan Haider65baf552016-09-28 16:47:28 -040010SERVICE_NAME_ELINE_VERBOSE = 'E-Line Service'
11SERVICE_NAME_ELAN_VERBOSE = 'E-LAN Service'
12SERVICE_NAME_ETREE_VERBOSE = 'E-Tree Service'
Rizwan Haider30b33792016-08-18 02:11:18 -040013
Rizwan Haider65baf552016-09-28 16:47:28 -040014class MetroNetworkSystem(PlCoreBase):
Rizwan Haider30b33792016-08-18 02:11:18 -040015
16 class Meta:
Rizwan Haider65baf552016-09-28 16:47:28 -040017 app_label = METRONETWORK_KIND
18 verbose_name = "Metro Network System"
Rizwan Haider30b33792016-08-18 02:11:18 -040019
20 ADMINISTRATIVE_STATE = (
21 ('enabled', 'Enabled'),
22 ('disabled', 'Disabled')
23 )
24
25 OPERATIONALSTATE = (
26 ('active', 'Active'),
27 ('inactive', 'Inactive')
28 )
29
Rizwan Haider65baf552016-09-28 16:47:28 -040030 name = models.CharField(unique=True,
31 verbose_name="Name",
32 max_length=256,
33 editable=True)
34
35 description = models.CharField(verbose_name="Description",
36 max_length=1024,
37 editable=True)
38
Rizwan Haider30b33792016-08-18 02:11:18 -040039 restUrl = models.CharField(verbose_name="Rest URL",
40 max_length=256,
41 editable=True)
42
43 administrativeState = models.CharField(choices=ADMINISTRATIVE_STATE,
44 default='disabled',
45 verbose_name="AdministrativeState",
46 max_length=16,
47 editable=True)
48
49 operationalState = models.CharField(choices=OPERATIONALSTATE,
50 verbose_name="OperationalState",
51 max_length=256,
52 editable=True)
53
54 def __init__(self, *args, **kwargs):
Rizwan Haider65baf552016-09-28 16:47:28 -040055 super(MetroNetworkSystem, self).__init__(*args, **kwargs)
Rizwan Haider30b33792016-08-18 02:11:18 -040056
57 def getAdminstrativeState(self):
58 return self.administrativeState
59
60 def setAdminstrativeState(self, value):
61 self.administrativeState = value
62
63 def getOperationalState(self):
64 return self.operationalState
65
66 def getRestUrl(self):
Rizwan Haidereb2cc772016-09-08 12:14:55 -040067 return self.restUrl
68
69
70class NetworkDevice(PlCoreBase):
71
72 class Meta:
Rizwan Haider65baf552016-09-28 16:47:28 -040073 app_label = METRONETWORK_KIND
74 verbose_name = "Network Device"
Rizwan Haidereb2cc772016-09-08 12:14:55 -040075
76 ADMINISTRATIVE_STATE = (
77 ('enabled', 'Enabled'),
78 ('disabled', 'Disabled'),
79 ('syncrequested', 'SyncRequested'),
80 ('syncinprogress', 'SyncInProgress')
81 )
82
83 AUTH_TYPE = (
84 ('basic', 'Basic'),
85 ('key', 'Key'),
86 ('oauth', 'OAuth')
87 )
88
89 # Leaving out the attributes below for now - not clear we will need them
90 # type = models.CharField(choices=TYPE, verbose_name="Type", max_length=256, editable=False)
91 # manufacturer = models.CharField(unique=False, verbose_name="Manufacturer", max_length=256, editable=False)
92 # serialNumber = models.CharField(unique=True, verbose_name="Serial Number", max_length=256, editable=False)
93 # chassisId = models.CharField(unique=False, verbose_name="Chassis ID", max_length=256, editable=False)
94
Matteo Scandoloddce4ec2016-09-26 13:11:03 -070095 name = models.CharField(max_length=20, help_text="Device friendly name", null=True, blank=True)
Rizwan Haidereb2cc772016-09-08 12:14:55 -040096 restCtrlUrl = models.CharField(unique=True,
97 verbose_name="RestCtrlURL",
98 max_length=256,
99 editable=True)
100 authType = models.CharField(choices=AUTH_TYPE, verbose_name='Auth Type', max_length=16, editable=True)
101 username = models.CharField(verbose_name='Username', max_length=32, editable=True, blank=True)
102 password = models.CharField(max_length=32, verbose_name='Password', editable=True, blank=True)
103 administrativeState = models.CharField(choices=ADMINISTRATIVE_STATE,
104 default='disabled',
105 verbose_name="AdministrativeState",
106 max_length=16,
107 editable=True)
108 id = models.CharField(unique=True,
109 verbose_name="Element Id",
110 primary_key=True,
111 max_length=256,
112 editable=True)
113
114 def __init__(self, *args, **kwargs):
115 super(NetworkDevice, self).__init__(*args, **kwargs)
116
Rizwan Haidereb2cc772016-09-08 12:14:55 -0400117class NetworkEdgePort(PlCoreBase):
118
119 class Meta:
Rizwan Haider65baf552016-09-28 16:47:28 -0400120 app_label = METRONETWORK_KIND
121 verbose_name = "Network Edge Port"
Rizwan Haidereb2cc772016-09-08 12:14:55 -0400122
123 element = models.ForeignKey(NetworkDevice, on_delete=models.CASCADE)
124 id = models.AutoField(verbose_name="id", primary_key=True, editable=False)
125 pid = models.CharField(unique=True, verbose_name="Port ID", max_length=256, editable=False)
126 bwpCfgCbs = models.IntegerField(verbose_name="Committed Burst Size", editable=False, blank=True)
127 bwpCfgEbs = models.IntegerField(verbose_name="Excess Burst Size", editable=False, blank=True)
128 bwpCfgCir = models.IntegerField(verbose_name="Committed Information Rate", editable=False, blank=True)
129 bwpCfgEir = models.IntegerField(verbose_name="Excess Information Rate", editable=False, blank=True)
130 name = models.CharField(verbose_name="Name", max_length=256, editable=True, blank=True)
131 location = models.CharField(verbose_name="Location", max_length=256, editable=True, blank=True)
132 latlng = models.CharField(verbose_name="Latitude/Longitude", max_length=50, editable=True, blank=True)
133
134 def __init__(self, *args, **kwargs):
135 super(NetworkEdgePort, self).__init__(*args, **kwargs)
136
Rizwan Haidere6ffdc02016-11-08 13:43:48 -0500137 def __unicode__(self):
138 return u'%s' % (self.pid)
139
Rizwan Haidereb2cc772016-09-08 12:14:55 -0400140 def save(self, *args, **kwargs):
141
142 if self.latlng:
143 try:
144 latlng_value = getattr(self, 'latlng').strip()
145 if (latlng_value.startswith('[') and latlng_value.endswith(']') and latlng_value.index(',') > 0):
146 lat = latlng_value[1: latlng_value.index(',')].strip()
147 lng = latlng_value[latlng_value.index(',') + 1: len(latlng_value) - 1].strip()
148
149 #If lat and lng are not floats, the code below should result in an error.
150 lat_validation = float(lat)
151 lng_validation = float(lng)
152 else:
153 raise ValueError("The lat/lng value is not formatted correctly.")
154 except:
155 raise ValueError("The lat/lng value is not formatted correctly.")
156
157 super(NetworkEdgePort, self).save(*args, **kwargs)
158
Rizwan Haider65baf552016-09-28 16:47:28 -0400159#E-Line Service
160class NetworkEdgeToEdgePointConnection(Service):
Rizwan Haidereb2cc772016-09-08 12:14:55 -0400161
162 class Meta:
163 app_label = SERVICE_NAME
Rizwan Haider65baf552016-09-28 16:47:28 -0400164 verbose_name = SERVICE_NAME_ELINE_VERBOSE
Rizwan Haidereb2cc772016-09-08 12:14:55 -0400165
166 TYPE = (
167 ('direct', 'Direct'),
168 ('tunnel', 'Tunnel'),
169 ('optical', 'Optical'),
170 ('virtual', 'Virtual'),
171 ('Point_To_Point', 'Point To Point')
172 )
173
174 OPERATIONALSTATE = (
175 ('active', 'Active'),
176 ('inactive', 'Inactive')
177 )
178
179 ADMINISTRATIVESTATE = (
180 ('disabled', 'Disabled'),
181 ('activationrequested', 'ActivationRequested'),
182 ('enabled', 'Enabled'),
183 ('invalid', 'Invalid'),
184 ('deactivationrequested', 'DeactivationRequested')
185 )
186
Rizwan Haidere6ffdc02016-11-08 13:43:48 -0500187 sid = models.CharField(verbose_name="Service ID", max_length=256, editable=True, blank=True)
Rizwan Haidereb2cc772016-09-08 12:14:55 -0400188 type = models.CharField(choices=TYPE, verbose_name="Type", max_length=256, editable=True)
Rizwan Haidere6ffdc02016-11-08 13:43:48 -0500189 vlanid = models.CharField(verbose_name="Vlanid", max_length=64, editable=True)
Rizwan Haidereb2cc772016-09-08 12:14:55 -0400190 uni1 = models.ForeignKey(NetworkEdgePort,
191 related_name='EdgePointToEdgePointSrc',
192 verbose_name="UNI 1",
193 editable=True,
194 on_delete=models.CASCADE)
195 uni2 = models.ForeignKey(NetworkEdgePort,
196 related_name='EdgePointToEdgePointDst',
197 verbose_name="UNI 2",
198 editable=True,
199 on_delete=models.CASCADE)
200 operstate = models.CharField(choices=OPERATIONALSTATE, verbose_name="OperationalState", max_length=256, editable=True)
201 adminstate = models.CharField(choices=ADMINISTRATIVESTATE, verbose_name="AdministrativeState", max_length=256, editable=True)
202
Rizwan Haider65baf552016-09-28 16:47:28 -0400203 #uni1_createbuffer = models.CharField(max_length=256, default="{}", null=True)
204 #uni2_createbuffer = models.CharField(max_length=256, default="{}", null=True)
Rizwan Haidereb2cc772016-09-08 12:14:55 -0400205
206 def __init__(self, *args, **kwargs):
207 super(NetworkEdgeToEdgePointConnection, self).__init__(*args, **kwargs)
208
Rizwan Haider65baf552016-09-28 16:47:28 -0400209#E-Tree Service
210class NetworkEdgeToMultipointConnection(Service):
Rizwan Haidereb2cc772016-09-08 12:14:55 -0400211
212 class Meta:
213 app_label = SERVICE_NAME
Rizwan Haider65baf552016-09-28 16:47:28 -0400214 verbose_name = SERVICE_NAME_ETREE_VERBOSE
Rizwan Haidereb2cc772016-09-08 12:14:55 -0400215
216 TYPE = (
217 ('vlan', 'VLAN'),
218 ('ip', 'IP'),
219 ('ethernet', 'Ethernet'),
Rizwan Haidere6ffdc02016-11-08 13:43:48 -0500220 ('Root_Multipoint', 'Root Multipoint')
Rizwan Haidereb2cc772016-09-08 12:14:55 -0400221 )
222
Rizwan Haider65baf552016-09-28 16:47:28 -0400223 OPERATIONALSTATE = (
Rizwan Haidereb2cc772016-09-08 12:14:55 -0400224 ('active', 'Active'),
225 ('inactive', 'Inactive')
226 )
227
Rizwan Haider65baf552016-09-28 16:47:28 -0400228 ADMINISTRATIVESTATE = (
229 ('disabled', 'Disabled'),
230 ('activationrequested', 'ActivationRequested'),
231 ('enabled', 'Enabled'),
232 ('invalid', 'Invalid'),
233 ('deactivationrequested', 'DeactivationRequested')
234 )
235
Rizwan Haidere6ffdc02016-11-08 13:43:48 -0500236 sid = models.CharField(verbose_name="Service ID", max_length=256, editable=True, blank=True)
237 type = models.CharField(choices=TYPE, verbose_name="Type", max_length=256, editable=True)
238 vlanid = models.CharField(verbose_name="Vlanid", max_length=64, editable=True)
Rizwan Haider65baf552016-09-28 16:47:28 -0400239 root = models.ForeignKey(NetworkEdgePort,
240 related_name='EdgeToMultipointRoot',
241 verbose_name="Root",
242 editable=True,
243 on_delete=models.CASCADE)
244 eps = models.ManyToManyField(NetworkEdgePort,
245 related_name='%(class)s_eps',
Rizwan Haidereb2cc772016-09-08 12:14:55 -0400246 verbose_name="Endpoints",
Rizwan Haidere6ffdc02016-11-08 13:43:48 -0500247 editable=True)
Rizwan Haider65baf552016-09-28 16:47:28 -0400248 operstate = models.CharField(choices=OPERATIONALSTATE, verbose_name="OperationalState", max_length=256,
249 editable=True)
250 adminstate = models.CharField(choices=ADMINISTRATIVESTATE, verbose_name="AdministrativeState", max_length=256,
251 editable=True)
252
253 # Scratch Area to help deal with the Many to Many relationship with the eps
254 #eps_createbuffer = models.CharField(max_length=1024, default="{}", null=True)
Rizwan Haidereb2cc772016-09-08 12:14:55 -0400255
256 def __init__(self, *args, **kwargs):
Rizwan Haider65baf552016-09-28 16:47:28 -0400257 super(NetworkEdgeToMultipointConnection, self).__init__(*args, **kwargs)
Rizwan Haidereb2cc772016-09-08 12:14:55 -0400258
Rizwan Haider65baf552016-09-28 16:47:28 -0400259#E-LAN Service
260class NetworkMultipointToMultipointConnection(Service):
Rizwan Haidereb2cc772016-09-08 12:14:55 -0400261
262 class Meta:
263 app_label = SERVICE_NAME
Rizwan Haider65baf552016-09-28 16:47:28 -0400264 verbose_name = SERVICE_NAME_ELAN_VERBOSE
Rizwan Haidereb2cc772016-09-08 12:14:55 -0400265
Rizwan Haider65baf552016-09-28 16:47:28 -0400266 TYPE = (
267 ('vlan', 'VLAN'),
268 ('ip', 'IP'),
269 ('ethernet', 'Ethernet'),
Rizwan Haidere6ffdc02016-11-08 13:43:48 -0500270 ('Multipoint_To_Multipoint', 'Multipoint To Multipoint')
Rizwan Haidereb2cc772016-09-08 12:14:55 -0400271 )
272
Rizwan Haider65baf552016-09-28 16:47:28 -0400273 OPERATIONALSTATE = (
Rizwan Haidereb2cc772016-09-08 12:14:55 -0400274 ('active', 'Active'),
275 ('inactive', 'Inactive')
276 )
277
Rizwan Haider65baf552016-09-28 16:47:28 -0400278 ADMINISTRATIVESTATE = (
279 ('disabled', 'Disabled'),
280 ('activationrequested', 'ActivationRequested'),
281 ('enabled', 'Enabled'),
282 ('invalid', 'Invalid'),
283 ('deactivationrequested', 'DeactivationRequested')
284 )
285
Rizwan Haidere6ffdc02016-11-08 13:43:48 -0500286 sid = models.CharField(verbose_name="Service ID", max_length=256, editable=True, blank=True)
287 type = models.CharField(choices=TYPE, verbose_name="Type", max_length=256, editable=True)
288 vlanid = models.CharField(verbose_name="Vlanid", max_length=64, editable=True)
Rizwan Haider65baf552016-09-28 16:47:28 -0400289 eps = models.ManyToManyField(NetworkEdgePort,
290 related_name='%(class)s_eps',
291 verbose_name="Endpoints",
Rizwan Haidere6ffdc02016-11-08 13:43:48 -0500292 editable=True)
Rizwan Haider65baf552016-09-28 16:47:28 -0400293
294 operstate = models.CharField(choices=OPERATIONALSTATE, verbose_name="OperationalState", max_length=256,
295 editable=True)
296 adminstate = models.CharField(choices=ADMINISTRATIVESTATE, verbose_name="AdministrativeState", max_length=256,
297 editable=True)
298
299 # Scratch Area to help deal with the Many to Many relationship with the eps
300 #eps_createbuffer = models.CharField(max_length=1024, default="{}", null=True)
Rizwan Haidereb2cc772016-09-08 12:14:55 -0400301
302 def __init__(self, *args, **kwargs):
Rizwan Haider65baf552016-09-28 16:47:28 -0400303 super(NetworkMultipointToMultipointConnection, self).__init__(*args, **kwargs)
304
Rizwan Haidere6ffdc02016-11-08 13:43:48 -0500305class BandwidthProfile(PlCoreBase):
306
307 class Meta:
308 app_label = METRONETWORK_KIND
309 verbose_name = "Bandwidth Profile"
310
311 id = models.AutoField(verbose_name="id", primary_key=True, editable=False)
312 bwpcfgcbs = models.IntegerField(verbose_name="Committed Burst Size", editable=True)
313 bwpcfgebs = models.IntegerField(verbose_name="Excess Burst Size", editable=True)
314 bwpcfgcir = models.IntegerField(verbose_name="Committed Information Rate", editable=True)
315 bwpcfgeir = models.IntegerField(verbose_name="Excess Information Rate", editable=True)
316 name = models.CharField(unique=True, verbose_name="Name", max_length=256, editable=True)
317
318 def __init__(self, *args, **kwargs):
319 super(BandwidthProfile, self).__init__(*args, **kwargs)
320
321 def __unicode__(self): return u'%s' % (self.name)
322
323# VNoD Global Objects - model is included in metro-net for simplicity
324
325class RemotePort(PlCoreBase):
326 class Meta:
327 app_label = METRONETWORK_KIND
328 verbose_name = "Remote Port"
329
330 remoteportsite = models.ForeignKey(Site,
331 related_name='RemotePortSite',
332 verbose_name="RemotePortSite",
333 editable=True,
334 on_delete=models.CASCADE)
335
336 edgeport = models.ForeignKey(NetworkEdgePort,
337 related_name='RemotePortEdgePort',
338 verbose_name="RemotePortEdgePort",
339 editable=True,
340 on_delete=models.CASCADE)
341
342 id = models.AutoField(verbose_name="id", primary_key=True, editable=False)
343 name = models.CharField(unique=True, verbose_name="Name", max_length=256, editable=True)
344
345 def __init__(self, *args, **kwargs):
346 super(RemotePort, self).__init__(*args, **kwargs)
347
348 def __unicode__(self): return u'%s' % (self.name)
349
350class ServiceSpoke(PlCoreBase):
351
352 class Meta:
353 app_label = METRONETWORK_KIND
354 verbose_name = "Service Spoke"
355
356 OPERATIONALSTATE = (
357 ('active', 'Active'),
358 ('inactive', 'Inactive')
359 )
360
361 ADMINISTRATIVE_STATE = (
362 ('disabled', 'Disabled'),
363 ('configured', 'Configured'),
364 ('impaired', 'Impaired'),
365 ('enabled', 'Enabled')
366 )
367
368 vnodlocalsite = models.ForeignKey(Site,
369 related_name='VnodLocalSite',
370 verbose_name="VnodLocalSite",
371 editable=True,
372 on_delete=models.CASCADE)
373
374 vnodlocalport = models.ForeignKey(RemotePort,
375 related_name='VnodLocalPort',
376 verbose_name="VnodLocalPort",
377 editable=True,
378 on_delete=models.CASCADE)
379
380 id = models.AutoField(verbose_name="id", primary_key=True, editable=False)
381 name = models.CharField(unique=True, verbose_name="Name", max_length=256, editable=True)
382 remotesubscriber = models.CharField(verbose_name="RemoteSubscriber", max_length=256, blank=True, editable=False)
383 remotevnodid = models.CharField(verbose_name="RemoteVnodId", max_length=256, blank=True, editable=False)
384 autoattached = models.BooleanField(verbose_name="Auto-Attached", default=False, editable=True)
385 operstate = models.CharField(choices=OPERATIONALSTATE, verbose_name="OperationalState", max_length=256,
386 editable=True, default='inactive')
387 adminstate = models.CharField(choices=ADMINISTRATIVE_STATE, default='disabled', verbose_name="AdministrativeState",
388 max_length=64, editable=True)
389
390 def __init__(self, *args, **kwargs):
391 super(ServiceSpoke, self).__init__(*args, **kwargs)
392
393 def __unicode__(self): return u'%s' % (self.name)
394
395class VnodGlobalService(Service):
396
397 class Meta:
398 app_label = SERVICE_NAME
399 verbose_name = "Virtual Network On Demand Global Service"
400
401 TYPE = (
402 ('eline', SERVICE_NAME_ELINE_VERBOSE),
403 ('elan', SERVICE_NAME_ELAN_VERBOSE),
404 ('etree', SERVICE_NAME_ETREE_VERBOSE),
405 )
406
407 OPERATIONALSTATE = (
408 ('active', 'Active'),
409 ('inactive', 'Inactive')
410 )
411
412 ADMINISTRATIVESTATE = (
413 ('disabled', 'Disabled'),
414 ('activationrequested', 'ActivationRequested'),
415 ('enabled', 'Enabled'),
416 ('invalid', 'Invalid'),
417 ('deactivationrequested', 'DeactivationRequested')
418 )
419
420 servicehandle = models.CharField(unique=True, verbose_name="Servicehandle", max_length=64, editable=True)
421 vlanid = models.CharField(verbose_name="Vlanid", max_length=64, editable=True)
422 type = models.CharField(choices=TYPE, verbose_name="Type", max_length=256, editable=True)
423
424 metronetworkroottomultipoint = models.ForeignKey(NetworkEdgeToMultipointConnection,
425 related_name='EtreeService',
426 verbose_name="EtreeService",
427 null=True,
428 editable=True,
429 on_delete=models.CASCADE)
430
431 metronetworkmultipoint = models.ForeignKey(NetworkMultipointToMultipointConnection,
432 related_name='ElanService',
433 verbose_name="ElanService",
434 null=True,
435 editable=True,
436 on_delete=models.CASCADE)
437
438 metronetworkpointtopoint = models.ForeignKey(NetworkEdgeToEdgePointConnection,
439 related_name='ElineService',
440 verbose_name="ElineService",
441 null=True,
442 editable=True,
443 on_delete=models.CASCADE)
444
445 operstate = models.CharField(choices=OPERATIONALSTATE, verbose_name="OperationalState", max_length=256,
446 editable=True)
447
448 adminstate = models.CharField(choices=ADMINISTRATIVESTATE, verbose_name="AdministrativeState", max_length=256,
449 editable=True, default='enabled')
450
451 spokes = models.ManyToManyField(ServiceSpoke,
452 related_name='ServiceSpokes',
453 verbose_name="Spokes",
454 editable=True)
455
456 bandwidthProfile = models.ForeignKey(BandwidthProfile,
457 related_name='BandwidthProfile',
458 verbose_name="BandwidthProfile",
459 editable=True,
460 on_delete=models.CASCADE)
461
462 def __init__(self, *args, **kwargs):
463 super(VnodGlobalService, self).__init__(*args, **kwargs)
Andrea Campanella11237552017-03-21 17:21:20 +0100464
465
466class UserNetworkInterface(PlCoreBase):
467
468 class Meta:
469 app_label = METRONETWORK_KIND
470 verbose_name = "User Network Interface"
471
472 id = models.AutoField(verbose_name="id", primary_key=True, editable=False)
473 enabled = models.IntegerField(verbose_name="State of UNI", editable=True)
474 capacity = models.IntegerField(verbose_name="UNI Capacity", editable=True)
475 bw_used = models.IntegerField(verbose_name="UNI bandwidth used", editable=True)
476 vlanIds = models.CharField(verbose_name="VlanIds in this UNI", max_length=256, editable=True)
477 location = models.CharField(verbose_name="Location", max_length=256, editable=True, blank=True)
478 latlng = models.CharField(verbose_name="Latitude/Longitude", max_length=50, editable=True, blank=True)
479 name = models.CharField(unique=True, verbose_name="Name", max_length=256, editable=True)
480
481 def __init__(self, *args, **kwargs):
482 super(UserNetworkInterface, self).__init__(*args, **kwargs)
483
484 def __unicode__(self): return u'%s' % (self.name)
485
486 def save(self, *args, **kwargs):
487
488 if self.latlng:
489 try:
490 latlng_value = getattr(self, 'latlng').strip()
491 if (latlng_value.startswith('[') and latlng_value.endswith(']') and latlng_value.index(',') > 0):
492 lat = latlng_value[1: latlng_value.index(',')].strip()
493 lng = latlng_value[latlng_value.index(',') + 1: len(latlng_value) - 1].strip()
494
495 # If lat and lng are not floats, the code below should result in an error.
496 lat_validation = float(lat)
497 lng_validation = float(lng)
498 else:
499 raise ValueError("The lat/lng value is not formatted correctly.")
500 except:
501 raise ValueError("The lat/lng value is not formatted correctly.")
502
503 super(UserNetworkInterface, self).save(*args, **kwargs)