Skip to content

fix: replace serializers.Serializer with MonitoringDeviceDetailSerial…#744

Open
shakurah wants to merge 4 commits intoopenwisp:masterfrom
shakurah:fix/716-removed-unused-api-fields
Open

fix: replace serializers.Serializer with MonitoringDeviceDetailSerial…#744
shakurah wants to merge 4 commits intoopenwisp:masterfrom
shakurah:fix/716-removed-unused-api-fields

Conversation

@shakurah
Copy link

@shakurah shakurah commented Feb 24, 2026

replace serializers.Serializer with MonitoringDeviceDetailSerializer in DeviceMetricView

Checklist

  • I have read the OpenWISP Contributing Guidelines.
  • I have manually tested the changes proposed in this pull request.
  • I have written new test cases for new code and/or updated existing tests for changes to existing code.
  • I have updated the documentation.

Reference to Existing Issue

Closes #716.

Description of Changes

The DeviceMetricView was using serializers.Serializer as its serializer_class
instead of MonitoringDeviceDetailSerializer. This caused drf-yasg to be unable to
infer the correct response schema, resulting in a generic example value being displayed
in the API documentation instead of the actual response fields.

Replacing it with MonitoringDeviceDetailSerializer allows drf-yasg to correctly
generate the schema for the endpoint, making the API documentation accurately reflect
the real response structure.

Screenshot

Screenshot 2026-02-24 191439
Screenshot 2026-02-24 191545
Screenshot 2026-02-24 191629

…izer in DeviceMetricView inside api views to display correct response schema in API documentation
@coderabbitai
Copy link

coderabbitai bot commented Feb 24, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8cb6d0d and dedd8c8.

📒 Files selected for processing (1)
  • openwisp_monitoring/device/api/views.py
📜 Recent review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: Python==3.12 | django~=5.1.0
  • GitHub Check: Python==3.12 | django~=5.2.0
  • GitHub Check: Python==3.13 | django~=5.2.0
  • GitHub Check: Python==3.11 | django~=5.2.0
  • GitHub Check: Python==3.13 | django~=5.1.0
  • GitHub Check: Python==3.11 | django~=4.2.0
  • GitHub Check: Python==3.12 | django~=4.2.0
  • GitHub Check: Python==3.11 | django~=5.1.0
  • GitHub Check: Python==3.10 | django~=4.2.0
  • GitHub Check: Python==3.10 | django~=5.1.0
  • GitHub Check: Python==3.10 | django~=5.2.0
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-02-21T18:44:28.852Z
Learnt from: dee077
Repo: openwisp/openwisp-monitoring PR: 738
File: openwisp_monitoring/device/api/views.py:263-281
Timestamp: 2026-02-21T18:44:28.852Z
Learning: In openwisp-monitoring, MonitoringIndoorCoordinatesList inherits organization scoping from the parent IndoorCoordinatesList (from openwisp-controller), which uses FilterByParentManaged mixin and filters by location_id in get_queryset(). The child class only overrides the queryset attribute to add monitoring-specific select_related fields; this pattern is safe as long as get_queryset() from the parent is not bypassed. During reviews, verify that MonitoringIndoorCoordinatesList continues to rely on the parent's get_queryset() and that any added select_related fields in the child do not alter the parent's filtering logic.

Applied to files:

  • openwisp_monitoring/device/api/views.py
🧬 Code graph analysis (1)
openwisp_monitoring/device/api/views.py (1)
openwisp_monitoring/device/api/serializers.py (1)
  • MonitoringDeviceDetailSerializer (118-119)
🔇 Additional comments (2)
openwisp_monitoring/device/api/views.py (2)

16-16: Import cleanup looks correct.

Removing serializers from the DRF import list is consistent with the current file usage.


127-127: serializer_class now matches the intended response serializer.

This update supports accurate schema generation for DeviceMetricView and aligns with the PR objective.


📝 Walkthrough

Walkthrough

