models.py
627 lines
| 19.4 KiB
| text/x-python
|
PythonLexer
|
r185 | |||
|
r266 | import os | ||
import json | ||||
|
r236 | import requests | ||
|
r266 | import time | ||
|
r85 | from datetime import datetime | ||
r364 | import base64 | |||
|
r85 | |||
|
r185 | try: | ||
from polymorphic.models import PolymorphicModel | ||||
except: | ||||
from polymorphic import PolymorphicModel | ||||
|
r0 | |||
|
r266 | from django.template.base import kwarg_re | ||
|
r185 | from django.db import models | ||
r335 | from django.urls import reverse | |||
|
r266 | from django.core.validators import MinValueValidator, MaxValueValidator | ||
|
r185 | from django.shortcuts import get_object_or_404 | ||
|
r316 | from django.contrib.auth.models import User | ||
|
r319 | from django.db.models.signals import post_save | ||
from django.dispatch import receiver | ||||
|
r108 | |||
|
r266 | from apps.main.utils import Params | ||
|
r72 | |||
|
r266 | DEV_PORTS = { | ||
r350 | 'pedestal' : 80, | |||
'pedestal_dev' : 80, | ||||
'generator' : 80, | ||||
'usrp_rx' : 2000, | ||||
'usrp_tx' : 2000, | ||||
|
r266 | } | ||
RADAR_STATES = ( | ||||
(0, 'No connected'), | ||||
(1, 'Connected'), | ||||
(2, 'Configured'), | ||||
(3, 'Running'), | ||||
(4, 'Scheduled'), | ||||
|
r47 | ) | ||
|
r41 | |||
|
r266 | EXPERIMENT_TYPE = ( | ||
(0, 'RAW_DATA'), | ||||
(1, 'PDATA'), | ||||
) | ||||
DECODE_TYPE = ( | ||||
(0, 'None'), | ||||
(1, 'TimeDomain'), | ||||
(2, 'FreqDomain'), | ||||
(3, 'InvFreqDomain'), | ||||
|
r47 | ) | ||
|
r16 | |||
|
r226 | DEV_STATES = ( | ||
r350 | (0, 'Unknown'), | |||
|
r47 | (1, 'Connected'), | ||
(2, 'Configured'), | ||||
(3, 'Running'), | ||||
r350 | (4, 'Offline'), | |||
|
r47 | ) | ||
|
r2 | |||
|
r13 | DEV_TYPES = ( | ||
r345 | ('', 'Select a device type'), | |||
('pedestal', 'Pedestal Controller'), | ||||
r350 | ('pedestal_dev', 'Pedestal Controller Dev Mode'), | |||
r345 | ('generator', 'Pulse Generator'), | |||
('usrp_rx', 'Universal Software Radio Peripheral Rx'), | ||||
('usrp_tx', 'Universal Software Radio Peripheral Tx'), | ||||
|
r47 | ) | ||
|
r266 | EXP_STATES = ( | ||
(0,'Error'), #RED | ||||
|
r329 | (1,'Cancelled'), #YELLOW | ||
|
r266 | (2,'Running'), #GREEN | ||
|
r329 | (3,'Scheduled'), #BLUE | ||
(4,'Unknown'), #WHITE | ||||
|
r49 | ) | ||
|
r216 | |||
|
r266 | CONF_TYPES = ( | ||
(0, 'Active'), | ||||
(1, 'Historical'), | ||||
) | ||||
|
r162 | |||
|
r319 | class Profile(models.Model): | ||
user = models.OneToOneField(User, on_delete=models.CASCADE) | ||||
|
r326 | theme = models.CharField(max_length=30, default='spacelab') | ||
|
r319 | |||
@receiver(post_save, sender=User) | ||||
def create_user_profile(sender, instance, created, **kwargs): | ||||
if created: | ||||
Profile.objects.create(user=instance) | ||||
@receiver(post_save, sender=User) | ||||
def save_user_profile(sender, instance, **kwargs): | ||||
instance.profile.save() | ||||
|
r2 | class DeviceType(models.Model): | ||
r350 | name = models.CharField(max_length = 15, choices = DEV_TYPES, default = 'pedestal') | |||
r335 | sequence = models.PositiveSmallIntegerField(default=55) | |||
|
r13 | description = models.TextField(blank=True, null=True) | ||
|
r2 | |||
class Meta: | ||||
|
r13 | db_table = 'db_device_types' | ||
|
r162 | |||
|
r172 | def __str__(self): | ||
r349 | return u'%s' % self.name.title() | |||
|
r162 | |||
|
r2 | class Device(models.Model): | ||
|
r343 | device_type = models.ForeignKey('DeviceType', on_delete=models.CASCADE) | ||
r346 | ip_address = models.GenericIPAddressField(verbose_name = 'IP address', protocol='IPv4', default='0.0.0.0') | |||
|
r13 | port_address = models.PositiveSmallIntegerField(default=2000) | ||
|
r343 | description = models.TextField(blank=True, null=True) | ||
status = models.PositiveSmallIntegerField(default=4, choices=DEV_STATES) | ||||
conf_active = models.PositiveIntegerField(default=0, verbose_name='Current configuration') | ||||
|
r2 | |||
class Meta: | ||||
|
r13 | db_table = 'db_devices' | ||
|
r162 | |||
|
r172 | def __str__(self): | ||
r349 | ret = self.device_type | |||
return str(ret) | ||||
|
r316 | |||
@property | ||||
def name(self): | ||||
return str(self) | ||||
|
r162 | |||
def get_status(self): | ||||
|
r47 | return self.status | ||
|
r162 | |||
|
r120 | @property | ||
def status_color(self): | ||||
color = 'muted' | ||||
if self.status == 0: | ||||
color = "danger" | ||||
elif self.status == 1: | ||||
r360 | color = "primary" | |||
|
r120 | elif self.status == 2: | ||
color = "info" | ||||
elif self.status == 3: | ||||
color = "success" | ||||
|
r162 | |||
|
r120 | return color | ||
|
r226 | |||
|
r185 | def url(self, path=None): | ||
|
r226 | |||
|
r185 | if path: | ||
return 'http://{}:{}/{}/'.format(self.ip_address, self.port_address, path) | ||||
else: | ||||
return 'http://{}:{}/'.format(self.ip_address, self.port_address) | ||||
|
r226 | |||
|
r89 | def get_absolute_url(self): | ||
return reverse('url_device', args=[str(self.id)]) | ||||
|
r162 | |||
|
r316 | def get_absolute_url_edit(self): | ||
return reverse('url_edit_device', args=[str(self.id)]) | ||||
def get_absolute_url_delete(self): | ||||
return reverse('url_delete_device', args=[str(self.id)]) | ||||
|
r266 | def change_ip(self, ip_address, mask, gateway, dns, **kwargs): | ||
|
r226 | |||
r346 | if self.device_type.name=='pedestal': | |||
|
r266 | headers = {'content-type': "application/json", | ||
'cache-control': "no-cache"} | ||||
|
r343 | ip = [int(x) for x in ip_address.split('.')] | ||
dns = [int(x) for x in dns.split('.')] | ||||
|
r266 | gateway = [int(x) for x in gateway.split('.')] | ||
|
r343 | subnet = [int(x) for x in mask.split('.')] | ||
|
r266 | |||
payload = { | ||||
"ip": ip, | ||||
"dns": dns, | ||||
"gateway": gateway, | ||||
"subnet": subnet | ||||
} | ||||
req = requests.post(self.url('changeip'), data=json.dumps(payload), headers=headers) | ||||
|
r236 | try: | ||
answer = req.json() | ||||
|
r243 | if answer['changeip']=='ok': | ||
|
r343 | self.message = '25|IP succesfully changed' | ||
|
r236 | self.ip_address = ip_address | ||
self.save() | ||||
else: | ||||
self.message = '30|An error ocuur when changing IP' | ||||
except Exception as e: | ||||
self.message = '40|{}'.format(str(e)) | ||||
|
r219 | else: | ||
self.message = 'Not implemented' | ||||
return False | ||||
|
r226 | |||
|
r219 | return True | ||
|
r13 | |||
r360 | class Experiment(PolymorphicModel): | |||
r358 | ||||
|
r343 | name = models.CharField(max_length=40, default='', unique=True) | ||
r360 | pedestal = models.ForeignKey('pedestal.PedestalConfiguration', null=False, blank=False, on_delete=models.PROTECT, default=None, related_name = "pedestal_conf") | |||
r386 | generator = models.ForeignKey('generator.GeneratorConfiguration', null=False, blank=False, on_delete=models.PROTECT, default=None, related_name = "generator_conf") | |||
r360 | reception_rx = models.ForeignKey('usrp_rx.USRPRXConfiguration', null=False, blank=False, on_delete=models.PROTECT, default=None, related_name = "usrp_rx_CONF") | |||
transmission_tx = models.ForeignKey('usrp_tx.USRPTXConfiguration', null=False, blank=False, on_delete=models.PROTECT, default=None, related_name = "usrp_tx") | ||||
|
r343 | task = models.CharField(max_length=36, default='', blank=True, null=True) | ||
status = models.PositiveSmallIntegerField(default=4, choices=EXP_STATES) | ||||
r360 | author = models.ForeignKey(User, null=True, blank=True, on_delete=models.CASCADE) | |||
|
r343 | hash = models.CharField(default='', max_length=64, null=True, blank=True) | ||
r368 | latitude = models.FloatField(null=True, blank=True) | |||
longitude = models.FloatField(null=True, blank=True) | ||||
heading = models.FloatField(null=True, blank=True) | ||||
|
r2 | |||
class Meta: | ||||
|
r13 | db_table = 'db_experiments' | ||
r368 | ordering = ('name',) | |||
|
r162 | |||
|
r172 | def __str__(self): | ||
r368 | return u'%s' % (self.name) | |||
|
r162 | |||
|
r266 | def jsonify(self): | ||
data = {} | ||||
r368 | ignored = [] | |||
|
r266 | |||
for field in self._meta.fields: | ||||
if field.name in ignored: | ||||
continue | ||||
data[field.name] = field.value_from_object(self) | ||||
r358 | ||||
|
r266 | data['configurations'] = ['{}'.format(conf.pk) for | ||
|
r306 | conf in Configuration.objects.filter(experiment=self, type=0)] | ||
|
r266 | |||
return data | ||||
|
r85 | def clone(self, **kwargs): | ||
|
r162 | |||
|
r85 | confs = Configuration.objects.filter(experiment=self, type=0) | ||
self.pk = None | ||||
|
r316 | self.name = '{}_{:%y%m%d}'.format(self.name, datetime.now()) | ||
|
r85 | for attr, value in kwargs.items(): | ||
setattr(self, attr, value) | ||||
|
r162 | |||
|
r85 | self.save() | ||
|
r162 | |||
|
r85 | for conf in confs: | ||
r368 | conf.clone(experiment=self) | |||
|
r162 | |||
return self | ||||
r364 | ||||
r386 | def generator_start(self): | |||
r364 | try: | |||
r386 | period = self.transmission_tx.ipp*2/0.3 | |||
if self.transmission_tx.enable_2: | ||||
payload = {"Delay": 0, "periode1": period, "width1": self.transmission_tx.pulse_1, "repeatability1": self.transmission_tx.repetitions_1, "periode2": period, "width2": self.transmission_tx.pulse_2, "repeatability2": self.transmission_tx.repetitions_2, "enable": 1} | ||||
else: | ||||
payload = {"Delay": 0, "periode1": period, "width1": self.transmission_tx.pulse_1, "repeatability1": 1, "periode2": self.transmission_tx.periode_1, "width2": self.transmission_tx.pulse_1, "repeatability2": 1, "enable": 1} | ||||
json_trmode = json.dumps(payload) | ||||
r364 | base64_trmode = base64.standard_b64encode(json_trmode.encode('ascii')) | |||
r386 | ||||
trmode_url = self.generator.device.url() + "trmode?params=" | ||||
r364 | complete_url_trmode = trmode_url + base64_trmode.decode('ascii') | |||
r386 | ||||
r364 | r = requests.get(complete_url_trmode) | |||
except: | ||||
return False | ||||
return True | ||||
|
r196 | def start(self): | ||
''' | ||||
|
r226 | Configure and start experiments's devices | ||
|
r196 | ''' | ||
r386 | ||||
data = { | ||||
'name': '%s_%d' % (self.name, int(time.time())), | ||||
'latitude': self.latitude, | ||||
'longitude': self.longitude, | ||||
'heading': self.heading | ||||
} | ||||
r335 | ||||
r391 | self.reception_rx.datadir = os.path.join(os.environ['EXPOSE_NAS'], data['name'], 'rawdata') | |||
self.reception_rx.save() | ||||
|
r329 | try: | ||
r386 | proc_url = 'http://10.10.10.130:8086/start' | |||
data['pedestal'] = self.pedestal.jsonify() | ||||
data['usrp_rx'] = self.reception_rx.jsonify() | ||||
data['usrp_tx'] = self.transmission_tx.jsonify() | ||||
payload = json.dumps(data) | ||||
ret = requests.post(proc_url, json=data) | ||||
self.reception_rx.start_device() | ||||
self.pedestal.start_device() | ||||
self.generator_start() | ||||
self.transmission_tx.start_device() | ||||
|
r329 | except: | ||
return 0 | ||||
return 2 | ||||
|
r226 | |||
|
r250 | |||
|
r226 | def stop(self): | ||
|
r196 | ''' | ||
|
r226 | Stop experiments's devices | ||
r365 | PEDESTAL, GENERATOR & USRP's | |||
|
r196 | ''' | ||
|
r226 | |||
r360 | #confs = Configuration.objects.filter(experiment=self, type = 0).order_by('device__device_type__sequence') | |||
experiment = get_object_or_404(Experiment, pk=self.id) | ||||
id_p = experiment.pedestal_id | ||||
id_rx = experiment.reception_rx_id | ||||
id_tx = experiment.transmission_tx_id | ||||
r364 | generator_url = experiment.generator.url() | |||
r360 | ||||
|
r329 | try: | ||
r386 | proc_url = 'http://10.10.10.130:8086/stop' | |||
ret = requests.get(proc_url) | ||||
r360 | Configuration.objects.get(id = id_p).stop_device() | |||
Configuration.objects.get(id = id_tx).stop_device() | ||||
r364 | generator_stop = generator_url + "stop" | |||
r = requests.get(generator_stop) | ||||
Configuration.objects.get(id = id_rx).stop_device() | ||||
|
r329 | except: | ||
return 0 | ||||
return 1 | ||||
|
r250 | |||
|
r196 | def get_status(self): | ||
|
r226 | |||
|
r306 | if self.status == 3: | ||
return | ||||
confs = Configuration.objects.filter(experiment=self, type=0) | ||||
|
r243 | |||
|
r240 | for conf in confs: | ||
conf.status_device() | ||||
|
r243 | |||
|
r216 | total = confs.aggregate(models.Sum('device__status'))['device__status__sum'] | ||
|
r162 | |||
|
r196 | if total==2*confs.count(): | ||
status = 1 | ||||
elif total == 3*confs.count(): | ||||
|
r84 | status = 2 | ||
else: | ||||
|
r196 | status = 0 | ||
|
r162 | |||
|
r306 | self.status = status | ||
self.save() | ||||
|
r162 | |||
|
r84 | def status_color(self): | ||
|
r121 | color = 'muted' | ||
|
r84 | if self.status == 0: | ||
color = "danger" | ||||
elif self.status == 1: | ||||
|
r329 | color = "warning" | ||
|
r84 | elif self.status == 2: | ||
|
r91 | color = "success" | ||
|
r84 | elif self.status == 3: | ||
|
r329 | color = "info" | ||
|
r162 | |||
|
r226 | return color | ||
|
r162 | |||
|
r100 | def parms_to_dict(self): | ||
|
r162 | |||
r311 | params = Params({}) | |||
|
r266 | params.add(self.jsonify(), 'experiments') | ||
|
r162 | |||
|
r266 | configurations = Configuration.objects.filter(experiment=self, type=0) | ||
|
r162 | |||
|
r266 | for conf in configurations: | ||
params.add(conf.jsonify(), 'configurations') | ||||
|
r162 | |||
|
r266 | return params.data | ||
|
r162 | |||
|
r266 | def dict_to_parms(self, parms, CONF_MODELS, id_exp=None): | ||
|
r162 | |||
|
r108 | configurations = Configuration.objects.filter(experiment=self) | ||
|
r162 | |||
|
r266 | if id_exp is not None: | ||
exp_parms = parms['experiments']['byId'][id_exp] | ||||
else: | ||||
exp_parms = parms['experiments']['byId'][parms['experiments']['allIds'][0]] | ||||
|
r108 | if configurations: | ||
|
r243 | for configuration in configurations: | ||
configuration.delete() | ||||
|
r266 | |||
for id_conf in exp_parms['configurations']: | ||||
conf_parms = parms['configurations']['byId'][id_conf] | ||||
|
r343 | device = Device.objects.filter(device_type__name=conf_parms['device_type'])[0] | ||
model = CONF_MODELS[conf_parms['device_type']] | ||||
|
r266 | conf = model( | ||
experiment = self, | ||||
device = device, | ||||
) | ||||
conf.dict_to_parms(parms, id=id_conf) | ||||
r358 | ||||
|
r266 | self.name = '{}-{}'.format(exp_parms['name'], datetime.now().strftime('%y%m%d')) | ||
|
r110 | self.save() | ||
|
r162 | |||
|
r110 | return self | ||
|
r226 | |||
|
r196 | def get_absolute_url(self): | ||
return reverse('url_experiment', args=[str(self.id)]) | ||||
|
r162 | |||
|
r108 | def get_absolute_url_edit(self): | ||
return reverse('url_edit_experiment', args=[str(self.id)]) | ||||
|
r162 | |||
|
r316 | def get_absolute_url_delete(self): | ||
return reverse('url_delete_experiment', args=[str(self.id)]) | ||||
|
r108 | def get_absolute_url_import(self): | ||
return reverse('url_import_experiment', args=[str(self.id)]) | ||||
|
r162 | |||
|
r100 | def get_absolute_url_export(self): | ||
return reverse('url_export_experiment', args=[str(self.id)]) | ||||
|
r162 | |||
|
r240 | def get_absolute_url_start(self): | ||
return reverse('url_start_experiment', args=[str(self.id)]) | ||||
def get_absolute_url_stop(self): | ||||
return reverse('url_stop_experiment', args=[str(self.id)]) | ||||
|
r162 | |||
|
r6 | class Configuration(PolymorphicModel): | ||
|
r2 | |||
r349 | id = models.AutoField(primary_key=True) | |||
|
r343 | device = models.ForeignKey('Device', verbose_name='Device', null=True, on_delete=models.CASCADE) | ||
type = models.PositiveSmallIntegerField(default=0, choices=CONF_TYPES) | ||||
created_date = models.DateTimeField(auto_now_add=True) | ||||
|
r22 | programmed_date = models.DateTimeField(auto_now=True) | ||
|
r343 | parameters = models.TextField(default='{}') | ||
author = models.ForeignKey(User, null=True, blank=True,on_delete=models.CASCADE) | ||||
hash = models.CharField(default='', max_length=64, null=True, blank=True) | ||||
|
r53 | message = "" | ||
|
r162 | |||
|
r2 | class Meta: | ||
|
r13 | db_table = 'db_configurations' | ||
|
r316 | ordering = ('device__device_type__name',) | ||
|
r162 | |||
|
r172 | def __str__(self): | ||
|
r162 | |||
|
r316 | ret = u'{} '.format(self.device.device_type.name.upper()) | ||
|
r162 | |||
|
r172 | if 'mix' in [f.name for f in self._meta.get_fields()]: | ||
|
r138 | if self.mix: | ||
|
r316 | ret = '{} MIX '.format(self.device.device_type.name.upper()) | ||
r335 | ||||
|
r316 | if 'label' in [f.name for f in self._meta.get_fields()]: | ||
|
r319 | ret += '{}'.format(self.label) | ||
|
r162 | |||
|
r316 | return ret | ||
@property | ||||
def name(self): | ||||
return str(self) | ||||
|
r79 | |||
r368 | @property | |||
def label(self): | ||||
return str(self) | ||||
|
r266 | def jsonify(self): | ||
data = {} | ||||
ignored = ('type', 'polymorphic_ctype', 'configuration_ptr', | ||||
r368 | 'created_date', 'programmed_date', 'device', | |||
r360 | 'experiment', 'author') | |||
|
r266 | |||
for field in self._meta.fields: | ||||
if field.name in ignored: | ||||
continue | ||||
data[field.name] = field.value_from_object(self) | ||||
data['device_type'] = self.device.device_type.name | ||||
return data | ||||
|
r85 | def clone(self, **kwargs): | ||
|
r162 | |||
|
r85 | self.pk = None | ||
self.id = None | ||||
for attr, value in kwargs.items(): | ||||
setattr(self, attr, value) | ||||
|
r162 | |||
self.save() | ||||
|
r85 | |||
return self | ||||
|
r162 | |||
|
r53 | def parms_to_dict(self): | ||
|
r162 | |||
r311 | params = Params({}) | |||
|
r266 | params.add(self.jsonify(), 'configurations') | ||
return params.data | ||||
|
r162 | |||
|
r57 | def parms_to_text(self): | ||
|
r162 | |||
|
r172 | raise NotImplementedError("This method should be implemented in %s Configuration model" %str(self.device.device_type.name).upper()) | ||
|
r162 | |||
|
r57 | def parms_to_binary(self): | ||
|
r162 | |||
|
r172 | raise NotImplementedError("This method should be implemented in %s Configuration model" %str(self.device.device_type.name).upper()) | ||
|
r162 | |||
|
r266 | def dict_to_parms(self, parameters, id=None): | ||
params = Params(parameters) | ||||
if id: | ||||
data = params.get_conf(id_conf=id) | ||||
else: | ||||
data = params.get_conf(dtype=self.device.device_type.name) | ||||
|
r162 | |||
|
r266 | for key, value in data.items(): | ||
if key not in ('id', 'device_type'): | ||||
setattr(self, key, value) | ||||
r346 | ||||
|
r266 | self.save() | ||
|
r162 | |||
|
r267 | |||
def export_to_file(self, format="json"): | ||||
|
r162 | |||
|
r57 | content_type = '' | ||
|
r162 | |||
|
r276 | if format == 'racp': | ||
content_type = 'text/plain' | ||||
filename = '%s_%s.%s' %(self.device.device_type.name, self.name, 'racp') | ||||
content = self.parms_to_text(file_format = 'racp') | ||||
|
r53 | if format == 'text': | ||
content_type = 'text/plain' | ||||
|
r57 | filename = '%s_%s.%s' %(self.device.device_type.name, self.name, self.device.device_type.name) | ||
content = self.parms_to_text() | ||||
|
r162 | |||
|
r53 | if format == 'binary': | ||
content_type = 'application/octet-stream' | ||||
|
r266 | filename = '%s_%s.bin' %(self.device.device_type.name, self.name) | ||
|
r57 | content = self.parms_to_binary() | ||
|
r162 | |||
|
r57 | if not content_type: | ||
content_type = 'application/json' | ||||
filename = '%s_%s.json' %(self.device.device_type.name, self.name) | ||||
|
r79 | content = json.dumps(self.parms_to_dict(), indent=2) | ||
r368 | ||||
|
r162 | |||
|
r53 | fields = {'content_type':content_type, | ||
'filename':filename, | ||||
'content':content | ||||
} | ||||
|
r162 | |||
|
r53 | return fields | ||
|
r162 | |||
|
r267 | def import_from_file(self, fp): | ||
|
r162 | |||
|
r57 | parms = {} | ||
|
r162 | |||
|
r57 | path, ext = os.path.splitext(fp.name) | ||
|
r162 | |||
|
r57 | if ext == '.json': | ||
parms = json.load(fp) | ||||
|
r162 | |||
|
r57 | return parms | ||
|
r162 | |||
|
r53 | def status_device(self): | ||
|
r162 | |||
r360 | self.message = 'Function not supported' | |||
|
r185 | return False | ||
|
r162 | |||
|
r53 | def stop_device(self): | ||
|
r162 | |||
r360 | self.message = 'Function not supported' | |||
|
r185 | return False | ||
|
r162 | |||
|
r53 | def start_device(self): | ||
r360 | ||||
self.message = 'Function not supported' | ||||
|
r185 | return False | ||
|
r162 | |||
r346 | def write_device(self): | |||
|
r162 | |||
r360 | self.message = 'Function not supported' | |||
|
r185 | return False | ||
|
r162 | |||
|
r53 | def read_device(self): | ||
|
r162 | |||
r360 | self.message = 'Function not supported' | |||
|
r185 | return False | ||
|
r162 | |||
|
r47 | def get_absolute_url(self): | ||
|
r23 | return reverse('url_%s_conf' % self.device.device_type.name, args=[str(self.id)]) | ||
|
r162 | |||
|
r30 | def get_absolute_url_edit(self): | ||
return reverse('url_edit_%s_conf' % self.device.device_type.name, args=[str(self.id)]) | ||||
|
r162 | |||
|
r316 | def get_absolute_url_delete(self): | ||
return reverse('url_delete_dev_conf', args=[str(self.id)]) | ||||
r335 | ||||
|
r30 | def get_absolute_url_import(self): | ||
|
r53 | return reverse('url_import_dev_conf', args=[str(self.id)]) | ||
|
r162 | |||
|
r30 | def get_absolute_url_export(self): | ||
|
r53 | return reverse('url_export_dev_conf', args=[str(self.id)]) | ||
|
r162 | |||
|
r30 | def get_absolute_url_write(self): | ||
|
r53 | return reverse('url_write_dev_conf', args=[str(self.id)]) | ||
|
r162 | |||
|
r30 | def get_absolute_url_read(self): | ||
|
r53 | return reverse('url_read_dev_conf', args=[str(self.id)]) | ||
|
r162 | |||
|
r53 | def get_absolute_url_start(self): | ||
return reverse('url_start_dev_conf', args=[str(self.id)]) | ||||
|
r162 | |||
|
r53 | def get_absolute_url_stop(self): | ||
return reverse('url_stop_dev_conf', args=[str(self.id)]) | ||||
|
r162 | |||
|
r53 | def get_absolute_url_status(self): | ||
|
r162 | return reverse('url_status_dev_conf', args=[str(self.id)]) | ||