Merge branch '10348-decimal-custom-field' of github.com:netbox-community/netbox into 10348-decimal-custom-field

This commit is contained in:
Arthur 2022-09-28 11:42:26 -07:00
commit 20f9388b80
19 changed files with 89 additions and 64 deletions

View File

@ -4,7 +4,7 @@ bleach
# The Python web framework on which NetBox is built # The Python web framework on which NetBox is built
# https://github.com/django/django # https://github.com/django/django
Django<4.1 Django<4.2
# Django middleware which permits cross-domain API requests # Django middleware which permits cross-domain API requests
# https://github.com/OttoYiu/django-cors-headers # https://github.com/OttoYiu/django-cors-headers

View File

@ -25,7 +25,7 @@ ALLOWED_HOSTS = ['*']
## DATABASE ## DATABASE
NetBox requires access to a PostgreSQL 10 or later database service to store data. This service can run locally on the NetBox server or on a remote system. The following parameters must be defined within the `DATABASE` dictionary: NetBox requires access to a PostgreSQL 11 or later database service to store data. This service can run locally on the NetBox server or on a remote system. The following parameters must be defined within the `DATABASE` dictionary:
* `NAME` - Database name * `NAME` - Database name
* `USER` - PostgreSQL username * `USER` - PostgreSQL username

View File

