基于Django REST Framework结合MongoDB实现带过滤的数据查询
Hey there! Let's walk through how to add filtered data querying to your Django REST Framework (DRF) setup that uses a MongoDB replica set. Since your MyModel stores structured data in a JSONField, we’ve got practical approaches to cover both structured, predefined filters and flexible ad-hoc filtering.
Step 1: Set Up Dependencies
First, install django-filter—the standard tool for adding filtering capabilities to DRF views:
pip install django-filter
Then add it to your Django project's INSTALLED_APPS and configure DRF to use its filter backend by default:
# settings.py INSTALLED_APPS = [ # ... other existing apps 'django_filters', ] REST_FRAMEWORK = { # ... other DRF settings 'DEFAULT_FILTER_BACKENDS': [ 'django_filters.rest_framework.DjangoFilterBackend', ] }
Step 2: Create a Custom FilterSet
Since your data field is a JSONField (stored as binary in MongoDB), we can leverage MongoDB's native support for querying nested JSON properties. Create a filters.py file to define your filter rules:
# filters.py import django_filters from .models import MyModel class MyModelFilter(django_filters.FilterSet): # Example 1: Exact match for a nested key in `data` user_id = django_filters.NumberFilter(method='filter_user_id') # Example 2: Case-insensitive partial match for a string key username = django_filters.CharFilter(method='filter_username') # Example 3: Filter records where `data.price` is greater than or equal to a value min_price = django_filters.NumberFilter(method='filter_min_price') class Meta: model = MyModel fields = ['user_id', 'username', 'min_price'] def filter_user_id(self, queryset, name, value): # Use double underscores to access nested JSON keys (djongo handles this for MongoDB) return queryset.filter(data__user_id=value) def filter_username(self, queryset, name, value): # Use MongoDB's $regex for partial matches return queryset.filter(data__username__regex=value) def filter_min_price(self, queryset, name, value): # Use `gte` for greater-than-or-equal filtering return queryset.filter(data__price__gte=value)
Step 3: Attach FilterSet to Your DRF View
Update your view to use the MyModelFilter so it accepts filter parameters via query strings:
# views.py from rest_framework import generics from .models import MyModel from .serializers import MySerializer from .filters import MyModelFilter class MyModelListView(generics.ListAPIView): queryset = MyModel.objects.all() serializer_class = MySerializer filterset_class = MyModelFilter
Now you can make requests like:
GET /api/mymodels/?user_id=123to get records wheredata.user_idequals 123GET /api/mymodels/?username=johnto get records wheredata.usernamecontains "john"GET /api/mymodels/?min_price=50to get records wheredata.priceis ≥50
Step 4: Add Flexible Ad-Hoc Filtering (Optional)
If you need to support dynamic filter conditions sent as JSON from the frontend, create a custom filter backend:
# views.py from rest_framework import filters import json class JSONFilterBackend(filters.BaseFilterBackend): def filter_queryset(self, request, queryset, view): # Get the JSON filter parameter from the request filter_json = request.query_params.get('filter', None) if not filter_json: return queryset try: # Parse the JSON into a dictionary filter_dict = json.loads(filter_json) # Map the keys to MongoDB's nested query format mongo_filter = {f'data__{key}': value for key, value in filter_dict.items()} return queryset.filter(**mongo_filter) except json.JSONDecodeError: # Return unfiltered queryset if JSON is invalid return queryset # Update your view to include this backend class MyModelListView(generics.ListAPIView): queryset = MyModel.objects.all() serializer_class = MySerializer filterset_class = MyModelFilter filter_backends = [ 'django_filters.rest_framework.DjangoFilterBackend', JSONFilterBackend ]
Now you can send complex filters via a single query parameter:GET /api/mymodels/?filter={"user_id":123,"status":"active","price":{"$lt":100}}
Key Notes for MongoDB Replica Set
Ensure your Django database configuration is correctly set up for the replica set—this ensures queries are routed appropriately (read preferences are handled by djongo/MongoDB driver):
# settings.py DATABASES = { 'default': { 'ENGINE': 'djongo', 'NAME': 'your_database_name', 'CLIENT': { 'host': 'mongodb://replica-node-1:27017,replica-node-2:27017,replica-node-3:27017/?replicaSet=your-replica-set-name', 'username': 'your_db_user', 'password': 'your_db_password', 'authSource': 'admin', } } }
The binary=True flag on your serializer's JSONField doesn't affect filtering—djongo automatically deserializes the binary JSON for querying.
内容的提问来源于stack exchange,提问作者Albert

