Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make EagerLoadingMixin independent of DynamicFieldsMixin #89

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 41 additions & 33 deletions django_restql/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
Serializer, ListSerializer,
ValidationError
)
from django.db.models import Prefetch
from django.conf import settings
from django.db.models.fields.related import(
ManyToOneRel, ManyToManyRel
)
Expand All @@ -18,36 +18,26 @@
)


class DynamicFieldsMixin(object):
query_param_name = "query"

def __init__(self, *args, **kwargs):
# Don't pass 'query', 'fields' and 'exclude' kwargs to the superclass
self.query = kwargs.pop('query', None) # Parsed query
self.allowed_fields = kwargs.pop('fields', None)
self.excluded_fields = kwargs.pop('exclude', None)
self.return_pk = kwargs.pop('return_pk', False)

is_field_kwarg_set = self.allowed_fields is not None
is_exclude_kwarg_set = self.excluded_fields is not None
msg = "May not set both `fields` and `exclude`"
assert not(is_field_kwarg_set and is_exclude_kwarg_set), msg

# Instantiate the superclass normally
super().__init__(*args, **kwargs)

def to_representation(self, instance):
if self.return_pk:
return instance.pk
return super().to_representation(instance)
class RequestQueryParserMixin(object):
yezyilomo marked this conversation as resolved.
Show resolved Hide resolved
@staticmethod
def get_query_param_name():
DEFAULT_QUERY_PARAM_NAME = 'query'
query_param_name = getattr(
settings,
"QUERY_PARAM_NAME",
DEFAULT_QUERY_PARAM_NAME
)
return query_param_name

@classmethod
def has_query_param(cls, request):
return cls.query_param_name in request.query_params
query_param_name = cls.get_query_param_name()
return query_param_name in request.query_params

@classmethod
def get_raw_query(cls, request):
return request.query_params[cls.query_param_name]
query_param_name = cls.get_query_param_name()
return request.query_params[query_param_name]

@classmethod
def get_parsed_query_from_req(cls, request):
Expand All @@ -64,6 +54,28 @@ def get_parsed_query_from_req(cls, request):
)
raise ValidationError(msg) from None


class DynamicFieldsMixin(RequestQueryParserMixin):
def __init__(self, *args, **kwargs):
# Don't pass 'query', 'fields' and 'exclude' kwargs to the superclass
self.query = kwargs.pop('query', None) # Parsed query
self.allowed_fields = kwargs.pop('fields', None)
self.excluded_fields = kwargs.pop('exclude', None)
self.return_pk = kwargs.pop('return_pk', False)

is_field_kwarg_set = self.allowed_fields is not None
is_exclude_kwarg_set = self.excluded_fields is not None
msg = "May not set both `fields` and `exclude`"
assert not(is_field_kwarg_set and is_exclude_kwarg_set), msg

# Instantiate the superclass normally
super().__init__(*args, **kwargs)

def to_representation(self, instance):
if self.return_pk:
return instance.pk
return super().to_representation(instance)

def get_allowed_fields(self):
fields = super().fields
if self.allowed_fields is not None:
Expand Down Expand Up @@ -268,20 +280,16 @@ def fields(self):
return {}


class EagerLoadingMixin(object):
class EagerLoadingMixin(RequestQueryParserMixin):
@property
def parsed_query(self):
"""
Gets parsed query for use in eager loading.
Defaults to the serializer parsed query assuming
using django-restql DynamicsFieldMixin.
"""
if hasattr(self, "get_serializer_class"):
serializer_class = self.get_serializer_class()

if issubclass(serializer_class, DynamicFieldsMixin):
if serializer_class.has_query_param(self.request):
return serializer_class.get_parsed_query_from_req(self.request)
if self.has_query_param(self.request):
yezyilomo marked this conversation as resolved.
Show resolved Hide resolved
return self.get_parsed_query_from_req(self.request)

# Else include all fields
query = {
Expand Down Expand Up @@ -391,7 +399,7 @@ def get_queryset(self):
queryset = super().get_queryset()
queryset = self.get_eager_queryset(queryset)
return queryset


class NestedCreateMixin(object):
""" Create Mixin """
Expand Down
10 changes: 3 additions & 7 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -614,15 +614,11 @@ When prefetching with a `to_attr`, ensure that there are no collisions. Django d
When prefetching *and* calling `select_related` on a field, Django may error, since the ORM does allow prefetching a selectable field, but not both at the same time.

### Changing `query` parameter name
If you don't want to use the name `query` as your parameter, you can inherit `DynamicFieldsMixin` and change it as shown below

If you don't want to use the name `query` as your parameter, you can change it with`QUERY_PARAM_NAME` on settings file e.g
```py
from django_restql.mixins import DynamicFieldsMixin
class MyDynamicFieldMixin(DynamicFieldsMixin):
query_param_name = "your_favourite_name"
QUERY_PARAM_NAME = "your_favourite_name"
yezyilomo marked this conversation as resolved.
Show resolved Hide resolved
```

Now you can use this Mixin on your serializer and use the name `your_favourite_name` as your parameter. E.g
Now you can use the name `your_favourite_name` as your query parameter. E.g

`GET /users/?your_favourite_name={id, username}`

Expand Down