From c9b84047d20a302667fcd5fcf2f072528c21e9e3 Mon Sep 17 00:00:00 2001 From: detraz Date: Sun, 3 Mar 2019 17:28:33 +0100 Subject: [PATCH] =?UTF-8?q?Change=20les=20variables=20type=20en=20name=20o?= =?UTF-8?q?u=20machine=5Ftype=20pour=20=C3=A9viter=20les=20confusions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/serializers.py | 12 ++--- freeradius_utils/auth.py | 8 ++-- machines/admin.py | 2 +- machines/forms.py | 18 ++++---- .../migrations/0102_auto_20190303_1611.py | 30 ++++++++++++ machines/models.py | 46 +++++++++---------- machines/templates/machines/aff_iptype.html | 2 +- machines/templates/machines/aff_machines.html | 2 +- .../templates/machines/aff_machinetype.html | 2 +- machines/views.py | 18 ++++---- re2o/utils.py | 2 +- topologie/models.py | 2 +- users/views.py | 2 +- 13 files changed, 88 insertions(+), 58 deletions(-) create mode 100644 machines/migrations/0102_auto_20190303_1611.py diff --git a/api/serializers.py b/api/serializers.py index 8c22ed21..eabcc73a 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -150,7 +150,7 @@ class MachineTypeSerializer(NamespacedHMSerializer): class Meta: model = machines.MachineType - fields = ('type', 'ip_type', 'api_url') + fields = ('name', 'ip_type', 'api_url') class IpTypeSerializer(NamespacedHMSerializer): @@ -159,7 +159,7 @@ class IpTypeSerializer(NamespacedHMSerializer): class Meta: model = machines.IpType - fields = ('type', 'extension', 'need_infra', 'domaine_ip_start', + fields = ('name', 'extension', 'need_infra', 'domaine_ip_start', 'domaine_ip_stop', 'prefix_v6', 'vlan', 'ouverture_ports', 'api_url') @@ -267,7 +267,7 @@ class InterfaceSerializer(NamespacedHMSerializer): class Meta: model = machines.Interface - fields = ('ipv4', 'mac_address', 'machine', 'type', 'details', + fields = ('ipv4', 'mac_address', 'machine', 'machine_type', 'details', 'port_lists', 'active', 'api_url') @@ -747,7 +747,7 @@ class InterfaceVlanSerializer(NamespacedHMSerializer): domain = serializers.CharField(read_only=True) ipv4 = serializers.CharField(read_only=True) ipv6 = Ipv6ListSerializer(read_only=True, many=True) - vlan_id = serializers.IntegerField(source='type.ip_type.vlan.vlan_id', read_only=True) + vlan_id = serializers.IntegerField(source='machine_type.ip_type.vlan.vlan_id', read_only=True) class Meta: model = machines.Interface @@ -865,7 +865,7 @@ class SubnetPortsOpenSerializer(serializers.ModelSerializer): class Meta: model = machines.IpType - fields = ('type', 'domaine_ip_start', 'domaine_ip_stop', 'complete_prefixv6', 'ouverture_ports') + fields = ('name', 'domaine_ip_start', 'domaine_ip_stop', 'complete_prefixv6', 'ouverture_ports') class InterfacePortsOpenSerializer(serializers.ModelSerializer): @@ -1080,7 +1080,7 @@ class DNSReverseZonesSerializer(serializers.ModelSerializer): class Meta: model = machines.IpType - fields = ('type', 'extension', 'soa', 'ns_records', 'mx_records', + fields = ('name', 'extension', 'soa', 'ns_records', 'mx_records', 'txt_records', 'ptr_records', 'ptr_v6_records', 'cidrs', 'prefix_v6', 'prefix_v6_length') diff --git a/freeradius_utils/auth.py b/freeradius_utils/auth.py index 54364dc1..7245013e 100644 --- a/freeradius_utils/auth.py +++ b/freeradius_utils/auth.py @@ -148,7 +148,7 @@ def authorize(data): # Toutes les reuquètes non proxifiées nas_type = None if nas_instance: - nas_type = Nas.objects.filter(nas_type=nas_instance.type).first() + nas_type = Nas.objects.filter(nas_type=nas_instance.machine_type).first() if not nas_type or nas_type.port_access_mode == '802.1X': user = data.get('User-Name', '').decode('utf-8', errors='replace') user = user.split('@', 1)[0] @@ -193,7 +193,7 @@ def post_auth(data): if not nas_instance: logger.info(u"Requete proxifiee, nas inconnu".encode('utf-8')) return radiusd.RLM_MODULE_OK - nas_type = Nas.objects.filter(nas_type=nas_instance.type).first() + nas_type = Nas.objects.filter(nas_type=nas_instance.machine_type).first() if not nas_type: logger.info( u"Type de nas non enregistre dans la bdd!".encode('utf-8') @@ -280,7 +280,7 @@ def find_nas_from_request(nas_id): Q(domain=Domain.objects.filter(name=nas_id)) | Q(ipv4=IpList.objects.filter(ipv4=nas_id)) ) - .select_related('type') + .select_related('machine_type') .select_related('machine__switch__stack')) return nas.first() @@ -531,7 +531,7 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, # Si on choisi de placer les machines sur le vlan # correspondant à leur type : if RadiusOption.get_cached_value('radius_general_policy') == 'MACHINE': - DECISION_VLAN = interface.type.ip_type.vlan.vlan_id + DECISION_VLAN = interface.machine_type.ip_type.vlan.vlan_id if not interface.ipv4: interface.assign_ipv4() return ( diff --git a/machines/admin.py b/machines/admin.py index bafebb80..099fa1ba 100644 --- a/machines/admin.py +++ b/machines/admin.py @@ -136,7 +136,7 @@ class OuverturePortListAdmin(VersionAdmin): class InterfaceAdmin(VersionAdmin): """ Admin view of a Interface object """ - list_display = ('machine', 'type', 'mac_address', 'ipv4', 'details') + list_display = ('machine', 'machine_type', 'mac_address', 'ipv4', 'details') class DomainAdmin(VersionAdmin): diff --git a/machines/forms.py b/machines/forms.py index 94b9293a..af05a48e 100644 --- a/machines/forms.py +++ b/machines/forms.py @@ -90,15 +90,15 @@ class EditInterfaceForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): class Meta: model = Interface - fields = ['machine', 'type', 'ipv4', 'mac_address', 'details'] + fields = ['machine', 'machine_type', 'ipv4', 'mac_address', 'details'] def __init__(self, *args, **kwargs): prefix = kwargs.pop('prefix', self.Meta.model.__name__) user = kwargs.get('user') super(EditInterfaceForm, self).__init__(*args, prefix=prefix, **kwargs) self.fields['mac_address'].label = _("MAC address") - self.fields['type'].label = _("Machine type") - self.fields['type'].empty_label = _("Select a machine type") + self.fields['machine_type'].label = _("Machine type") + self.fields['machine_type'].empty_label = _("Select a machine type") if "ipv4" in self.fields: self.fields['ipv4'].empty_label = _("Automatic IPv4 assignment") self.fields['ipv4'].queryset = IpList.objects.filter( @@ -122,7 +122,7 @@ class EditInterfaceForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): .select_related('user') can_use_all_machinetype, _reason = MachineType.can_use_all(user) if not can_use_all_machinetype: - self.fields['type'].queryset = MachineType.objects.filter( + self.fields['machine_type'].queryset = MachineType.objects.filter( ip_type__in=IpType.objects.filter(need_infra=False) ) @@ -132,7 +132,7 @@ class AddInterfaceForm(EditInterfaceForm): affiche ou non l'ensemble des ip disponibles""" class Meta(EditInterfaceForm.Meta): - fields = ['type', 'ipv4', 'mac_address', 'details'] + fields = ['machine_type', 'ipv4', 'mac_address', 'details'] class AliasForm(FormRevMixin, ModelForm): @@ -191,12 +191,12 @@ class MachineTypeForm(FormRevMixin, ModelForm): class Meta: model = MachineType - fields = ['type', 'ip_type'] + fields = ['name', 'ip_type'] def __init__(self, *args, **kwargs): prefix = kwargs.pop('prefix', self.Meta.model.__name__) super(MachineTypeForm, self).__init__(*args, prefix=prefix, **kwargs) - self.fields['type'].label = _("Machine type to add") + self.fields['name'].label = _("Machine type to add") self.fields['ip_type'].label = _("Related IP type") @@ -228,7 +228,7 @@ class IpTypeForm(FormRevMixin, ModelForm): def __init__(self, *args, **kwargs): prefix = kwargs.pop('prefix', self.Meta.model.__name__) super(IpTypeForm, self).__init__(*args, prefix=prefix, **kwargs) - self.fields['type'].label = _("IP type to add") + self.fields['name'].label = _("IP type to add") class EditIpTypeForm(IpTypeForm): @@ -236,7 +236,7 @@ class EditIpTypeForm(IpTypeForm): synchroniser les objets iplist""" class Meta(IpTypeForm.Meta): - fields = ['extension', 'type', 'need_infra', 'domaine_ip_network', 'domaine_ip_netmask', + fields = ['extension', 'name', 'need_infra', 'domaine_ip_network', 'domaine_ip_netmask', 'prefix_v6', 'prefix_v6_length', 'vlan', 'reverse_v4', 'reverse_v6', 'ouverture_ports'] diff --git a/machines/migrations/0102_auto_20190303_1611.py b/machines/migrations/0102_auto_20190303_1611.py new file mode 100644 index 00000000..3531fb11 --- /dev/null +++ b/machines/migrations/0102_auto_20190303_1611.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2019-03-03 15:11 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('machines', '0101_auto_20190108_1623'), + ] + + operations = [ + migrations.RenameField( + model_name='interface', + old_name='type', + new_name='machine_type', + ), + migrations.RenameField( + model_name='iptype', + old_name='type', + new_name='name', + ), + migrations.RenameField( + model_name='machinetype', + old_name='type', + new_name='name', + ), + ] diff --git a/machines/models.py b/machines/models.py index 75da1317..a1ab5b6c 100644 --- a/machines/models.py +++ b/machines/models.py @@ -241,7 +241,7 @@ class Machine(RevMixin, FieldPermissionModelMixin, models.Model): class MachineType(RevMixin, AclMixin, models.Model): """ Type de machine, relié à un type d'ip, affecté aux interfaces""" - type = models.CharField(max_length=255) + name = models.CharField(max_length=255) ip_type = models.ForeignKey( 'IpType', on_delete=models.PROTECT, @@ -260,7 +260,7 @@ class MachineType(RevMixin, AclMixin, models.Model): def all_interfaces(self): """ Renvoie toutes les interfaces (cartes réseaux) de type machinetype""" - return Interface.objects.filter(type=self) + return Interface.objects.filter(machine_type=self) @staticmethod def can_use_all(user_request, *_args, **_kwargs): @@ -278,12 +278,12 @@ class MachineType(RevMixin, AclMixin, models.Model): return True, None def __str__(self): - return self.type + return self.name class IpType(RevMixin, AclMixin, models.Model): """ Type d'ip, définissant un range d'ip, affecté aux machine types""" - type = models.CharField(max_length=255) + name = models.CharField(max_length=255) extension = models.ForeignKey('Extension', on_delete=models.PROTECT) need_infra = models.BooleanField(default=False) domaine_ip_start = models.GenericIPAddressField(protocol='IPv4') @@ -456,7 +456,7 @@ class IpType(RevMixin, AclMixin, models.Model): else: for ipv6 in Ipv6List.objects.filter( interface__in=Interface.objects.filter( - type__in=MachineType.objects.filter(ip_type=self) + machine_type__in=MachineType.objects.filter(ip_type=self) ) ): ipv6.check_and_replace_prefix(prefix=self.prefix_v6) @@ -465,7 +465,7 @@ class IpType(RevMixin, AclMixin, models.Model): from re2o.utils import all_active_assigned_interfaces if self.reverse_v4: return (all_active_assigned_interfaces() - .filter(type__ip_type=self) + .filter(machine_type__ip_type=self) .filter(ipv4__isnull=False)) else: return None @@ -474,7 +474,7 @@ class IpType(RevMixin, AclMixin, models.Model): from re2o.utils import all_active_interfaces if self.reverse_v6: return (all_active_interfaces(full=True) - .filter(type__ip_type=self)) + .filter(machine_type__ip_type=self)) else: return None @@ -519,7 +519,7 @@ class IpType(RevMixin, AclMixin, models.Model): return user_request.has_perm('machines.use_all_iptype'), None def __str__(self): - return self.type + return self.name class Vlan(RevMixin, AclMixin, models.Model): @@ -724,19 +724,19 @@ class Extension(RevMixin, AclMixin, models.Model): def get_associated_sshfp_records(self): from re2o.utils import all_active_assigned_interfaces return (all_active_assigned_interfaces() - .filter(type__ip_type__extension=self) + .filter(machine_type__ip_type__extension=self) .filter(machine__id__in=SshFp.objects.values('machine'))) def get_associated_a_records(self): from re2o.utils import all_active_assigned_interfaces return (all_active_assigned_interfaces() - .filter(type__ip_type__extension=self) + .filter(machine_type__ip_type__extension=self) .filter(ipv4__isnull=False)) def get_associated_aaaa_records(self): from re2o.utils import all_active_interfaces return (all_active_interfaces(full=True) - .filter(type__ip_type__extension=self)) + .filter(machine_type__ip_type__extension=self)) def get_associated_cname_records(self): from re2o.utils import all_active_assigned_interfaces @@ -1003,7 +1003,7 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): ) mac_address = MACAddressField(integer=False) machine = models.ForeignKey('Machine', on_delete=models.CASCADE) - type = models.ForeignKey('MachineType', on_delete=models.PROTECT) + machine_type = models.ForeignKey('MachineType', on_delete=models.PROTECT) details = models.CharField(max_length=255, blank=True) port_lists = models.ManyToManyField('OuverturePortList', blank=True) @@ -1027,9 +1027,9 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): def ipv6_slaac(self): """ Renvoie un objet type ipv6 à partir du prefix associé à l'iptype parent""" - if self.type.ip_type.prefix_v6: + if self.machine_type.ip_type.prefix_v6: return EUI(self.mac_address).ipv6( - IPNetwork(self.type.ip_type.prefix_v6).network + IPNetwork(self.machine_type.ip_type.prefix_v6).network ) else: return None @@ -1037,7 +1037,7 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): @cached_property def gen_ipv6_dhcpv6(self): """Cree une ip, à assigner avec dhcpv6 sur une machine""" - prefix_v6 = self.type.ip_type.prefix_v6.encode().decode('utf-8') + prefix_v6 = self.machine_type.ip_type.prefix_v6.encode().decode('utf-8') if not prefix_v6: return None return IPv6Address( @@ -1122,7 +1122,7 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): def assign_ipv4(self): """ Assigne une ip à l'interface """ - free_ips = self.type.ip_type.free_ip() + free_ips = self.machine_type.ip_type.free_ip() if free_ips: self.ipv4 = free_ips[0] else: @@ -1162,16 +1162,16 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): # instance. # But in our case, it's impossible to create a type value so we raise # the error. - if not hasattr(self, 'type'): + if not hasattr(self, 'machine_type'): raise ValidationError(_("The selected IP type is invalid.")) self.filter_macaddress() - if not self.ipv4 or self.type.ip_type != self.ipv4.ip_type: + if not self.ipv4 or self.machine_type.ip_type != self.ipv4.ip_type: self.assign_ipv4() super(Interface, self).clean(*args, **kwargs) def validate_unique(self, *args, **kwargs): super(Interface, self).validate_unique(*args, **kwargs) - interfaces_similar = Interface.objects.filter(mac_address=self.mac_address, type__ip_type=self.type.ip_type) + interfaces_similar = Interface.objects.filter(mac_address=self.mac_address, machine_type__ip_type=self.machine_type.ip_type) if interfaces_similar and interfaces_similar.first() != self: raise ValidationError(_("Mac address already registered in this Machine Type/Subnet")) @@ -1179,7 +1179,7 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): self.filter_macaddress() # On verifie la cohérence en forçant l'extension par la méthode if self.ipv4: - if self.type.ip_type != self.ipv4.ip_type: + if self.machine_type.ip_type != self.ipv4.ip_type: raise ValidationError(_("The IPv4 address and the machine type" " don't match.")) self.validate_unique() @@ -1381,7 +1381,7 @@ class Ipv6List(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): def check_and_replace_prefix(self, prefix=None): """Si le prefixe v6 est incorrect, on maj l'ipv6""" - prefix_v6 = prefix or self.interface.type.ip_type.prefix_v6.encode().decode('utf-8') + prefix_v6 = prefix or self.interface.machine_type.ip_type.prefix_v6.encode().decode('utf-8') if not prefix_v6: return if (IPv6Address(self.ipv6.encode().decode('utf-8')).exploded[:20] != @@ -1398,7 +1398,7 @@ class Ipv6List(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): .exclude(id=self.id)): raise ValidationError(_("A SLAAC IP address is already registered.")) try: - prefix_v6 = self.interface.type.ip_type.prefix_v6.encode().decode('utf-8') + prefix_v6 = self.interface.machine_type.ip_type.prefix_v6.encode().decode('utf-8') except AttributeError: # Prevents from crashing when there is no defined prefix_v6 prefix_v6 = None if prefix_v6: @@ -1453,7 +1453,7 @@ class Domain(RevMixin, AclMixin, models.Model): """ Retourne l'extension de l'interface parente si c'est un A Retourne l'extension propre si c'est un cname, renvoie None sinon""" if self.interface_parent: - return self.interface_parent.type.ip_type.extension + return self.interface_parent.machine_type.ip_type.extension elif hasattr(self, 'extension'): return self.extension else: diff --git a/machines/templates/machines/aff_iptype.html b/machines/templates/machines/aff_iptype.html index c30c0c73..08372a7d 100644 --- a/machines/templates/machines/aff_iptype.html +++ b/machines/templates/machines/aff_iptype.html @@ -45,7 +45,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% for type in iptype_list %} - {{ type.type }} + {{ type.name }} {{ type.extension }} {{ type.need_infra|tick }} {{ type.domaine_ip_start }}-{{ type.domaine_ip_stop }}{% if type.ip_network %} on diff --git a/machines/templates/machines/aff_machines.html b/machines/templates/machines/aff_machines.html index 6001f7ce..c444b78b 100644 --- a/machines/templates/machines/aff_machines.html +++ b/machines/templates/machines/aff_machines.html @@ -88,7 +88,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% endif %} - {{ interface.type }} + {{ interface.machine_type }} {{ interface.mac_address }} diff --git a/machines/templates/machines/aff_machinetype.html b/machines/templates/machines/aff_machinetype.html index ebd77b4f..d80044bb 100644 --- a/machines/templates/machines/aff_machinetype.html +++ b/machines/templates/machines/aff_machinetype.html @@ -36,7 +36,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% for type in machinetype_list %} - {{ type.type }} + {{ type.name }} {{ type.ip_type }} {% can_edit type %} diff --git a/machines/views.py b/machines/views.py index 59d4bd5a..bdbb1a83 100644 --- a/machines/views.py +++ b/machines/views.py @@ -144,7 +144,7 @@ def f_type_id(is_type_tt): """ The id that will be used in HTML to store the value of the field type. Depends on the fact that type is generate using typeahead or not """ - return 'id_Interface-type_hidden' if is_type_tt else 'id_Interface-type' + return 'id_Interface-machine_type_hidden' if is_type_tt else 'id_Interface-machine_type' def generate_ipv4_choices(form_obj): @@ -170,7 +170,7 @@ def generate_ipv4_choices(form_obj): v=ip.ipv4 ) - for t in form_obj.fields['type'].queryset.exclude(id__in=used_mtype_id): + for t in form_obj.fields['machine_type'].queryset.exclude(id__in=used_mtype_id): choices += '], "' + str(t.id) + '": [' choices += '{key: "", value: "' + str(f_ipv4.empty_label) + '"},' choices += ']}' @@ -184,11 +184,11 @@ def generate_ipv4_engine(is_type_tt): 'new Bloodhound( {{' 'datumTokenizer: Bloodhound.tokenizers.obj.whitespace( "value" ),' 'queryTokenizer: Bloodhound.tokenizers.whitespace,' - 'local: choices_ipv4[ $( "#{type_id}" ).val() ],' + 'local: choices_ipv4[ $( "#{machine_type_id}" ).val() ],' 'identify: function( obj ) {{ return obj.key; }}' '}} )' ).format( - type_id=f_type_id(is_type_tt) + machine_type_id=f_type_id(is_type_tt) ) @@ -198,7 +198,7 @@ def generate_ipv4_match_func(is_type_tt): return ( 'function(q, sync) {{' 'if (q === "") {{' - 'var first = choices_ipv4[$("#{type_id}").val()].slice(0, 5);' + 'var first = choices_ipv4[$("#{machine_type_id}").val()].slice(0, 5);' 'first = first.map( function (obj) {{ return obj.key; }} );' 'sync(engine_ipv4.get(first));' '}} else {{' @@ -206,7 +206,7 @@ def generate_ipv4_match_func(is_type_tt): '}}' '}}' ).format( - type_id=f_type_id(is_type_tt) + machine_type_id=f_type_id(is_type_tt) ) @@ -1388,7 +1388,7 @@ def index(request): .prefetch_related('interface_set__domain__extension') .prefetch_related('interface_set__ipv4__ip_type') .prefetch_related( - 'interface_set__type__ip_type__extension' + 'interface_set__machine_type__ip_type__extension' ).prefetch_related( 'interface_set__domain__related_domain__extension' ).prefetch_related('interface_set__ipv6list')) @@ -1417,7 +1417,7 @@ def index_iptype(request): iptype_list = (IpType.objects .select_related('extension') .select_related('vlan') - .order_by('type')) + .order_by('name')) return render( request, 'machines/index_iptype.html', @@ -1443,7 +1443,7 @@ def index_machinetype(request): """ View displaying the list of existing types of machines """ machinetype_list = (MachineType.objects .select_related('ip_type') - .order_by('type')) + .order_by('name')) return render( request, 'machines/index_machinetype.html', diff --git a/re2o/utils.py b/re2o/utils.py index 20218a81..ca8bce43 100644 --- a/re2o/utils.py +++ b/re2o/utils.py @@ -126,7 +126,7 @@ def filter_active_interfaces(interface_set): ).filter(active=True) ).select_related('domain') .select_related('machine') - .select_related('type') + .select_related('machine_type') .select_related('ipv4') .select_related('domain__extension') .select_related('ipv4__ip_type') diff --git a/topologie/models.py b/topologie/models.py index 82a9c6a8..61448a79 100644 --- a/topologie/models.py +++ b/topologie/models.py @@ -300,7 +300,7 @@ class Switch(AclMixin, Machine): It must the the management interface for that device""" switch_iptype = OptionalTopologie.get_cached_value('switchs_ip_type') if switch_iptype: - return self.interface_set.filter(type__ip_type=switch_iptype).first() + return self.interface_set.filter(machine_type__ip_type=switch_iptype).first() return self.interface_set.first() @cached_property diff --git a/users/views.py b/users/views.py index ea22359a..eac93790 100644 --- a/users/views.py +++ b/users/views.py @@ -965,7 +965,7 @@ def profil(request, users, **_kwargs): machines = Machine.objects.filter(user=users).select_related('user')\ .prefetch_related('interface_set__domain__extension')\ .prefetch_related('interface_set__ipv4__ip_type__extension')\ - .prefetch_related('interface_set__type')\ + .prefetch_related('interface_set__machine_type')\ .prefetch_related('interface_set__domain__related_domain__extension') machines = SortTable.sort( machines,