Closes #22989: Reference brief components for nested SerializedPKRelatedField - #23071
Conversation
…tedField FixSerializedPKRelatedField passed the serializer class to resolve_serializer(), which instantiates it with no arguments. The field's nested setting was therefore lost, and the generated response schema referenced the complete component (with the complete field set) even where the field renders a brief representation. Resolve an instance carrying the field's nested setting instead. Request schemas are unaffected and continue to accept integer primary keys. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
bb40631 to
2893928
Compare
|
@claude /review Only report on issues of potential concern; we don't need commentary on anything that doesn't require further consideration. |
|
Claude finished @jeremystretch's task in 4m 24s —— View job Review: #23071 — Reference brief components for nested
|
* Drop the non-BaseModelSerializer fallback in FixSerializedPKRelatedField. SerializedPKRelatedField.to_representation() passes nested unconditionally, so a serializer which doesn't accept it raises TypeError on every read; the branch documented a component for a configuration the API cannot serve. * Generate the OpenAPI schema once per class rather than once per test method. * Exercise the component.ref and request-schema return paths, and use SimpleTestCase for the tests which don't touch the database. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
1 — Non- serializer = self.target.serializer(nested=self.target.nested)That also removes the need for the 3 — Per-test schema generation. Moved into 5 — Breaking change. Renamed the PR section to "Schema churn (breaking change for generated clients)" with a bolded call-out that it warrants an explicit breaking-change note when release notes are assembled. I also folded in the item-4 detail as a factual note ( |
Serializers used only in a nested context have no complete form in the schema, so prefixing them with "Brief" renamed an existing component to no purpose and dropped the old name entirely. Exempt serializers declaring an explicit Meta.ref_name from the prefix, and pin the three affected names. This narrows the schema diff to the fields the bug actually affected: no components are removed, and the nine which are added are purely additive. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Some reservations about the |
Closes: #22989
Problem
SerializedPKRelatedField.to_representation()renders related objects using the field'snestedsetting:The drf-spectacular extension in
core/api/schema.pyinstead handed the serializer class toresolve_serializer(). drf-spectacular callsforce_instance()on it, instantiating with no kwargs, sonestedfell back toFalse. As a result bothNetBoxAutoSchema._get_serializer_name()(which applies theBriefprefix) and_map_serializer()(which prunes toMeta.brief_fields) saw a non-nested serializer, and the schema advertised fields the API never returns.For example,
Site.asnsdocumented#/components/schemas/ASN(18 fields) while the API returns the brief representation (5 fields). 31 fields across the schema were affected.Fix
FixSerializedPKRelatedField.map_serializer_field()now resolves a serializer instance carrying the field'snestedsetting, mirroring whatto_representation()does:The
requestbranch is untouched, so request bodies continue to accept an array of integer primary keys.Notes:
many=Trueneeds no special handling: drf-spectacular checks the extension registry before unwrappingManyRelatedField, andRelatedField.many_init()passesnestedthrough to thechild_relation, soself.targetis theSerializedPKRelatedFielditself with.nestedintact.nested(e.g.VRF.import_targets) instantiate withnested=False, which is identical to whatforce_instance()did before — no change for them.nestedkwarg is deliberately not defended against here.to_representation()passesnested=unconditionally, so such a serializer already raisesTypeErroron every read of the field; catching it in the schema layer would only document a component for a field the API cannot serve.Avoiding gratuitous component renames
Three serializers —
ASNSiteSerializer,NestedGroupSerializer,NestedUserSerializer— are used only in a nested context, and their brief and complete field sets are identical (the twoNested*serializers declare nobrief_fieldsat all). Prefixing them withBriefwould therefore have renamed an existing component to no purpose and droppedASNSite,NestedGroupandNestedUserfrom the schema entirely._get_serializer_name()now exempts serializers which declare an explicitMeta.ref_namefrom the prefix, and those three names are pinned. drf-spectacular already honoursMeta.ref_name; NetBox's ownget_serializer_ref_name()is unrelated (it only feeds theWritableprefix). A serializer that legitimately needs both a complete and a brief form must not declareref_name.Schema impact
No components are removed and none are renamed. Nine new
Brief*components are added, which is purely additive:BriefASN,BriefContactGroup,BriefGroup,BriefIKEProposal,BriefIPSecProposal,BriefObjectPermission,BriefRouteTarget,BriefVirtualDeviceContext,BriefWirelessLAN31 fields change their
$refto the brief component they actually return —ConfigContext(12 fields),Interface.tagged_vlans/vdcs/wireless_lans,Site.asns,Provider.asns,User.groups/permissions,L2VPN.import_targets/export_targets, and others. This is the fix itself and cannot be avoided: a client generated from the old schema carried a type there which the API never actually produced. SDKs regenerated after this change will differ in those fields, so it still warrants a note when the release notes are assembled.contrib/openapi.jsonis not regenerated here, as it is refreshed as part of the release process. Note thatscripts/verify-openapi.shwill therefore report a mismatch if run locally before then; it is not wired into any CI workflow.Testing
core/tests/test_openapi_schema.pygains coverage at two levels.Against the generated schema (
OpenAPISchemaTestCase):Site.asns→BriefASN,ConfigContext.sites→BriefSite,Interface.tagged_vlans→BriefVLAN— andBriefASNadvertises onlyASNSerializer.Meta.brief_fields.Meta.ref_namekeep their name:ASN.sites→ASNSite,ObjectPermission.groups→NestedGroup,ObjectPermission.users→NestedUser, with noBrief*counterpart generated.VRF.import_targets/export_targetsstill reference the completeRouteTarget.SiteRequest.asns,ConfigContextRequest.sites,ASNRequest.sites).Against the extension directly (
SerializedPKRelatedFieldSchemaTestCase, aSimpleTestCase— it touches no database):nestedsetting, for bothTrueandFalse, and the resolved component'srefis what gets returned.requestdirection returns an integer type without resolving a serializer at all.All of the schema-level assertions were verified to fail against the unpatched extension.
This class also now generates the OpenAPI schema once in
setUpClass()rather than once per test method — it is one of the more expensive operations in the suite, and its output is immutable across these tests. Measured onOpenAPISchemaTestCasealone: 0.700s → 0.277s.🤖 Generated with Claude Code