In openwisp_monitoring/device/api/views.py the DeviceMetricView.serializer_class was changed from rest_framework.serializers.Serializer to MonitoringDeviceDetailSerializer. The import of serializers from rest_framework was removed from the module imports since serializers.Serializer is no longer used.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: replacing serializers.Serializer with MonitoringDeviceDetailSerializer in DeviceMetricView.
Description check ✅ Passed The description covers the key aspects but omits test updates and documentation updates despite the template requiring them to be checked.
Linked Issues check ✅ Passed The PR successfully addresses issue #716 by replacing the generic serializer with MonitoringDeviceDetailSerializer, enabling drf-yasg to generate correct API documentation schemas.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing the serializer used in DeviceMetricView, with no out-of-scope modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@openwisp_monitoring/device/api/views.py`:
- Line 123: The get() method currently bypasses the view's serializer_class by
calling MonitoringDeviceDetailSerializer(self.instance).data directly, causing
double-serialization or schema/runtime mismatches; change get() to use the
view's standard serializer retrieval (call self.get_serializer(self.instance))
and use its .data so both drf-yasg/schema generation and runtime responses rely
on the same serializer; ensure MonitoringApiViewMixin.get() behavior is
compatible (i.e., if it already calls get_serializer(), remove the hardcoded
MonitoringDeviceDetailSerializer usage) and keep serializer_class =
MonitoringDeviceDetailSerializer as the single source of truth.
- Line 123: The view sets serializer_class = MonitoringDeviceDetailSerializer
but assigns a plain JSON schema dict to schema, which drf-yasg ignores and
causes incorrect POST/GET/CSV documentation; fix by creating a drf-yasg
AutoSchema subclass (e.g., MonitoringDeviceAutoSchema) that returns the correct
per-method requestBody and responses using the existing JSON schema dict from
openwisp_monitoring/device/schema.py and the actual merged GET response (device
detail + charts) and CSV response (charts only), then set schema =
MonitoringDeviceAutoSchema() on the view; alternatively, if
MonitoringDeviceDetailSerializer is not used at runtime (the view hardcodes
serialization), remove serializer_class to avoid misleading docs.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 331fca2 and b740dea.

📒 Files selected for processing (1)
  • openwisp_monitoring/device/api/views.py
📜 Review details
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-02-21T18:44:28.852Z
Learnt from: dee077
Repo: openwisp/openwisp-monitoring PR: 738
File: openwisp_monitoring/device/api/views.py:263-281
Timestamp: 2026-02-21T18:44:28.852Z
Learning: In openwisp-monitoring, MonitoringIndoorCoordinatesList inherits organization scoping from the parent IndoorCoordinatesList (from openwisp-controller), which uses FilterByParentManaged mixin and filters by location_id in get_queryset(). The child class only overrides the queryset attribute to add monitoring-specific select_related fields; this pattern is safe as long as get_queryset() from the parent is not bypassed. During reviews, verify that MonitoringIndoorCoordinatesList continues to rely on the parent's get_queryset() and that any added select_related fields in the child do not alter the parent's filtering logic.

Applied to files:

  • openwisp_monitoring/device/api/views.py
🧬 Code graph analysis (1)
openwisp_monitoring/device/api/views.py (1)
openwisp_monitoring/device/api/serializers.py (1)
  • MonitoringDeviceDetailSerializer (109-110)

.all()
)
serializer_class = serializers.Serializer
serializer_class = MonitoringDeviceDetailSerializer
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

serializer_class and the explicit MonitoringDeviceDetailSerializer call on line 154 are decoupled — consider aligning them

The get() method always explicitly constructs device detail data via MonitoringDeviceDetailSerializer(self.instance).data (line 154), regardless of serializer_class. This means:

  1. If MonitoringApiViewMixin.get() internally calls self.get_serializer() (the standard DRF path), device data is now serialized twice per request — once by the mixin via get_serializer() and again on line 154.
  2. For the CSV path (return response on line 158), super().get() is returned directly. If the mixin uses get_serializer(), this response now includes MonitoringDeviceDetailSerializer fields that weren't present before (when serializers.Serializer was the serializer_class), potentially changing the CSV output structure.

If MonitoringApiViewMixin.get() does not call get_serializer() and the fix is purely for drf-yasg, the existing design is simply inconsistent — get() could be refactored to use self.get_serializer(self.instance) instead of hardcoding the class, so that both schema inference and runtime behaviour share a single source of truth:

♻️ Suggested alignment (contingent on mixin behaviour)
     if not request.query_params.get("csv"):
         charts_data = dict(response.data)
-        device_metrics_data = MonitoringDeviceDetailSerializer(self.instance).data
+        device_metrics_data = self.get_serializer(self.instance).data
         return Response(
             {**device_metrics_data, **charts_data}, status=status.HTTP_200_OK
         )

