mirror of
https://github.com/netbox-community/netbox.git
synced 2025-08-08 00:28:16 -06:00
Merge branch 'develop' into develop
This commit is contained in:
commit
a62d4645ac
@ -7,7 +7,7 @@ from django.db.models import Q
|
||||
from dcim.models import Site
|
||||
from extras.filters import CustomFieldFilterSet
|
||||
from tenancy.models import Tenant
|
||||
from utilities.filters import NullableModelMultipleChoiceFilter, NumericInFilter
|
||||
from utilities.filters import NumericInFilter
|
||||
from .models import Provider, Circuit, CircuitTermination, CircuitType
|
||||
|
||||
|
||||
@ -78,12 +78,12 @@ class CircuitFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
||||
to_field_name='slug',
|
||||
label='Circuit type (slug)',
|
||||
)
|
||||
tenant_id = NullableModelMultipleChoiceFilter(
|
||||
tenant_id = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=Tenant.objects.all(),
|
||||
label='Tenant (ID)',
|
||||
)
|
||||
tenant = NullableModelMultipleChoiceFilter(
|
||||
name='tenant',
|
||||
tenant = django_filters.ModelMultipleChoiceFilter(
|
||||
name='tenant__slug',
|
||||
queryset=Tenant.objects.all(),
|
||||
to_field_name='slug',
|
||||
label='Tenant (slug)',
|
||||
|
@ -221,7 +221,7 @@ class WritableRackReservationSerializer(ValidatedModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = RackReservation
|
||||
fields = ['id', 'rack', 'units', 'description']
|
||||
fields = ['id', 'rack', 'units', 'user', 'description']
|
||||
|
||||
|
||||
#
|
||||
|
@ -9,7 +9,7 @@ from django.db.models import Q
|
||||
|
||||
from extras.filters import CustomFieldFilterSet
|
||||
from tenancy.models import Tenant
|
||||
from utilities.filters import NullableCharFieldFilter, NullableModelMultipleChoiceFilter, NumericInFilter
|
||||
from utilities.filters import NullableCharFieldFilter, NumericInFilter
|
||||
from virtualization.models import Cluster
|
||||
from .models import (
|
||||
ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceBay,
|
||||
@ -21,11 +21,12 @@ from .models import (
|
||||
|
||||
|
||||
class RegionFilter(django_filters.FilterSet):
|
||||
parent_id = NullableModelMultipleChoiceFilter(
|
||||
parent_id = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=Region.objects.all(),
|
||||
label='Parent region (ID)',
|
||||
)
|
||||
parent = NullableModelMultipleChoiceFilter(
|
||||
parent = django_filters.ModelMultipleChoiceFilter(
|
||||
name='parent__slug',
|
||||
queryset=Region.objects.all(),
|
||||
to_field_name='slug',
|
||||
label='Parent region (slug)',
|
||||
@ -42,20 +43,22 @@ class SiteFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
||||
method='search',
|
||||
label='Search',
|
||||
)
|
||||
region_id = NullableModelMultipleChoiceFilter(
|
||||
region_id = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=Region.objects.all(),
|
||||
label='Region (ID)',
|
||||
)
|
||||
region = NullableModelMultipleChoiceFilter(
|
||||
region = django_filters.ModelMultipleChoiceFilter(
|
||||
name='region__slug',
|
||||
queryset=Region.objects.all(),
|
||||
to_field_name='slug',
|
||||
label='Region (slug)',
|
||||
)
|
||||
tenant_id = NullableModelMultipleChoiceFilter(
|
||||
tenant_id = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=Tenant.objects.all(),
|
||||
label='Tenant (ID)',
|
||||
)
|
||||
tenant = NullableModelMultipleChoiceFilter(
|
||||
tenant = django_filters.ModelMultipleChoiceFilter(
|
||||
name='tenant__slug',
|
||||
queryset=Tenant.objects.all(),
|
||||
to_field_name='slug',
|
||||
label='Tenant (slug)',
|
||||
@ -126,32 +129,32 @@ class RackFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
||||
to_field_name='slug',
|
||||
label='Site (slug)',
|
||||
)
|
||||
group_id = NullableModelMultipleChoiceFilter(
|
||||
group_id = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=RackGroup.objects.all(),
|
||||
label='Group (ID)',
|
||||
)
|
||||
group = NullableModelMultipleChoiceFilter(
|
||||
name='group',
|
||||
group = django_filters.ModelMultipleChoiceFilter(
|
||||
name='group__slug',
|
||||
queryset=RackGroup.objects.all(),
|
||||
to_field_name='slug',
|
||||
label='Group',
|
||||
)
|
||||
tenant_id = NullableModelMultipleChoiceFilter(
|
||||
tenant_id = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=Tenant.objects.all(),
|
||||
label='Tenant (ID)',
|
||||
)
|
||||
tenant = NullableModelMultipleChoiceFilter(
|
||||
name='tenant',
|
||||
tenant = django_filters.ModelMultipleChoiceFilter(
|
||||
name='tenant__slug',
|
||||
queryset=Tenant.objects.all(),
|
||||
to_field_name='slug',
|
||||
label='Tenant (slug)',
|
||||
)
|
||||
role_id = NullableModelMultipleChoiceFilter(
|
||||
role_id = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=RackRole.objects.all(),
|
||||
label='Role (ID)',
|
||||
)
|
||||
role = NullableModelMultipleChoiceFilter(
|
||||
name='role',
|
||||
role = django_filters.ModelMultipleChoiceFilter(
|
||||
name='role__slug',
|
||||
queryset=RackRole.objects.all(),
|
||||
to_field_name='slug',
|
||||
label='Role (slug)',
|
||||
@ -193,13 +196,13 @@ class RackReservationFilter(django_filters.FilterSet):
|
||||
to_field_name='slug',
|
||||
label='Site (slug)',
|
||||
)
|
||||
group_id = NullableModelMultipleChoiceFilter(
|
||||
group_id = django_filters.ModelMultipleChoiceFilter(
|
||||
name='rack__group',
|
||||
queryset=RackGroup.objects.all(),
|
||||
label='Group (ID)',
|
||||
)
|
||||
group = NullableModelMultipleChoiceFilter(
|
||||
name='rack__group',
|
||||
group = django_filters.ModelMultipleChoiceFilter(
|
||||
name='rack__group__slug',
|
||||
queryset=RackGroup.objects.all(),
|
||||
to_field_name='slug',
|
||||
label='Group',
|
||||
@ -378,22 +381,22 @@ class DeviceFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
||||
to_field_name='slug',
|
||||
label='Role (slug)',
|
||||
)
|
||||
tenant_id = NullableModelMultipleChoiceFilter(
|
||||
tenant_id = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=Tenant.objects.all(),
|
||||
label='Tenant (ID)',
|
||||
)
|
||||
tenant = NullableModelMultipleChoiceFilter(
|
||||
name='tenant',
|
||||
tenant = django_filters.ModelMultipleChoiceFilter(
|
||||
name='tenant__slug',
|
||||
queryset=Tenant.objects.all(),
|
||||
to_field_name='slug',
|
||||
label='Tenant (slug)',
|
||||
)
|
||||
platform_id = NullableModelMultipleChoiceFilter(
|
||||
platform_id = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=Platform.objects.all(),
|
||||
label='Platform (ID)',
|
||||
)
|
||||
platform = NullableModelMultipleChoiceFilter(
|
||||
name='platform',
|
||||
platform = django_filters.ModelMultipleChoiceFilter(
|
||||
name='platform__slug',
|
||||
queryset=Platform.objects.all(),
|
||||
to_field_name='slug',
|
||||
label='Platform (slug)',
|
||||
@ -415,12 +418,12 @@ class DeviceFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
||||
queryset=RackGroup.objects.all(),
|
||||
label='Rack group (ID)',
|
||||
)
|
||||
rack_id = NullableModelMultipleChoiceFilter(
|
||||
rack_id = django_filters.ModelMultipleChoiceFilter(
|
||||
name='rack',
|
||||
queryset=Rack.objects.all(),
|
||||
label='Rack (ID)',
|
||||
)
|
||||
cluster_id = NullableModelMultipleChoiceFilter(
|
||||
cluster_id = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=Cluster.objects.all(),
|
||||
label='VM cluster (ID)',
|
||||
)
|
||||
@ -605,7 +608,7 @@ class DeviceBayFilter(DeviceComponentFilterSet):
|
||||
|
||||
|
||||
class InventoryItemFilter(DeviceComponentFilterSet):
|
||||
parent_id = NullableModelMultipleChoiceFilter(
|
||||
parent_id = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=InventoryItem.objects.all(),
|
||||
label='Parent inventory item (ID)',
|
||||
)
|
||||
|
@ -4,6 +4,7 @@ from mptt.forms import TreeNodeChoiceField
|
||||
import re
|
||||
|
||||
from django import forms
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib.postgres.forms.array import SimpleArrayField
|
||||
from django.db.models import Count, Q
|
||||
|
||||
@ -376,6 +377,7 @@ class RackFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||
|
||||
class RackReservationForm(BootstrapMixin, TenancyForm, forms.ModelForm):
|
||||
units = SimpleArrayField(forms.IntegerField(), widget=ArrayFieldSelectMultiple(attrs={'size': 10}))
|
||||
user = forms.ModelChoiceField(queryset=User.objects.order_by('username'))
|
||||
|
||||
class Meta:
|
||||
model = RackReservation
|
||||
@ -416,6 +418,15 @@ class RackReservationFilterForm(BootstrapMixin, forms.Form):
|
||||
)
|
||||
|
||||
|
||||
class RackReservationBulkEditForm(BootstrapMixin, BulkEditForm):
|
||||
pk = forms.ModelMultipleChoiceField(queryset=RackReservation.objects.all(), widget=forms.MultipleHiddenInput)
|
||||
user = forms.ModelChoiceField(queryset=User.objects.order_by('username'), required=False)
|
||||
description = forms.CharField(max_length=100, required=False)
|
||||
|
||||
class Meta:
|
||||
nullable_fields = []
|
||||
|
||||
|
||||
#
|
||||
# Manufacturers
|
||||
#
|
||||
|
22
netbox/dcim/migrations/0049_rackreservation_change_user.py
Normal file
22
netbox/dcim/migrations/0049_rackreservation_change_user.py
Normal file
@ -0,0 +1,22 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.6 on 2017-10-31 17:32
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0048_rack_serial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='rackreservation',
|
||||
name='user',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
]
|
@ -296,6 +296,7 @@ class Rack(CreatedUpdatedModel, CustomFieldModel):
|
||||
self.tenant.name if self.tenant else None,
|
||||
self.role.name if self.role else None,
|
||||
self.get_type_display() if self.type else None,
|
||||
self.serial,
|
||||
self.width,
|
||||
self.u_height,
|
||||
self.desc_units,
|
||||
@ -418,7 +419,7 @@ class RackReservation(models.Model):
|
||||
units = ArrayField(models.PositiveSmallIntegerField())
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
tenant = models.ForeignKey(Tenant, blank=True, null=True, related_name='rackreservations', on_delete=models.PROTECT)
|
||||
user = models.ForeignKey(User, editable=False, on_delete=models.PROTECT)
|
||||
user = models.ForeignKey(User, on_delete=models.PROTECT)
|
||||
description = models.CharField(max_length=100)
|
||||
|
||||
class Meta:
|
||||
|
@ -45,6 +45,7 @@ urlpatterns = [
|
||||
|
||||
# Rack reservations
|
||||
url(r'^rack-reservations/$', views.RackReservationListView.as_view(), name='rackreservation_list'),
|
||||
url(r'^rack-reservations/edit/$', views.RackReservationBulkEditView.as_view(), name='rackreservation_bulk_edit'),
|
||||
url(r'^rack-reservations/delete/$', views.RackReservationBulkDeleteView.as_view(), name='rackreservation_bulk_delete'),
|
||||
url(r'^rack-reservations/(?P<pk>\d+)/edit/$', views.RackReservationEditView.as_view(), name='rackreservation_edit'),
|
||||
url(r'^rack-reservations/(?P<pk>\d+)/delete/$', views.RackReservationDeleteView.as_view(), name='rackreservation_delete'),
|
||||
|
@ -426,6 +426,16 @@ class RackReservationDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
||||
return obj.rack.get_absolute_url()
|
||||
|
||||
|
||||
class RackReservationBulkEditView(PermissionRequiredMixin, BulkEditView):
|
||||
permission_required = 'dcim.change_rackreservation'
|
||||
cls = RackReservation
|
||||
queryset = RackReservation.objects.select_related('rack', 'user')
|
||||
filter = filters.RackReservationFilter
|
||||
table = tables.RackReservationTable
|
||||
form = forms.RackReservationBulkEditForm
|
||||
default_return_url = 'dcim:rackreservation_list'
|
||||
|
||||
|
||||
class RackReservationBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
||||
permission_required = 'dcim.delete_rackreservation'
|
||||
cls = RackReservation
|
||||
|
@ -9,7 +9,7 @@ from django.db.models import Q
|
||||
from dcim.models import Site, Device, Interface
|
||||
from extras.filters import CustomFieldFilterSet
|
||||
from tenancy.models import Tenant
|
||||
from utilities.filters import NullableModelMultipleChoiceFilter, NumericInFilter
|
||||
from utilities.filters import NumericInFilter
|
||||
from virtualization.models import VirtualMachine
|
||||
from .models import (
|
||||
Aggregate, IPAddress, IPADDRESS_ROLE_CHOICES, IPADDRESS_STATUS_CHOICES, Prefix, PREFIX_STATUS_CHOICES, RIR, Role,
|
||||
@ -23,12 +23,12 @@ class VRFFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
||||
method='search',
|
||||
label='Search',
|
||||
)
|
||||
tenant_id = NullableModelMultipleChoiceFilter(
|
||||
tenant_id = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=Tenant.objects.all(),
|
||||
label='Tenant (ID)',
|
||||
)
|
||||
tenant = NullableModelMultipleChoiceFilter(
|
||||
name='tenant',
|
||||
tenant = django_filters.ModelMultipleChoiceFilter(
|
||||
name='tenant__slug',
|
||||
queryset=Tenant.objects.all(),
|
||||
to_field_name='slug',
|
||||
label='Tenant (slug)',
|
||||
@ -110,37 +110,37 @@ class PrefixFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
||||
method='filter_mask_length',
|
||||
label='Mask length',
|
||||
)
|
||||
vrf_id = NullableModelMultipleChoiceFilter(
|
||||
vrf_id = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=VRF.objects.all(),
|
||||
label='VRF',
|
||||
)
|
||||
vrf = NullableModelMultipleChoiceFilter(
|
||||
name='vrf',
|
||||
vrf = django_filters.ModelMultipleChoiceFilter(
|
||||
name='vrf__rd',
|
||||
queryset=VRF.objects.all(),
|
||||
to_field_name='rd',
|
||||
label='VRF (RD)',
|
||||
)
|
||||
tenant_id = NullableModelMultipleChoiceFilter(
|
||||
tenant_id = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=Tenant.objects.all(),
|
||||
label='Tenant (ID)',
|
||||
)
|
||||
tenant = NullableModelMultipleChoiceFilter(
|
||||
name='tenant',
|
||||
tenant = django_filters.ModelMultipleChoiceFilter(
|
||||
name='tenant__slug',
|
||||
queryset=Tenant.objects.all(),
|
||||
to_field_name='slug',
|
||||
label='Tenant (slug)',
|
||||
)
|
||||
site_id = NullableModelMultipleChoiceFilter(
|
||||
site_id = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=Site.objects.all(),
|
||||
label='Site (ID)',
|
||||
)
|
||||
site = NullableModelMultipleChoiceFilter(
|
||||
name='site',
|
||||
site = django_filters.ModelMultipleChoiceFilter(
|
||||
name='site__slug',
|
||||
queryset=Site.objects.all(),
|
||||
to_field_name='slug',
|
||||
label='Site (slug)',
|
||||
)
|
||||
vlan_id = NullableModelMultipleChoiceFilter(
|
||||
vlan_id = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=VLAN.objects.all(),
|
||||
label='VLAN (ID)',
|
||||
)
|
||||
@ -148,12 +148,12 @@ class PrefixFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
||||
name='vlan__vid',
|
||||
label='VLAN number (1-4095)',
|
||||
)
|
||||
role_id = NullableModelMultipleChoiceFilter(
|
||||
role_id = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=Role.objects.all(),
|
||||
label='Role (ID)',
|
||||
)
|
||||
role = NullableModelMultipleChoiceFilter(
|
||||
name='role',
|
||||
role = django_filters.ModelMultipleChoiceFilter(
|
||||
name='role__slug',
|
||||
queryset=Role.objects.all(),
|
||||
to_field_name='slug',
|
||||
label='Role (slug)',
|
||||
@ -207,22 +207,22 @@ class IPAddressFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
||||
method='filter_mask_length',
|
||||
label='Mask length',
|
||||
)
|
||||
vrf_id = NullableModelMultipleChoiceFilter(
|
||||
vrf_id = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=VRF.objects.all(),
|
||||
label='VRF',
|
||||
)
|
||||
vrf = NullableModelMultipleChoiceFilter(
|
||||
name='vrf',
|
||||
vrf = django_filters.ModelMultipleChoiceFilter(
|
||||
name='vrf__rd',
|
||||
queryset=VRF.objects.all(),
|
||||
to_field_name='rd',
|
||||
label='VRF (RD)',
|
||||
)
|
||||
tenant_id = NullableModelMultipleChoiceFilter(
|
||||
tenant_id = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=Tenant.objects.all(),
|
||||
label='Tenant (ID)',
|
||||
)
|
||||
tenant = NullableModelMultipleChoiceFilter(
|
||||
name='tenant',
|
||||
tenant = django_filters.ModelMultipleChoiceFilter(
|
||||
name='tenant__slug',
|
||||
queryset=Tenant.objects.all(),
|
||||
to_field_name='slug',
|
||||
label='Tenant (slug)',
|
||||
@ -290,12 +290,12 @@ class IPAddressFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
||||
|
||||
|
||||
class VLANGroupFilter(django_filters.FilterSet):
|
||||
site_id = NullableModelMultipleChoiceFilter(
|
||||
site_id = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=Site.objects.all(),
|
||||
label='Site (ID)',
|
||||
)
|
||||
site = NullableModelMultipleChoiceFilter(
|
||||
name='site',
|
||||
site = django_filters.ModelMultipleChoiceFilter(
|
||||
name='site__slug',
|
||||
queryset=Site.objects.all(),
|
||||
to_field_name='slug',
|
||||
label='Site (slug)',
|
||||
@ -312,42 +312,42 @@ class VLANFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
||||
method='search',
|
||||
label='Search',
|
||||
)
|
||||
site_id = NullableModelMultipleChoiceFilter(
|
||||
site_id = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=Site.objects.all(),
|
||||
label='Site (ID)',
|
||||
)
|
||||
site = NullableModelMultipleChoiceFilter(
|
||||
name='site',
|
||||
site = django_filters.ModelMultipleChoiceFilter(
|
||||
name='site__slug',
|
||||
queryset=Site.objects.all(),
|
||||
to_field_name='slug',
|
||||
label='Site (slug)',
|
||||
)
|
||||
group_id = NullableModelMultipleChoiceFilter(
|
||||
group_id = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=VLANGroup.objects.all(),
|
||||
label='Group (ID)',
|
||||
)
|
||||
group = NullableModelMultipleChoiceFilter(
|
||||
name='group',
|
||||
group = django_filters.ModelMultipleChoiceFilter(
|
||||
name='group__slug',
|
||||
queryset=VLANGroup.objects.all(),
|
||||
to_field_name='slug',
|
||||
label='Group',
|
||||
)
|
||||
tenant_id = NullableModelMultipleChoiceFilter(
|
||||
tenant_id = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=Tenant.objects.all(),
|
||||
label='Tenant (ID)',
|
||||
)
|
||||
tenant = NullableModelMultipleChoiceFilter(
|
||||
name='tenant',
|
||||
tenant = django_filters.ModelMultipleChoiceFilter(
|
||||
name='tenant__slug',
|
||||
queryset=Tenant.objects.all(),
|
||||
to_field_name='slug',
|
||||
label='Tenant (slug)',
|
||||
)
|
||||
role_id = NullableModelMultipleChoiceFilter(
|
||||
role_id = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=Role.objects.all(),
|
||||
label='Role (ID)',
|
||||
)
|
||||
role = NullableModelMultipleChoiceFilter(
|
||||
name='role',
|
||||
role = django_filters.ModelMultipleChoiceFilter(
|
||||
name='role__slug',
|
||||
queryset=Role.objects.all(),
|
||||
to_field_name='slug',
|
||||
label='Role (slug)',
|
||||
|
@ -13,7 +13,7 @@ except ImportError:
|
||||
)
|
||||
|
||||
|
||||
VERSION = '2.2.3-dev'
|
||||
VERSION = '2.2.5-dev'
|
||||
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
@ -206,6 +206,10 @@ LOGIN_URL = '/{}login/'.format(BASE_PATH)
|
||||
# Secrets
|
||||
SECRETS_MIN_PUBKEY_SIZE = 2048
|
||||
|
||||
# Django filters
|
||||
FILTERS_NULL_CHOICE_LABEL = 'None'
|
||||
FILTERS_NULL_CHOICE_VALUE = '0' # Must be a string
|
||||
|
||||
# Django REST framework (API)
|
||||
REST_FRAMEWORK_VERSION = VERSION[0:3] # Use major.minor as API version
|
||||
REST_FRAMEWORK = {
|
||||
|
@ -120,7 +120,7 @@
|
||||
</td>
|
||||
<td>
|
||||
<strong>Network Device</strong><br />
|
||||
<small class="text-muted">This device {% if devicetype.is_network_device %}has{% else %}does not have{% endif %} non-management network interfaces</small>
|
||||
<small class="text-muted">This device {% if devicetype.is_network_device %}has{% else %}does not have{% endif %} network interfaces</small>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -5,7 +5,7 @@
|
||||
<h1>{% block title %}Rack Reservations{% endblock %}</h1>
|
||||
<div class="row">
|
||||
<div class="col-md-9">
|
||||
{% include 'utilities/obj_table.html' with bulk_delete_url='dcim:rackreservation_bulk_delete' %}
|
||||
{% include 'utilities/obj_table.html' with bulk_edit_url='dcim:rackreservation_bulk_edit' bulk_delete_url='dcim:rackreservation_bulk_delete' %}
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
{% include 'inc/search_panel.html' %}
|
||||
|
@ -5,7 +5,7 @@ import django_filters
|
||||
from django.db.models import Q
|
||||
|
||||
from extras.filters import CustomFieldFilterSet
|
||||
from utilities.filters import NullableModelMultipleChoiceFilter, NumericInFilter
|
||||
from utilities.filters import NumericInFilter
|
||||
from .models import Tenant, TenantGroup
|
||||
|
||||
|
||||
@ -22,12 +22,12 @@ class TenantFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
||||
method='search',
|
||||
label='Search',
|
||||
)
|
||||
group_id = NullableModelMultipleChoiceFilter(
|
||||
group_id = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=TenantGroup.objects.all(),
|
||||
label='Group (ID)',
|
||||
)
|
||||
group = NullableModelMultipleChoiceFilter(
|
||||
name='group',
|
||||
group = django_filters.ModelMultipleChoiceFilter(
|
||||
name='group__slug',
|
||||
queryset=TenantGroup.objects.all(),
|
||||
to_field_name='slug',
|
||||
label='Group (slug)',
|
||||
|
@ -4,7 +4,6 @@ import django_filters
|
||||
import itertools
|
||||
|
||||
from django import forms
|
||||
from django.db.models import Q
|
||||
from django.utils.encoding import force_text
|
||||
|
||||
|
||||
@ -66,51 +65,3 @@ class NullableModelMultipleChoiceField(forms.ModelMultipleChoiceField):
|
||||
stripped_value = value
|
||||
super(NullableModelMultipleChoiceField, self).clean(stripped_value)
|
||||
return value
|
||||
|
||||
|
||||
class NullableModelMultipleChoiceFilter(django_filters.ModelMultipleChoiceFilter):
|
||||
"""
|
||||
This class extends ModelMultipleChoiceFilter to accept an additional value which implies "is null". The default
|
||||
queryset filter argument is:
|
||||
|
||||
.filter(fieldname=value)
|
||||
|
||||
When filtering by the value representing "is null" ('0' by default) the argument is modified to:
|
||||
|
||||
.filter(fieldname__isnull=True)
|
||||
"""
|
||||
field_class = NullableModelMultipleChoiceField
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.null_value = kwargs.get('null_value', 0)
|
||||
super(NullableModelMultipleChoiceFilter, self).__init__(*args, **kwargs)
|
||||
|
||||
def filter(self, qs, value):
|
||||
value = value or () # Make sure we have an iterable
|
||||
|
||||
if self.is_noop(qs, value):
|
||||
return qs
|
||||
|
||||
# Even though not a noop, no point filtering if empty
|
||||
if not value:
|
||||
return qs
|
||||
|
||||
q = Q()
|
||||
for v in set(value):
|
||||
# Filtering by "is null"
|
||||
if v == force_text(self.null_value):
|
||||
arg = {'{}__isnull'.format(self.name): True}
|
||||
# Filtering by a related field (e.g. slug)
|
||||
elif self.field.to_field_name is not None:
|
||||
arg = {'{}__{}'.format(self.name, self.field.to_field_name): v}
|
||||
# Filtering by primary key (default)
|
||||
else:
|
||||
arg = {self.name: v}
|
||||
if self.conjoined:
|
||||
qs = self.get_method(qs)(**arg)
|
||||
else:
|
||||
q |= Q(**arg)
|
||||
if self.distinct:
|
||||
return self.get_method(qs)(q).distinct()
|
||||
|
||||
return self.get_method(qs)(q)
|
||||
|
@ -9,7 +9,7 @@ from django.db.models import Q
|
||||
from dcim.models import DeviceRole, Interface, Platform, Site
|
||||
from extras.filters import CustomFieldFilterSet
|
||||
from tenancy.models import Tenant
|
||||
from utilities.filters import NullableModelMultipleChoiceFilter, NumericInFilter
|
||||
from utilities.filters import NumericInFilter
|
||||
from .constants import STATUS_CHOICES
|
||||
from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine
|
||||
|
||||
@ -20,11 +20,12 @@ class ClusterFilter(CustomFieldFilterSet):
|
||||
method='search',
|
||||
label='Search',
|
||||
)
|
||||
group_id = NullableModelMultipleChoiceFilter(
|
||||
group_id = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=ClusterGroup.objects.all(),
|
||||
label='Parent group (ID)',
|
||||
)
|
||||
group = NullableModelMultipleChoiceFilter(
|
||||
group = django_filters.ModelMultipleChoiceFilter(
|
||||
name='group__slug',
|
||||
queryset=ClusterGroup.objects.all(),
|
||||
to_field_name='slug',
|
||||
label='Parent group (slug)',
|
||||
@ -72,13 +73,13 @@ class VirtualMachineFilter(CustomFieldFilterSet):
|
||||
status = django_filters.MultipleChoiceFilter(
|
||||
choices=STATUS_CHOICES
|
||||
)
|
||||
cluster_group_id = NullableModelMultipleChoiceFilter(
|
||||
cluster_group_id = django_filters.ModelMultipleChoiceFilter(
|
||||
name='cluster__group',
|
||||
queryset=ClusterGroup.objects.all(),
|
||||
label='Cluster group (ID)',
|
||||
)
|
||||
cluster_group = NullableModelMultipleChoiceFilter(
|
||||
name='cluster__group',
|
||||
cluster_group = django_filters.ModelMultipleChoiceFilter(
|
||||
name='cluster__group__slug',
|
||||
queryset=ClusterGroup.objects.all(),
|
||||
to_field_name='slug',
|
||||
label='Cluster group (slug)',
|
||||
@ -87,29 +88,32 @@ class VirtualMachineFilter(CustomFieldFilterSet):
|
||||
queryset=Cluster.objects.all(),
|
||||
label='Cluster (ID)',
|
||||
)
|
||||
role_id = NullableModelMultipleChoiceFilter(
|
||||
role_id = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=DeviceRole.objects.all(),
|
||||
label='Role (ID)',
|
||||
)
|
||||
role = NullableModelMultipleChoiceFilter(
|
||||
role = django_filters.ModelMultipleChoiceFilter(
|
||||
name='role__slug',
|
||||
queryset=DeviceRole.objects.all(),
|
||||
to_field_name='slug',
|
||||
label='Role (slug)',
|
||||
)
|
||||
tenant_id = NullableModelMultipleChoiceFilter(
|
||||
tenant_id = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=Tenant.objects.all(),
|
||||
label='Tenant (ID)',
|
||||
)
|
||||
tenant = NullableModelMultipleChoiceFilter(
|
||||
tenant = django_filters.ModelMultipleChoiceFilter(
|
||||
name='tenant__slug',
|
||||
queryset=Tenant.objects.all(),
|
||||
to_field_name='slug',
|
||||
label='Tenant (slug)',
|
||||
)
|
||||
platform_id = NullableModelMultipleChoiceFilter(
|
||||
platform_id = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=Platform.objects.all(),
|
||||
label='Platform (ID)',
|
||||
)
|
||||
platform = NullableModelMultipleChoiceFilter(
|
||||
platform = django_filters.ModelMultipleChoiceFilter(
|
||||
name='platform__slug',
|
||||
queryset=Platform.objects.all(),
|
||||
to_field_name='slug',
|
||||
label='Platform (slug)',
|
||||
|
@ -1,7 +1,7 @@
|
||||
Django>=1.11,<2.0
|
||||
django-cors-headers>=2.1
|
||||
django-debug-toolbar>=1.8
|
||||
django-filter>=1.0.4
|
||||
django-filter>=1.1.0
|
||||
django-mptt==0.8.7
|
||||
django-rest-swagger>=2.1.0
|
||||
django-tables2>=1.10.0
|
||||
|
Loading…
Reference in New Issue
Block a user