Перейти к содержанию

Оболочка Python InfraVision

InfraVision включает оболочку управления Python, в которой объекты могут напрямую запрашиваться, создаваться, изменяться и удаляться. Чтобы войти в оболочку, выполните следующую команду:

./manage.py nbshell

Это запустит слегка настроенную версию встроенной оболочки Django со всеми соответствующими моделями InfraVision, предварительно загруженными. (При желании стандартная оболочка Django также доступна при выполнении ./manage.py shell.)

$ ./manage.py nbshell
### NetBox interactive shell (localhost)
### Python 3.7.10 | Django 3.2.5 | NetBox 3.0
### lsmodels() will show available models. Use help(<model>) for more info.

Функция lsmodels() выведет список всех доступных моделей InfraVision:

>>> lsmodels()
DCIM:
  ConsolePort
  ConsolePortTemplate
  ConsoleServerPort
  ConsoleServerPortTemplate
  Device
  ...

Внимание

Оболочка InfraVision предоставляет прямой доступ к данным и функциям InfraVision с очень небольшой валидацией. Поэтому крайне важно обеспечить, чтобы только авторизованные, компетентные пользователи когда-либо получали доступ к ней. Никогда не выполняйте никаких действий в оболочке управления без полной резервной копии.

Запросы объектов

Объекты извлекаются из базы данных с помощью queryset Django. Базовый queryset для объекта имеет форму <model>.objects.all(), который вернёт (усечённый) список всех объектов этого типа.

>>> Device.objects.all()
<QuerySet [<Device: TestDevice1>, <Device: TestDevice2>, <Device: TestDevice3>,
<Device: TestDevice4>, <Device: TestDevice5>, '...(remaining elements truncated)...']>

Используйте цикл for для перебора всех объектов в списке:

>>> for device in Device.objects.all():
...   print(device.name, device.device_type)
...
('TestDevice1', <DeviceType: PacketThingy 9000>)
('TestDevice2', <DeviceType: PacketThingy 9000>)
('TestDevice3', <DeviceType: PacketThingy 9000>)
('TestDevice4', <DeviceType: PacketThingy 9000>)
('TestDevice5', <DeviceType: PacketThingy 9000>)
...

Чтобы подсчитать все объекты, соответствующие запросу, замените all() на count():

>>> Device.objects.count()
1274

Чтобы получить конкретный объект (обычно по первичному ключу или другому уникальному полю), используйте get():

>>> Site.objects.get(pk=7)
<Site: Test Lab>

Фильтрация queryset

В большинстве случаев вы захотите получить только определённое подмножество объектов. Чтобы отфильтровать queryset, замените all() на filter() и передайте один или несколько именованных аргументов. Например:

>>> Device.objects.filter(status="active")
<QuerySet [<Device: TestDevice1>, <Device: TestDevice2>, <Device: TestDevice3>,
<Device: TestDevice8>, <Device: TestDevice9>, '...(remaining elements truncated)...']>

Queryset поддерживают срезы для возврата определённого диапазона объектов.

>>> Device.objects.filter(status="active")[:3]
<QuerySet [<Device: TestDevice1>, <Device: TestDevice2>, <Device: TestDevice3>]>

Метод count() может быть добавлен к queryset для возврата количества объектов вместо полного списка.

>>> Device.objects.filter(status="active").count()
982

Связи с другими моделями можно обходить, объединяя имена атрибутов двойным подчёркиванием. Например, следующий запрос вернёт все устройства, назначенные арендатору с именем "Pied Piper".

>>> Device.objects.filter(tenant__name="Pied Piper")

Этот подход может охватывать несколько уровней связей. Например, следующий запрос вернёт все IP-адреса, назначенные устройству в Северной Америке:

>>> IPAddress.objects.filter(interface__device__site__region__slug="north-america")

Примечание

Хотя приведённый выше запрос функционален, он не очень эффективен. Существуют способы оптимизации таких запросов; однако они выходят за рамки этого документа. Для получения дополнительной информации см. документацию Django queryset method reference.

Обратные связи также можно обходить. Например, следующий запрос найдёт все устройства с интерфейсом с именем "em0":

>>> Device.objects.filter(interfaces__name="em0")

Символьные поля можно фильтровать по частичным совпадениям с помощью выражений поиска contains или icontains (последнее без учёта регистра).

>>> Device.objects.filter(name__icontains="testdevice")

Аналогично, числовые поля можно фильтровать по значениям меньше, больше и/или равным заданному значению.

>>> VLAN.objects.filter(vid__gt=2000)

Несколько фильтров можно комбинировать для дальнейшего уточнения queryset.

>>> VLAN.objects.filter(vid__gt=2000, name__icontains="engineering")

Чтобы вернуть обратное от отфильтрованного queryset, используйте exclude() вместо filter().

>>> Device.objects.count()
4479
>>> Device.objects.filter(status="active").count()
4133
>>> Device.objects.exclude(status="active").count()
346

Информация

Примеры выше предназначены только для предоставления краткого введения в фильтрацию queryset. Полный список доступных фильтров см. в документации Django queryset API.

Создание и обновление объектов

Новые объекты можно создавать, создавая экземпляр нужной модели, определяя значения для всех обязательных атрибутов и вызывая save() на экземпляре. Например, мы можем создать новый VLAN, указав его числовой ID, имя и назначенную площадку:

>>> lab1 = Site.objects.get(pk=7)
>>> myvlan = VLAN(vid=123, name='MyNewVLAN', site=lab1)
>>> myvlan.full_clean()
>>> myvlan.save()

Чтобы изменить существующий объект, мы получаем его, обновляем нужное поле (поля) и снова вызываем save().

>>> vlan = VLAN.objects.get(pk=1280)
>>> vlan.name
'MyNewVLAN'
>>> vlan.name = 'BetterName'
>>> vlan.full_clean()
>>> vlan.save()
>>> VLAN.objects.get(pk=1280).name
'BetterName'

Внимание

Django ORM предоставляет методы для создания/редактирования многих объектов одновременно, а именно bulk_create() и update(). В большинстве случаев их лучше избегать, так как они обходят встроенную валидацию модели и могут легко привести к повреждению базы данных при неосторожном использовании.

Удаление объектов

Чтобы удалить объект, просто вызовите delete() на его экземпляре. Это вернёт словарь всех объектов (включая связанные объекты), которые были удалены в результате этой операции.

>>> vlan
<VLAN: 123 (BetterName)>
>>> vlan.delete()
(1, {'ipam.VLAN': 1})

Чтобы удалить несколько объектов одновременно, вызовите delete() на отфильтрованном queryset. Хорошей идеей будет всегда проверять количество выбранных объектов перед их удалением.

>>> Device.objects.filter(name__icontains='test').count()
27
>>> Device.objects.filter(name__icontains='test').delete()
(35, {'dcim.DeviceBay': 0, 'dcim.InterfaceConnection': 4,
'extras.ImageAttachment': 0, 'dcim.Device': 27, 'dcim.Interface': 4,
'dcim.ConsolePort': 0, 'dcim.PowerPort': 0})

Внимание

Удаления происходят немедленно и необратимы. Всегда тщательно обдумывайте последствия удаления объектов перед вызовом delete() на экземпляре или queryset.