Also applies to: 144-158

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@openwisp_monitoring/device/api/views.py` at line 123, The get() method
currently bypasses the view's serializer_class by calling
MonitoringDeviceDetailSerializer(self.instance).data directly, causing
double-serialization or schema/runtime mismatches; change get() to use the
view's standard serializer retrieval (call self.get_serializer(self.instance))
and use its .data so both drf-yasg/schema generation and runtime responses rely
on the same serializer; ensure MonitoringApiViewMixin.get() behavior is
compatible (i.e., if it already calls get_serializer(), remove the hardcoded
MonitoringDeviceDetailSerializer usage) and keep serializer_class =
MonitoringDeviceDetailSerializer as the single source of truth.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find and inspect the custom schema class
echo "=== Searching for schema.py in openwisp_monitoring/device/ ==="
find openwisp_monitoring/device -name "schema.py" -type f

echo -e "\n=== Searching for MonitoringApiViewMixin definition ==="
rg -n "class MonitoringApiViewMixin" --type py -A 40

echo -e "\n=== Inspecting DeviceMetricView more closely ==="
rg -n "class DeviceMetricView" openwisp_monitoring/device/api/views.py -A 100 | head -120

echo -e "\n=== Finding where schema is imported from ==="
rg -n "from.*schema import" openwisp_monitoring/device/api/views.py

Repository: openwisp/openwisp-monitoring

Length of output: 7739


🏁 Script executed:

#!/bin/bash
echo "=== Full MonitoringApiViewMixin.get() method ==="
rg -n "def get" openwisp_monitoring/views.py -A 80 | head -100

echo -e "\n=== Full openwisp_monitoring/device/schema.py ==="
cat openwisp_monitoring/device/schema.py

Repository: openwisp/openwisp-monitoring

Length of output: 24141


🏁 Script executed:

#!/bin/bash
echo "=== Checking if there are tests for DeviceMetricView POST/GET ==="
rg -n "class.*DeviceMetric.*Test" --type py -A 5

echo -e "\n=== Checking imports in views.py to understand drf-yasg integration ==="
head -50 openwisp_monitoring/device/api/views.py | grep -E "^from|^import"

echo -e "\n=== Checking if schema is used as drf-yasg AutoSchema ==="
rg -n "from drf_yasg" openwisp_monitoring/device/ --type py
</parameter>

Repository: openwisp/openwisp-monitoring

Length of output: 1608


🏁 Script executed:

#!/bin/bash
echo "=== Checking MonitoringDeviceDetailSerializer fields ==="
rg -n "class MonitoringDeviceDetailSerializer" openwisp_monitoring/device/api/ -A 30

echo -e "\n=== Checking what data is actually returned in GET response ==="
rg -n "def get\|return Response" openwisp_monitoring/device/api/views.py | head -20

Repository: openwisp/openwisp-monitoring

Length of output: 2682


drf-yasg will incorrectly document POST and GET schemas — the plain JSON schema dict does not override serializer-based schema generation

The schema = schema assignment (line 125) is a plain JSON schema dict from openwisp_monitoring/device/schema.py, not a drf-yasg AutoSchema subclass. drf-yasg ignores plain dicts and falls back to using serializer_class for schema generation.

This causes API documentation mismatches:

  • POST request body: Documented as MonitoringDeviceDetailSerializer fields, but the actual payload is raw device-metrics JSON (matching the NetJSON schema structure).
  • GET response: Documented as MonitoringDeviceDetailSerializer only, but the actual response merges device detail data with charts data (line 156).
  • CSV response: Documented as MonitoringDeviceDetailSerializer but actually returns only chart data (line 158).

Clients using auto-generated swagger clients or reading the API docs will have incorrect schema expectations. Either implement a custom drf-yasg AutoSchema subclass that properly documents per-HTTP-method schemas, or remove serializer_class if it's not used at runtime (line 154 hardcodes the serializer independently).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@openwisp_monitoring/device/api/views.py` at line 123, The view sets
serializer_class = MonitoringDeviceDetailSerializer but assigns a plain JSON
schema dict to schema, which drf-yasg ignores and causes incorrect POST/GET/CSV
documentation; fix by creating a drf-yasg AutoSchema subclass (e.g.,
MonitoringDeviceAutoSchema) that returns the correct per-method requestBody and
responses using the existing JSON schema dict from
openwisp_monitoring/device/schema.py and the actual merged GET response (device
detail + charts) and CSV response (charts only), then set schema =
MonitoringDeviceAutoSchema() on the view; alternatively, if
MonitoringDeviceDetailSerializer is not used at runtime (the view hardcodes
serialization), remove serializer_class to avoid misleading docs.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
openwisp_monitoring/device/api/views.py (1)

