Skip to content

Frequency Management API Package

frequency_management.api

REST API module for frequency_management app.

serializers

API serializers for frequency_management.

FrequencyBandSerializer

Bases: NautobotModelSerializer, TaggedModelSerializerMixin

FrequencyBand Serializer.

Source code in frequency_management/api/serializers.py
class FrequencyBandSerializer(NautobotModelSerializer, TaggedModelSerializerMixin):  # pylint: disable=too-many-ancestors
    """FrequencyBand Serializer."""

    @staticmethod
    def _apply_standard_range(attrs, instance=None):
        """Apply standard lower/upper range for the selected band name."""
        band_name = attrs.get("name", getattr(instance, "name", None))
        standard_range = models.FrequencyBand.get_standard_range(band_name)
        if standard_range is None:
            allowed_bands = ", ".join(models.FrequencyBand.STANDARD_BAND_RANGES_MHZ.keys())
            raise serializers.ValidationError({"name": f"Band must be one of: {allowed_bands}."})

        attrs["lower_frequency_mhz"], attrs["upper_frequency_mhz"] = standard_range
        return attrs

    def to_internal_value(self, data):
        """Populate normalized range fields before field-level validation."""
        mutable_data = dict(data)
        band_name = mutable_data.get("name")
        standard_range = models.FrequencyBand.get_standard_range(band_name)
        if standard_range is not None:
            mutable_data["lower_frequency_mhz"], mutable_data["upper_frequency_mhz"] = standard_range
        return super().to_internal_value(mutable_data)

    def validate(self, attrs):
        """Validate name and normalize lower/upper ranges to standard values."""
        attrs = super().validate(attrs)
        return self._apply_standard_range(attrs, self.instance)

    def create(self, validated_data):
        """Create FrequencyBand with normalized standard range values."""
        validated_data = self._apply_standard_range(validated_data)
        return super().create(validated_data)

    def update(self, instance, validated_data):
        """Update FrequencyBand with normalized standard range values."""
        validated_data = self._apply_standard_range(validated_data, instance)
        return super().update(instance, validated_data)

    class Meta:
        """Meta attributes."""

        model = models.FrequencyBand
        fields = "__all__"
        read_only_fields = ["lower_frequency_mhz", "upper_frequency_mhz"]
Meta

Meta attributes.

Source code in frequency_management/api/serializers.py
class Meta:
    """Meta attributes."""

    model = models.FrequencyBand
    fields = "__all__"
    read_only_fields = ["lower_frequency_mhz", "upper_frequency_mhz"]
create(validated_data)

Create FrequencyBand with normalized standard range values.

Source code in frequency_management/api/serializers.py
def create(self, validated_data):
    """Create FrequencyBand with normalized standard range values."""
    validated_data = self._apply_standard_range(validated_data)
    return super().create(validated_data)
to_internal_value(data)

Populate normalized range fields before field-level validation.

Source code in frequency_management/api/serializers.py
def to_internal_value(self, data):
    """Populate normalized range fields before field-level validation."""
    mutable_data = dict(data)
    band_name = mutable_data.get("name")
    standard_range = models.FrequencyBand.get_standard_range(band_name)
    if standard_range is not None:
        mutable_data["lower_frequency_mhz"], mutable_data["upper_frequency_mhz"] = standard_range
    return super().to_internal_value(mutable_data)
update(instance, validated_data)

Update FrequencyBand with normalized standard range values.

Source code in frequency_management/api/serializers.py
def update(self, instance, validated_data):
    """Update FrequencyBand with normalized standard range values."""
    validated_data = self._apply_standard_range(validated_data, instance)
    return super().update(instance, validated_data)
validate(attrs)

Validate name and normalize lower/upper ranges to standard values.

Source code in frequency_management/api/serializers.py
def validate(self, attrs):
    """Validate name and normalize lower/upper ranges to standard values."""
    attrs = super().validate(attrs)
    return self._apply_standard_range(attrs, self.instance)

FrequencySerializer

Bases: NautobotModelSerializer, TaggedModelSerializerMixin

Frequency Serializer.

Source code in frequency_management/api/serializers.py
class FrequencySerializer(NautobotModelSerializer, TaggedModelSerializerMixin):  # pylint: disable=too-many-ancestors
    """Frequency Serializer."""

    class Meta:
        """Serializer metadata for Frequency."""

        model = models.Frequency
        fields = "__all__"
