{"id":8129,"library":"drf-flex-fields","title":"drf-flex-fields","description":"drf-flex-fields (DRF-FF) is a Python package for Django REST Framework that provides flexible, dynamic fields and nested resources for serializers. It allows clients to control which fields are included or excluded, and to dynamically expand related models via URL parameters like `?fields=id,name` or `?expand=organization.owner.roles`. The library focuses on simplicity with minimal entanglement with DRF's core classes. It is actively maintained with regular updates, including bug fixes and new features, as seen in the recent 1.0.x releases.","status":"active","version":"1.0.2","language":"en","source_language":"en","source_url":"https://github.com/rsinger86/drf-flex-fields","tags":["django","rest-framework","serializers","fields","dynamic","nesting","graphql-like"],"install":[{"cmd":"pip install drf-flex-fields","lang":"bash","label":"Install stable version"}],"dependencies":[{"reason":"Core dependency for Django REST Framework functionality.","package":"djangorestframework","optional":false},{"reason":"Underlying web framework.","package":"django","optional":false}],"imports":[{"note":"Primary serializer class for dynamic field control and expansion.","symbol":"FlexFieldsModelSerializer","correct":"from rest_flex_fields import FlexFieldsModelSerializer"},{"note":"Mixin to add FlexFields functionality to Django REST Framework ViewSets.","symbol":"FlexFieldsMixin","correct":"from rest_flex_fields.views import FlexFieldsMixin"},{"note":"Optional filter backend to automatically optimize queries using select_related/prefetch_related based on expanded fields.","symbol":"FlexFieldsFilterBackend","correct":"from rest_flex_fields.filter_backends import FlexFieldsFilterBackend"},{"note":"Filter backend for OpenAPI/Swagger schema population, useful for documentation tools.","symbol":"FlexFieldsDocsFilterBackend","correct":"from rest_flex_fields.filter_backends import FlexFieldsDocsFilterBackend"}],"quickstart":{"code":"import os\nfrom django.db import models\nfrom rest_framework import serializers, viewsets\nfrom rest_flex_fields import FlexFieldsModelSerializer\nfrom rest_flex_fields.views import FlexFieldsMixin\n\n# Minimal Django setup for demonstration\nos.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')\n\n# Define a simple Django model (e.g., in models.py)\nclass Country(models.Model):\n    name = models.CharField(max_length=100)\n    population = models.IntegerField()\n\n    def __str__(self):\n        return self.name\n\nclass State(models.Model):\n    name = models.CharField(max_length=100)\n    country = models.ForeignKey(Country, related_name='states', on_delete=models.CASCADE)\n\n    def __str__(self):\n        return self.name\n\n# Define FlexFields serializers\nclass StateSerializer(FlexFieldsModelSerializer):\n    class Meta:\n        model = State\n        fields = ('id', 'name')\n\nclass CountrySerializer(FlexFieldsModelSerializer):\n    class Meta:\n        model = Country\n        fields = ('id', 'name', 'population', 'states')\n        expandable_fields = {\n            'states': (StateSerializer, {'many': True})\n        }\n\n# Define a ViewSet using FlexFieldsMixin\nclass CountryViewSet(FlexFieldsMixin, viewsets.ModelViewSet):\n    queryset = Country.objects.all()\n    serializer_class = CountrySerializer\n    # Allow 'states' to be expanded on list views (GET /countries/)\n    permit_list_expands = ['states']\n\n# Example usage (conceptual, in a Django/DRF app context):\n# GET /countries/1/?expand=states\n# GET /countries/?fields=id,name","lang":"python","description":"To use `drf-flex-fields`, inherit your serializers from `FlexFieldsModelSerializer` and define `expandable_fields` in the `Meta` class. For viewsets, inherit from `FlexFieldsMixin` to enable query parameter processing. This allows dynamic field selection via `?fields=` and nested resource expansion via `?expand=` URL parameters. Remember to configure `permit_list_expands` on your viewset if you want to allow expansions on list endpoints, not just detail views."},"warnings":[{"fix":"Add `permit_list_expands = ['field_name']` to your `FlexFieldsMixin` based ViewSet's class definition.","message":"By default, expanding fields is only allowed on detail (single object) views to prevent accidental over-fetching on list views. To enable expansion on list views (e.g., `GET /items/?expand=related_field`), you must explicitly add the field name to `permit_list_expands` on your `FlexFieldsMixin` based ViewSet.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Ensure that any fields you intend to expand are also included in the `fields` query parameter if you are using both. For example, `?fields=id,name,country&expand=country`.","message":"If both `fields` and `expand` query parameters are used simultaneously, the `fields` parameter takes precedence. An expanded field will not be included in the response if it's not also explicitly listed in the `fields` parameter. This can lead to unexpected missing data if not understood.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Utilize `select_related()` and `prefetch_related()` in your ViewSet's `get_queryset()` method or configure the `FlexFieldsFilterBackend` to automatically optimize queries based on the `expand` parameter.","message":"Using deep or recursive expansions (`?expand=a.b.c`) can result in a large number of database queries (`N+1` problem) and significantly impact performance. This is especially true without proper database query optimization.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Change `expandable_fields = {'field': ('MySerializer', {'many': True})}` to `expandable_fields = {'field': ('myapp.serializers.MySerializer', {'many': True})}`.","message":"When referencing serializers by a string name (lazy evaluation) in `expandable_fields`, ensure you include the full app path (e.g., `'myapp.serializers.MySerializer'`) to avoid import resolution issues, especially with complex project structures or circular dependencies.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Avoid using wildcards in public APIs or implement strict permissioning and rate limiting. For internal/trusted APIs, ensure the performance implications are understood and mitigated.","message":"The `expand=*` or `expand=~all` wildcard options, while convenient, can expose the entire object graph and may lead to sensitive data exposure or performance degradation if not carefully controlled and restricted in a public API.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"fix":"Modify your request to include the expanded field in `fields`, e.g., `GET /api/templates/1/?fields=id,coupon_type,book&expand=book`.","cause":"If you are also using the `?fields=` query parameter, the expanded field 'book' must be explicitly included in the `fields` parameter as well.","error":"Expanded field 'book' is not showing in the response when using `?expand=book`."},{"fix":"Use string-based lazy evaluation for serializers in `expandable_fields`, ensuring the full app path is provided: `expandable_fields = {'category': ('myapp.serializers.CategorySerializer', {'many': True})}`.","cause":"Python's import system can struggle with circular imports. Referencing serializers by direct class import can create these issues.","error":"CircularDependencyError or similar import issues when referencing serializers in `expandable_fields`."},{"fix":"Explicitly pass the `request` object in the serializer context: `serializer = MySerializer(instance, context={'request': request})`.","cause":"When manually creating a serializer instance, especially within a custom view or `@action` method, the `request` context might not be automatically passed down to nested serializers, leading to `drf-flex-fields` not properly processing `expand` or `fields`.","error":"`AttributeError: 'Request' object has no attribute 'query_params'` or context missing in nested serializers."}]}