@ -58,7 +58,7 @@ Email is sent from NetBox only for critical events or if configured for [logging
Default: None Default: None
A dictionary of HTTP proxies to use for outbound requests originating from NetBox (e.g. when sending webhook requests). Proxies should be specified by schema (HTTP and HTTPS) as per the [Python requests library documentation](https://2.python-requests.org/en/master/user/advanced/). For example: A dictionary of HTTP proxies to use for outbound requests originating from NetBox (e.g. when sending webhook requests). Proxies should be specified by schema (HTTP and HTTPS) as per the [Python requests library documentation](https://requests.readthedocs.io/en/latest/user/advanced/#proxies). For example:
```python ```python
HTTP_PROXIES = { HTTP_PROXIES = {

View File

@ -2,8 +2,8 @@
This section entails the installation and configuration of a local PostgreSQL database. If you already have a PostgreSQL database service in place, skip to [the next section](2-redis.md). This section entails the installation and configuration of a local PostgreSQL database. If you already have a PostgreSQL database service in place, skip to [the next section](2-redis.md).
!!! warning "PostgreSQL 10 or later required" !!! warning "PostgreSQL 11 or later required"
NetBox requires PostgreSQL 10 or later. Please note that MySQL and other relational databases are **not** supported. NetBox requires PostgreSQL 11 or later. Please note that MySQL and other relational databases are **not** supported.
## Installation ## Installation
@ -35,7 +35,7 @@ sudo systemctl start postgresql
sudo systemctl enable postgresql sudo systemctl enable postgresql
``` ```
Before continuing, verify that you have installed PostgreSQL 10 or later: Before continuing, verify that you have installed PostgreSQL 11 or later:
```no-highlight ```no-highlight
psql -V psql -V

View File

@ -18,7 +18,7 @@ The following sections detail how to set up a new instance of NetBox:
| Dependency | Minimum Version | | Dependency | Minimum Version |
|------------|-----------------| |------------|-----------------|
| Python | 3.8 | | Python | 3.8 |
| PostgreSQL | 10 | | PostgreSQL | 11 |
| Redis | 4.0 | | Redis | 4.0 |
Below is a simplified overview of the NetBox application stack for reference: Below is a simplified overview of the NetBox application stack for reference:

View File

@ -20,7 +20,7 @@ NetBox v3.0 and later require the following:
| Dependency | Minimum Version | | Dependency | Minimum Version |
|------------|-----------------| |------------|-----------------|
| Python | 3.8 | | Python | 3.8 |
| PostgreSQL | 10 | | PostgreSQL | 11 |
| Redis | 4.0 | | Redis | 4.0 |
## 3. Install the Latest Release ## 3. Install the Latest Release
@ -28,16 +28,15 @@ NetBox v3.0 and later require the following:
As with the initial installation, you can upgrade NetBox by either downloading the latest release package or by cloning the `master` branch of the git repository. As with the initial installation, you can upgrade NetBox by either downloading the latest release package or by cloning the `master` branch of the git repository.
!!! warning !!! warning
Use the same method as you used to install Netbox originally Use the same method as you used to install NetBox originally
If you are not sure how Netbox was installed originally, check with this If you are not sure how NetBox was installed originally, check with this command:
command:
``` ```
ls -ld /opt/netbox /opt/netbox/.git ls -ld /opt/netbox /opt/netbox/.git
``` ```
If Netbox was installed from a release package, then `/opt/netbox` will be a If NetBox was installed from a release package, then `/opt/netbox` will be a
symlink pointing to the current version, and `/opt/netbox/.git` will not symlink pointing to the current version, and `/opt/netbox/.git` will not
exist. If it was installed from git, then `/opt/netbox` and exist. If it was installed from git, then `/opt/netbox` and
`/opt/netbox/.git` will both exist as normal directories. `/opt/netbox/.git` will both exist as normal directories.

View File

@ -74,6 +74,6 @@ NetBox is built on the [Django](https://djangoproject.com/) Python framework and
| HTTP service | nginx or Apache | | HTTP service | nginx or Apache |
| WSGI service | gunicorn or uWSGI | | WSGI service | gunicorn or uWSGI |
| Application | Django/Python | | Application | Django/Python |
| Database | PostgreSQL 10+ | | Database | PostgreSQL 11+ |
| Task queuing | Redis/django-rq | | Task queuing | Redis/django-rq |
| Live device access | NAPALM (optional) | | Live device access | NAPALM (optional) |

View File

@ -49,24 +49,6 @@ class MyModel(NetBoxModel):
... ...
``` ```
### The `clone()` Method
!!! info
This method was introduced in NetBox v3.3.
The `NetBoxModel` class includes a `clone()` method to be used for gathering attributes which can be used to create a "cloned" instance. This is used primarily for form initialization, e.g. when using the "clone" button in the NetBox UI. By default, this method will replicate any fields listed in the model's `clone_fields` list, if defined.
Plugin models can leverage this method by defining `clone_fields` as a list of field names to be replicated, or override this method to replace or extend its content:
```python
class MyModel(NetBoxModel):
def clone(self):
attrs = super().clone()
attrs['extra-value'] = 123
return attrs
```
### Enabling Features Individually ### Enabling Features Individually
If you prefer instead to enable only a subset of these features for a plugin model, NetBox provides a discrete "mix-in" class for each feature. You can subclass each of these individually when defining your model. (Your model will also need to inherit from Django's built-in `Model` class.) If you prefer instead to enable only a subset of these features for a plugin model, NetBox provides a discrete "mix-in" class for each feature. You can subclass each of these individually when defining your model. (Your model will also need to inherit from Django's built-in `Model` class.)
@ -116,6 +98,8 @@ For more information about database migrations, see the [Django documentation](h
::: netbox.models.features.ChangeLoggingMixin ::: netbox.models.features.ChangeLoggingMixin
::: netbox.models.features.CloningMixin
::: netbox.models.features.CustomLinksMixin ::: netbox.models.features.CustomLinksMixin
::: netbox.models.features.CustomFieldsMixin ::: netbox.models.features.CustomFieldsMixin

View File

@ -2,12 +2,17 @@
## v3.3.5 (FUTURE) ## v3.3.5 (FUTURE)
### Bug Fixes
* [#9497](https://github.com/netbox-community/netbox/issues/9497) - Adjust non-racked device filter on site and location detailed view
* [#10435](https://github.com/netbox-community/netbox/issues/10435) - Fix exception when filtering VLANs by virtual machine with no cluster assigned
* [#10439](https://github.com/netbox-community/netbox/issues/10439) - Fix form widget styling for DeviceType airflow field
--- ---
## v3.3.4 (2022-09-16) ## v3.3.4 (2022-09-16)
### Bug Fixes ### Bug Fixes
* [#10383](https://github.com/netbox-community/netbox/issues/10383) - Fix assignment of component templates to module types via web UI * [#10383](https://github.com/netbox-community/netbox/issues/10383) - Fix assignment of component templates to module types via web UI
* [#10387](https://github.com/netbox-community/netbox/issues/10387) - Fix `MultiValueDictKeyError` exception when editing a device interface * [#10387](https://github.com/netbox-community/netbox/issues/10387) - Fix `MultiValueDictKeyError` exception when editing a device interface

View File

@ -0,0 +1,12 @@
# NetBox v3.4
!!! warning "PostgreSQL 11 Required"
NetBox v3.4 requires PostgreSQL 11 or later.
### Plugins API
* [#10314](https://github.com/netbox-community/netbox/issues/10314) - Move `clone()` method from NetBoxModel to CloningMixin
### Other Changes
* [#10358](https://github.com/netbox-community/netbox/issues/10358) - Raise minimum required PostgreSQL version from 10 to 11

View File

@ -252,6 +252,7 @@ nav:
- git Cheat Sheet: 'development/git-cheat-sheet.md' - git Cheat Sheet: 'development/git-cheat-sheet.md'
- Release Notes: - Release Notes:
- Summary: 'release-notes/index.md' - Summary: 'release-notes/index.md'
- Version 3.4: 'release-notes/version-3.4.md'
- Version 3.3: 'release-notes/version-3.3.md' - Version 3.3: 'release-notes/version-3.3.md'
- Version 3.2: 'release-notes/version-3.2.md' - Version 3.2: 'release-notes/version-3.2.md'
- Version 3.1: 'release-notes/version-3.1.md' - Version 3.1: 'release-notes/version-3.1.md'

View File

@ -373,6 +373,7 @@ class DeviceTypeForm(NetBoxModelForm):
'front_image', 'rear_image', 'comments', 'tags', 'front_image', 'rear_image', 'comments', 'tags',
] ]
widgets = { widgets = {
'airflow': StaticSelect(),
'subdevice_role': StaticSelect(), 'subdevice_role': StaticSelect(),
'front_image': ClearableFileInput(attrs={ 'front_image': ClearableFileInput(attrs={
'accept': DEVICETYPE_IMAGE_FORMATS 'accept': DEVICETYPE_IMAGE_FORMATS

View File

@ -955,12 +955,13 @@ class RearPort(ModularComponentModel, CabledObjectModel):
super().clean() super().clean()
# Check that positions count is greater than or equal to the number of associated FrontPorts # Check that positions count is greater than or equal to the number of associated FrontPorts
frontport_count = self.frontports.count() if self.pk:
if self.positions < frontport_count: frontport_count = self.frontports.count()
raise ValidationError({ if self.positions < frontport_count:
"positions": f"The number of positions cannot be less than the number of mapped front ports " raise ValidationError({
f"({frontport_count})" "positions": f"The number of positions cannot be less than the number of mapped front ports "
}) f"({frontport_count})"
})
# #

View File

@ -268,7 +268,7 @@ class DeviceType(NetBoxModel):
if ( if (
self.subdevice_role != SubdeviceRoleChoices.ROLE_PARENT self.subdevice_role != SubdeviceRoleChoices.ROLE_PARENT
) and self.devicebaytemplates.count(): ) and self.pk and self.devicebaytemplates.count():
raise ValidationError({ raise ValidationError({
'subdevice_role': "Must delete all device bay templates associated with this device before " 'subdevice_role': "Must delete all device bay templates associated with this device before "
"declassifying it as a parent device." "declassifying it as a parent device."

View File

@ -81,30 +81,34 @@ class VLANQuerySet(RestrictedQuerySet):
# Find all relevant VLANGroups # Find all relevant VLANGroups
q = Q() q = Q()
if vm.cluster.site: site = vm.site or vm.cluster.site
if vm.cluster.site.region: if vm.cluster:
# Add VLANGroups scoped to the assigned cluster (or its group)
q |= Q(
scope_type=ContentType.objects.get_by_natural_key('virtualization', 'cluster'),
scope_id=vm.cluster_id
)
if vm.cluster.group:
q |= Q( q |= Q(
scope_type=ContentType.objects.get_by_natural_key('dcim', 'region'), scope_type=ContentType.objects.get_by_natural_key('virtualization', 'clustergroup'),
scope_id__in=vm.cluster.site.region.get_ancestors(include_self=True) scope_id=vm.cluster.group_id
)
if vm.cluster.site.group:
q |= Q(
scope_type=ContentType.objects.get_by_natural_key('dcim', 'sitegroup'),
scope_id__in=vm.cluster.site.group.get_ancestors(include_self=True)
) )
if site:
# Add VLANGroups scoped to the assigned site (or its group or region)
q |= Q( q |= Q(
scope_type=ContentType.objects.get_by_natural_key('dcim', 'site'), scope_type=ContentType.objects.get_by_natural_key('dcim', 'site'),
scope_id=vm.cluster.site_id scope_id=site.pk
) )
if vm.cluster.group: if site.region:
q |= Q( q |= Q(
scope_type=ContentType.objects.get_by_natural_key('virtualization', 'clustergroup'), scope_type=ContentType.objects.get_by_natural_key('dcim', 'region'),
scope_id=vm.cluster.group_id scope_id__in=site.region.get_ancestors(include_self=True)
) )
q |= Q( if site.group:
scope_type=ContentType.objects.get_by_natural_key('virtualization', 'cluster'), q |= Q(
scope_id=vm.cluster_id scope_type=ContentType.objects.get_by_natural_key('dcim', 'sitegroup'),
) scope_id__in=site.group.get_ancestors(include_self=True)
)
vlan_groups = VLANGroup.objects.filter(q) vlan_groups = VLANGroup.objects.filter(q)
# Return all applicable VLANs # Return all applicable VLANs
@ -113,7 +117,7 @@ class VLANQuerySet(RestrictedQuerySet):
Q(group__scope_id__isnull=True, site__isnull=True) | # Global group VLANs Q(group__scope_id__isnull=True, site__isnull=True) | # Global group VLANs
Q(group__isnull=True, site__isnull=True) # Global VLANs Q(group__isnull=True, site__isnull=True) # Global VLANs
) )
if vm.cluster.site: if site:
q |= Q(site=vm.cluster.site) q |= Q(site=site)
return self.filter(q) return self.filter(q)

View File

@ -92,8 +92,17 @@ class CloningMixin(models.Model):
def clone(self): def clone(self):
""" """
Return a dictionary of attributes suitable for creating a copy of the current instance. This is used for pre- Returns a dictionary of attributes suitable for creating a copy of the current instance. This is used for pre-
populating an object creation form in the UI. populating an object creation form in the UI. By default, this method will replicate any fields listed in the
model's `clone_fields` list (if defined), but it can be overridden to apply custom logic.
```python
class MyModel(NetBoxModel):
def clone(self):
attrs = super().clone()
attrs['extra-value'] = 123
return attrs
```
""" """
attrs = {} attrs = {}

View File

@ -367,7 +367,7 @@ class VirtualMachine(NetBoxModel, ConfigContextModel):
}) })
# Validate primary IP addresses # Validate primary IP addresses
interfaces = self.interfaces.all() interfaces = self.interfaces.all() if self.pk else None
for family in (4, 6): for family in (4, 6):
field = f'primary_ip{family}' field = f'primary_ip{family}'
ip = getattr(self, field) ip = getattr(self, field)

View File

@ -11,3 +11,12 @@ profile = "black"
[tool.pylint] [tool.pylint]
max-line-length = 120 max-line-length = 120
[tool.pyright]
include = ["netbox"]
exclude = [
"**/node_modules",
"**/__pycache__",
]
reportMissingImports = true
reportMissingTypeStubs = false

View File

@ -1,5 +1,5 @@
bleach==5.0.1 bleach==5.0.1
Django==4.0.7 Django==4.1.1
django-cors-headers==3.13.0 django-cors-headers==3.13.0
django-debug-toolbar==3.6.0 django-debug-toolbar==3.6.0
django-filter==22.1 django-filter==22.1