123-158: Previously raised concerns remain unaddressed.

The serializer_class assignment is the right intent for fixing drf-yasg schema generation. However, two pre-existing issues flagged in prior review rounds are still present in the current code and are directly relevant to this change:

  1. Double-serialization / decoupled serializer_class (line 154): get() still hardcodes MonitoringDeviceDetailSerializer(self.instance).data independently of serializer_class. If MonitoringApiViewMixin.get() calls self.get_serializer() internally, the serializer is invoked twice per request. At minimum, line 154 should use self.get_serializer(self.instance).data so the runtime path and the schema-inferred path share a single source of truth.

  2. drf-yasg schema mismatch (lines 123, 125): The schema = schema assignment on line 125 is a plain dict (from openwisp_monitoring/device/schema.py), not a drf-yasg AutoSchema subclass — drf-yasg silently ignores it and falls back entirely to serializer_class. This means:

    • POST: Request body is documented as MonitoringDeviceDetailSerializer fields, but the actual POST payload is raw device-metrics JSON (NetJSON format).
    • GET: Response is documented as MonitoringDeviceDetailSerializer only, but the actual response is MonitoringDeviceDetailSerializer data merged with chart data (line 155–156).
    • CSV path (line 158): Returns only chart data, but is documented as MonitoringDeviceDetailSerializer.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@openwisp_monitoring/device/api/views.py` around lines 123 - 158, The view
still double-serializes and misleads drf-yasg: replace the hardcoded
MonitoringDeviceDetailSerializer(self.instance).data in get() with
self.get_serializer(self.instance).data (so the runtime serializer is the same
as serializer_class and used by any MonitoringApiViewMixin.get() path), and
replace the plain dict assigned to schema (the schema variable) with a proper
drf-yasg AutoSchema-compatible inspector or remove the dict so drf-yasg uses
serializer_class correctly; ensure GET responses documented reflect the merged
payload (MonitoringDeviceDetailSerializer + charts) and the CSV branch
documents/returns only chart data by updating the view’s schema implementation
to return the correct request/response schemas for get/post/csv.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@openwisp_monitoring/device/api/views.py`:
- Around line 123-158: The view still double-serializes and misleads drf-yasg:
replace the hardcoded MonitoringDeviceDetailSerializer(self.instance).data in
get() with self.get_serializer(self.instance).data (so the runtime serializer is
the same as serializer_class and used by any MonitoringApiViewMixin.get() path),
and replace the plain dict assigned to schema (the schema variable) with a
proper drf-yasg AutoSchema-compatible inspector or remove the dict so drf-yasg
uses serializer_class correctly; ensure GET responses documented reflect the
merged payload (MonitoringDeviceDetailSerializer + charts) and the CSV branch
documents/returns only chart data by updating the view’s schema implementation
to return the correct request/response schemas for get/post/csv.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b740dea and 8cb6d0d.

📒 Files selected for processing (1)
  • openwisp_monitoring/device/api/views.py
📜 Review details
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-02-21T18:44:28.852Z
Learnt from: dee077
Repo: openwisp/openwisp-monitoring PR: 738
File: openwisp_monitoring/device/api/views.py:263-281
Timestamp: 2026-02-21T18:44:28.852Z
Learning: In openwisp-monitoring, MonitoringIndoorCoordinatesList inherits organization scoping from the parent IndoorCoordinatesList (from openwisp-controller), which uses FilterByParentManaged mixin and filters by location_id in get_queryset(). The child class only overrides the queryset attribute to add monitoring-specific select_related fields; this pattern is safe as long as get_queryset() from the parent is not bypassed. During reviews, verify that MonitoringIndoorCoordinatesList continues to rely on the parent's get_queryset() and that any added select_related fields in the child do not alter the parent's filtering logic.

Applied to files:

  • openwisp_monitoring/device/api/views.py
🧬 Code graph analysis (1)
openwisp_monitoring/device/api/views.py (1)
openwisp_monitoring/device/api/serializers.py (1)
  • MonitoringDeviceDetailSerializer (109-110)
🔇 Additional comments (1)
openwisp_monitoring/device/api/views.py (1)

16-16: LGTM — import cleanup is correct.

Removing serializers from the import is accurate since serializers.Serializer is no longer referenced anywhere in the file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[bug] REST API: device monitoring API mentions unused fields "example" and "Model"

1 participant