Meta

Serializer metadata for Frequency.

Source code in frequency_management/api/serializers.py
class Meta:
    """Serializer metadata for Frequency."""

    model = models.Frequency
    fields = "__all__"

FrequencySetSerializer

Bases: NautobotModelSerializer, TaggedModelSerializerMixin

FrequencySet Serializer.

Source code in frequency_management/api/serializers.py
class FrequencySetSerializer(NautobotModelSerializer, TaggedModelSerializerMixin):  # pylint: disable=too-many-ancestors
    """FrequencySet Serializer."""

    class Meta:
        """Serializer metadata for FrequencySet."""

        model = models.MissionFrequencySet
        fields = "__all__"
Meta

Serializer metadata for FrequencySet.

Source code in frequency_management/api/serializers.py
class Meta:
    """Serializer metadata for FrequencySet."""

    model = models.MissionFrequencySet
    fields = "__all__"

SatelliteSerializer

Bases: NautobotModelSerializer, TaggedModelSerializerMixin

Satellite Serializer.

Source code in frequency_management/api/serializers.py
class SatelliteSerializer(NautobotModelSerializer, TaggedModelSerializerMixin):  # pylint: disable=too-many-ancestors
    """Satellite Serializer."""

    class Meta:
        """Serializer metadata for Satellite."""

        model = models.Satellite
        fields = "__all__"
Meta

Serializer metadata for Satellite.

Source code in frequency_management/api/serializers.py
class Meta:
    """Serializer metadata for Satellite."""

    model = models.Satellite
    fields = "__all__"

urls

Django API urlpatterns declaration for frequency_management app.

views

API views for frequency_management.

FrequencyBandViewSet

Bases: ReadOnlyModelViewSet

Read-only FrequencyBand viewset for lookup/classification use.

Source code in frequency_management/api/views.py
class FrequencyBandViewSet(ReadOnlyModelViewSet):  # pylint: disable=too-many-ancestors
    """Read-only FrequencyBand viewset for lookup/classification use."""

    queryset = models.FrequencyBand.objects.all()
    serializer_class = serializers.FrequencyBandSerializer
    filterset_class = filters.FrequencyBandFilterSet

FrequencySetViewSet

Bases: NautobotModelViewSet

FrequencySet viewset.

Source code in frequency_management/api/views.py
class FrequencySetViewSet(NautobotModelViewSet):  # pylint: disable=too-many-ancestors
    """FrequencySet viewset."""

    queryset = models.MissionFrequencySet.objects.select_related("satellite", "band", "provider", "status", "tenant")
    serializer_class = serializers.FrequencySetSerializer
    filterset_class = filters.FrequencySetFilterSet

FrequencyViewSet

Bases: NautobotModelViewSet

Frequency viewset.

