mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
* fixed prefix header to represent new serial "vlan_vid" * shows option in creation now * fixed visibility on rack page * cleanup * Added view to Tenant page * Moved migration for update from #1666 and fixed tenant enumeration in FilterForm * Fixed conflict #1 * Fixed filters from merge and made migration merge * added tenant to api * Fixed migrations problem * Added Tenant to bulkedit option
This commit is contained in:
committed by
Jeremy Stretch
parent
db0ef95fe3
commit
fbd39da8ca
@ -218,7 +218,7 @@ class RackReservationSerializer(serializers.ModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = RackReservation
|
||||
fields = ['id', 'rack', 'units', 'created', 'user', 'description']
|
||||
fields = ['id', 'rack', 'units', 'created', 'user', 'tenant', 'description']
|
||||
|
||||
|
||||
class WritableRackReservationSerializer(ValidatedModelSerializer):
|
||||
|
@ -208,6 +208,16 @@ class RackReservationFilter(django_filters.FilterSet):
|
||||
to_field_name='slug',
|
||||
label='Group',
|
||||
)
|
||||
tenant_id = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=Tenant.objects.all(),
|
||||
label='Tenant (ID)',
|
||||
)
|
||||
tenant = django_filters.ModelMultipleChoiceFilter(
|
||||
name='tenant__slug',
|
||||
queryset=Tenant.objects.all(),
|
||||
to_field_name='slug',
|
||||
label='Tenant (slug)',
|
||||
)
|
||||
user_id = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=User.objects.all(),
|
||||
label='User (ID)',
|
||||
|
@ -379,13 +379,13 @@ class RackFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||
# Rack reservations
|
||||
#
|
||||
|
||||
class RackReservationForm(BootstrapMixin, forms.ModelForm):
|
||||
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
|
||||
fields = ['units', 'user', 'description']
|
||||
fields = ['units', 'user', 'tenant_group', 'tenant', 'description']
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
@ -415,11 +415,17 @@ class RackReservationFilterForm(BootstrapMixin, forms.Form):
|
||||
label='Rack group',
|
||||
null_option=(0, 'None')
|
||||
)
|
||||
tenant = FilterChoiceField(
|
||||
queryset=Tenant.objects.annotate(filter_count=Count('rackreservations')),
|
||||
to_field_name='slug',
|
||||
null_option=(0, 'None')
|
||||
)
|
||||
|
||||
|
||||
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)
|
||||
tenant = forms.ModelChoiceField(queryset=Tenant.objects.all(), required=False)
|
||||
description = forms.CharField(max_length=100, required=False)
|
||||
|
||||
class Meta:
|
||||
@ -805,10 +811,10 @@ class DeviceForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
||||
pk = self.instance.pk if self.instance.pk else None
|
||||
try:
|
||||
if self.is_bound and self.data.get('rack') and str(self.data.get('face')):
|
||||
position_choices = Rack.objects.get(pk=self.data['rack'])\
|
||||
position_choices = Rack.objects.get(pk=self.data['rack']) \
|
||||
.get_rack_units(face=self.data.get('face'), exclude=pk)
|
||||
elif self.initial.get('rack') and str(self.initial.get('face')):
|
||||
position_choices = Rack.objects.get(pk=self.initial['rack'])\
|
||||
position_choices = Rack.objects.get(pk=self.initial['rack']) \
|
||||
.get_rack_units(face=self.initial.get('face'), exclude=pk)
|
||||
else:
|
||||
position_choices = []
|
||||
|
22
netbox/dcim/migrations/0050_rackreservation_tenant.py
Normal file
22
netbox/dcim/migrations/0050_rackreservation_tenant.py
Normal file
@ -0,0 +1,22 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.6 on 2017-10-30 20:43
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('tenancy', '0003_unicode_literals'),
|
||||
('dcim', '0049_rackreservation_change_user'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='rackreservation',
|
||||
name='tenant',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='rackreservations', to='tenancy.Tenant'),
|
||||
),
|
||||
]
|
@ -417,6 +417,7 @@ class RackReservation(models.Model):
|
||||
rack = models.ForeignKey('Rack', related_name='reservations', on_delete=models.CASCADE)
|
||||
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, on_delete=models.PROTECT)
|
||||
description = models.CharField(max_length=100)
|
||||
|
||||
|
@ -244,6 +244,7 @@ class RackImportTable(BaseTable):
|
||||
|
||||
class RackReservationTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
tenant = tables.LinkColumn('tenancy:tenant', args=[Accessor('tenant.slug')])
|
||||
rack = tables.LinkColumn('dcim:rack', args=[Accessor('rack.pk')])
|
||||
unit_list = tables.Column(orderable=False, verbose_name='Units')
|
||||
actions = tables.TemplateColumn(
|
||||
@ -252,7 +253,7 @@ class RackReservationTable(BaseTable):
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = RackReservation
|
||||
fields = ('pk', 'rack', 'unit_list', 'user', 'created', 'description', 'actions')
|
||||
fields = ('pk', 'rack', 'unit_list', 'user', 'created', 'tenant', 'description', 'actions')
|
||||
|
||||
|
||||
#
|
||||
|
@ -326,7 +326,7 @@ class RackView(View):
|
||||
|
||||
rack = get_object_or_404(Rack.objects.select_related('site__region', 'tenant__group', 'group', 'role'), pk=pk)
|
||||
|
||||
nonracked_devices = Device.objects.filter(rack=rack, position__isnull=True, parent_bay__isnull=True)\
|
||||
nonracked_devices = Device.objects.filter(rack=rack, position__isnull=True, parent_bay__isnull=True) \
|
||||
.select_related('device_type__manufacturer')
|
||||
next_rack = Rack.objects.filter(site=rack.site, name__gt=rack.name).order_by('name').first()
|
||||
prev_rack = Rack.objects.filter(site=rack.site, name__lt=rack.name).order_by('-name').first()
|
||||
@ -1783,7 +1783,7 @@ class InterfaceConnectionsBulkImportView(PermissionRequiredMixin, BulkImportView
|
||||
#
|
||||
|
||||
class ConsoleConnectionsListView(ObjectListView):
|
||||
queryset = ConsolePort.objects.select_related('device', 'cs_port__device').filter(cs_port__isnull=False)\
|
||||
queryset = ConsolePort.objects.select_related('device', 'cs_port__device').filter(cs_port__isnull=False) \
|
||||
.order_by('cs_port__device__name', 'cs_port__name')
|
||||
filter = filters.ConsoleConnectionFilter
|
||||
filter_form = forms.ConsoleConnectionFilterForm
|
||||
@ -1792,7 +1792,7 @@ class ConsoleConnectionsListView(ObjectListView):
|
||||
|
||||
|
||||
class PowerConnectionsListView(ObjectListView):
|
||||
queryset = PowerPort.objects.select_related('device', 'power_outlet__device').filter(power_outlet__isnull=False)\
|
||||
queryset = PowerPort.objects.select_related('device', 'power_outlet__device').filter(power_outlet__isnull=False) \
|
||||
.order_by('power_outlet__device__name', 'power_outlet__name')
|
||||
filter = filters.PowerConnectionFilter
|
||||
filter_form = forms.PowerConnectionFilterForm
|
||||
@ -1801,7 +1801,7 @@ class PowerConnectionsListView(ObjectListView):
|
||||
|
||||
|
||||
class InterfaceConnectionsListView(ObjectListView):
|
||||
queryset = InterfaceConnection.objects.select_related('interface_a__device', 'interface_b__device')\
|
||||
queryset = InterfaceConnection.objects.select_related('interface_a__device', 'interface_b__device') \
|
||||
.order_by('interface_a__device__name', 'interface_a__name')
|
||||
filter = filters.InterfaceConnectionFilter
|
||||
filter_form = forms.InterfaceConnectionFilterForm
|
||||
|
@ -233,12 +233,14 @@
|
||||
<table class="table table-hover panel-body">
|
||||
<tr>
|
||||
<th>Units</th>
|
||||
<th>Tenant</th>
|
||||
<th>Description</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
{% for resv in reservations %}
|
||||
<tr>
|
||||
<td>{{ resv.unit_list }}</td>
|
||||
<td>{{ resv.tenant }}</td>
|
||||
<td>
|
||||
{{ resv.description }}<br />
|
||||
<small>{{ resv.user }} · {{ resv.created }}</small>
|
||||
|
@ -100,6 +100,10 @@
|
||||
<h2><a href="{% url 'dcim:rack_list' %}?tenant={{ tenant.slug }}" class="btn {% if stats.rack_count %}btn-primary{% else %}btn-default{% endif %} btn-lg">{{ stats.rack_count }}</a></h2>
|
||||
<p>Racks</p>
|
||||
</div>
|
||||
<div class="col-md-4 text-center">
|
||||
<h2><a href="{% url 'dcim:rackreservation_list' %}?tenant={{ tenant.slug }}" class="btn {% if stats.rackreservation_count %}btn-primary{% else %}btn-default{% endif %} btn-lg">{{ stats.rackreservation_count }}</a></h2>
|
||||
<p>Rack Reservations</p>
|
||||
</div>
|
||||
<div class="col-md-4 text-center">
|
||||
<h2><a href="{% url 'dcim:device_list' %}?tenant={{ tenant.slug }}" class="btn {% if stats.device_count %}btn-primary{% else %}btn-default{% endif %} btn-lg">{{ stats.device_count }}</a></h2>
|
||||
<p>Devices</p>
|
||||
|
@ -7,7 +7,7 @@ from django.urls import reverse
|
||||
from django.views.generic import View
|
||||
|
||||
from circuits.models import Circuit
|
||||
from dcim.models import Site, Rack, Device
|
||||
from dcim.models import Site, Rack, Device, RackReservation
|
||||
from ipam.models import IPAddress, Prefix, VLAN, VRF
|
||||
from utilities.views import (
|
||||
BulkDeleteView, BulkEditView, BulkImportView, ObjectDeleteView, ObjectEditView, ObjectListView,
|
||||
@ -75,6 +75,7 @@ class TenantView(View):
|
||||
stats = {
|
||||
'site_count': Site.objects.filter(tenant=tenant).count(),
|
||||
'rack_count': Rack.objects.filter(tenant=tenant).count(),
|
||||
'rackreservation_count': RackReservation.objects.filter(tenant=tenant).count(),
|
||||
'device_count': Device.objects.filter(tenant=tenant).count(),
|
||||
'vrf_count': VRF.objects.filter(tenant=tenant).count(),
|
||||
'prefix_count': Prefix.objects.filter(
|
||||
|
Reference in New Issue
Block a user