Source code in frequency_management/api/views.py
class FrequencyViewSet(NautobotModelViewSet):  # pylint: disable=too-many-ancestors
    """Frequency viewset."""

    queryset = models.Frequency.objects.select_related("band", "device", "status", "tenant")
    serializer_class = serializers.FrequencySerializer
    filterset_class = filters.FrequencyFilterSet

    @action(detail=False, methods=["get"], url_path="available", filterset_class=None)
    def available(self, request):
        """Return catalog frequencies that are not currently in use by scoped Frequency Sets."""
        band_id = request.query_params.get("band")
        if not band_id:
            return Response({"detail": "Query parameter 'band' is required."}, status=400)

        satellite_id = request.query_params.get("satellite")
        tenant_id = request.query_params.get("tenant")
        provider_id = request.query_params.get("provider")
        exclude_mission_number = request.query_params.get("exclude_mission_number")

        status_ids_param = request.query_params.get("mission_set_status_id", "")
        status_ids = [status_id.strip() for status_id in status_ids_param.split(",") if status_id.strip()]
        status_param = request.query_params.get("mission_set_status", "active")
        status_names = [name.strip() for name in status_param.split(",") if name.strip()]

        catalog_queryset = self.get_queryset().filter(band_id=band_id)
        if tenant_id:
            catalog_queryset = catalog_queryset.filter(django_models.Q(tenant_id=tenant_id) | django_models.Q(tenant__isnull=True))

        occupied_sets = models.MissionFrequencySet.objects.filter(band_id=band_id)
        if satellite_id:
            occupied_sets = occupied_sets.filter(satellite_id=satellite_id)
        if tenant_id:
            occupied_sets = occupied_sets.filter(django_models.Q(tenant_id=tenant_id) | django_models.Q(tenant__isnull=True))
        if provider_id:
            occupied_sets = occupied_sets.filter(provider_id=provider_id)
        if exclude_mission_number:
            occupied_sets = occupied_sets.exclude(mission_number=exclude_mission_number)

        if status_ids:
            occupied_sets = occupied_sets.filter(status_id__in=status_ids)
        elif status_names:
            status_query = django_models.Q()
            for status_name in status_names:
                status_query |= django_models.Q(status__name__iexact=status_name)
            occupied_sets = occupied_sets.filter(status_query)

        occupied_frequencies = set(occupied_sets.values_list("tx_frequency_mhz", flat=True))
        occupied_frequencies.update(occupied_sets.values_list("rx_frequency_mhz", flat=True))

        available_queryset = catalog_queryset.exclude(frequency_mhz__in=occupied_frequencies).order_by("frequency_mhz")

        page = self.paginate_queryset(available_queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(available_queryset, many=True)
        return Response(serializer.data)
available(request)

Return catalog frequencies that are not currently in use by scoped Frequency Sets.

Source code in frequency_management/api/views.py
@action(detail=False, methods=["get"], url_path="available", filterset_class=None)
def available(self, request):
    """Return catalog frequencies that are not currently in use by scoped Frequency Sets."""
    band_id = request.query_params.get("band")
    if not band_id:
        return Response({"detail": "Query parameter 'band' is required."}, status=400)

    satellite_id = request.query_params.get("satellite")
    tenant_id = request.query_params.get("tenant")
    provider_id = request.query_params.get("provider")
    exclude_mission_number = request.query_params.get("exclude_mission_number")

    status_ids_param = request.query_params.get("mission_set_status_id", "")
    status_ids = [status_id.strip() for status_id in status_ids_param.split(",") if status_id.strip()]
    status_param = request.query_params.get("mission_set_status", "active")
    status_names = [name.strip() for name in status_param.split(",") if name.strip()]

    catalog_queryset = self.get_queryset().filter(band_id=band_id)
    if tenant_id:
        catalog_queryset = catalog_queryset.filter(django_models.Q(tenant_id=tenant_id) | django_models.Q(tenant__isnull=True))

    occupied_sets = models.MissionFrequencySet.objects.filter(band_id=band_id)
    if satellite_id:
        occupied_sets = occupied_sets.filter(satellite_id=satellite_id)
    if tenant_id:
        occupied_sets = occupied_sets.filter(django_models.Q(tenant_id=tenant_id) | django_models.Q(tenant__isnull=True))
    if provider_id:
        occupied_sets = occupied_sets.filter(provider_id=provider_id)
    if exclude_mission_number:
        occupied_sets = occupied_sets.exclude(mission_number=exclude_mission_number)

    if status_ids:
        occupied_sets = occupied_sets.filter(status_id__in=status_ids)
    elif status_names:
        status_query = django_models.Q()
        for status_name in status_names:
            status_query |= django_models.Q(status__name__iexact=status_name)
        occupied_sets = occupied_sets.filter(status_query)

    occupied_frequencies = set(occupied_sets.values_list("tx_frequency_mhz", flat=True))
    occupied_frequencies.update(occupied_sets.values_list("rx_frequency_mhz", flat=True))

    available_queryset = catalog_queryset.exclude(frequency_mhz__in=occupied_frequencies).order_by("frequency_mhz")

    page = self.paginate_queryset(available_queryset)
    if page is not None:
        serializer = self.get_serializer(page, many=True)
        return self.get_paginated_response(serializer.data)

    serializer = self.get_serializer(available_queryset, many=True)
    return Response(serializer.data)

SatelliteViewSet

Bases: NautobotModelViewSet

Satellite viewset.

Source code in frequency_management/api/views.py
class SatelliteViewSet(NautobotModelViewSet):  # pylint: disable=too-many-ancestors
    """Satellite viewset."""

    queryset = models.Satellite.objects.all()
    serializer_class = serializers.SatelliteSerializer
    filterset_class = filters.SatelliteFilterSet