mirror of
				https://github.com/encode/django-rest-framework.git
				synced 2025-11-04 01:47:59 +03:00 
			
		
		
		
	moved mixin's get_query_kwargs to get_query_args to allow the use of django.db.models.Q which is only callable as *args, not **kwargs.
This commit is contained in:
		
							parent
							
								
									8253db67cc
								
							
						
					
					
						commit
						b474c275b7
					
				| 
						 | 
					@ -6,6 +6,7 @@ classes that can be added to a `View`.
 | 
				
			||||||
from django.contrib.auth.models import AnonymousUser
 | 
					from django.contrib.auth.models import AnonymousUser
 | 
				
			||||||
from django.core.paginator import Paginator
 | 
					from django.core.paginator import Paginator
 | 
				
			||||||
from django.db.models.fields.related import ForeignKey
 | 
					from django.db.models.fields.related import ForeignKey
 | 
				
			||||||
 | 
					from django.db.models import Q
 | 
				
			||||||
from django.http import HttpResponse
 | 
					from django.http import HttpResponse
 | 
				
			||||||
from django.utils.safestring import mark_safe
 | 
					from django.utils.safestring import mark_safe
 | 
				
			||||||
from urlobject import URLObject
 | 
					from urlobject import URLObject
 | 
				
			||||||
| 
						 | 
					@ -463,12 +464,13 @@ class ModelMixin(object):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    queryset = None
 | 
					    queryset = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_query_kwargs(self, *args, **kwargs):
 | 
					    def get_query_args(self, *args, **kwargs):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Return a dict of kwargs that will be used to build the
 | 
					        Return a dict of kwargs that will be used to build the
 | 
				
			||||||
        model instance retrieval or to filter querysets.
 | 
					        model instance retrieval or to filter querysets.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        args = list(args)
 | 
				
			||||||
        kwargs = dict(kwargs)
 | 
					        kwargs = dict(kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # If the URLconf includes a .(?P<format>\w+) pattern to match against
 | 
					        # If the URLconf includes a .(?P<format>\w+) pattern to match against
 | 
				
			||||||
| 
						 | 
					@ -477,7 +479,7 @@ class ModelMixin(object):
 | 
				
			||||||
        if BaseRenderer._FORMAT_QUERY_PARAM in kwargs:
 | 
					        if BaseRenderer._FORMAT_QUERY_PARAM in kwargs:
 | 
				
			||||||
            del kwargs[BaseRenderer._FORMAT_QUERY_PARAM]
 | 
					            del kwargs[BaseRenderer._FORMAT_QUERY_PARAM]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return kwargs
 | 
					        return [], kwargs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_instance_data(self, model, content, **kwargs):
 | 
					    def get_instance_data(self, model, content, **kwargs):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
| 
						 | 
					@ -506,11 +508,11 @@ class ModelMixin(object):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return all_kw_args
 | 
					        return all_kw_args
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_instance(self, **kwargs):
 | 
					    def get_instance(self, *args, **kwargs):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Get a model instance for read/update/delete requests.
 | 
					        Get a model instance for read/update/delete requests.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        return self.get_queryset().get(**kwargs)
 | 
					        return self.get_queryset().get(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_queryset(self):
 | 
					    def get_queryset(self):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
| 
						 | 
					@ -532,10 +534,10 @@ class ReadModelMixin(ModelMixin):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    def get(self, request, *args, **kwargs):
 | 
					    def get(self, request, *args, **kwargs):
 | 
				
			||||||
        model = self.resource.model
 | 
					        model = self.resource.model
 | 
				
			||||||
        query_kwargs = self.get_query_kwargs(request, *args, **kwargs)
 | 
					        query_args, query_kwargs = self.get_query_args(request, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            self.model_instance = self.get_instance(**query_kwargs)
 | 
					            self.model_instance = self.get_instance(*query_args, **query_kwargs)
 | 
				
			||||||
        except model.DoesNotExist:
 | 
					        except model.DoesNotExist:
 | 
				
			||||||
            raise ErrorResponse(status.HTTP_404_NOT_FOUND)
 | 
					            raise ErrorResponse(status.HTTP_404_NOT_FOUND)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -588,12 +590,12 @@ class UpdateModelMixin(ModelMixin):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    def put(self, request, *args, **kwargs):
 | 
					    def put(self, request, *args, **kwargs):
 | 
				
			||||||
        model = self.resource.model
 | 
					        model = self.resource.model
 | 
				
			||||||
        query_kwargs = self.get_query_kwargs(request, *args, **kwargs)
 | 
					        query_args, query_kwargs = self.get_query_args(request, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # TODO: update on the url of a non-existing resource url doesn't work
 | 
					        # TODO: update on the url of a non-existing resource url doesn't work
 | 
				
			||||||
        # correctly at the moment - will end up with a new url
 | 
					        # correctly at the moment - will end up with a new url
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            self.model_instance = self.get_instance(**query_kwargs)
 | 
					            self.model_instance = self.get_instance(*query_args, **query_kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            for (key, val) in self.CONTENT.items():
 | 
					            for (key, val) in self.CONTENT.items():
 | 
				
			||||||
                setattr(self.model_instance, key, val)
 | 
					                setattr(self.model_instance, key, val)
 | 
				
			||||||
| 
						 | 
					@ -609,10 +611,10 @@ class DeleteModelMixin(ModelMixin):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    def delete(self, request, *args, **kwargs):
 | 
					    def delete(self, request, *args, **kwargs):
 | 
				
			||||||
        model = self.resource.model
 | 
					        model = self.resource.model
 | 
				
			||||||
        query_kwargs = self.get_query_kwargs(request, *args, **kwargs)
 | 
					        query_args, query_kwargs = self.get_query_args(request, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            instance = self.get_instance(**query_kwargs)
 | 
					            instance = self.get_instance(*query_args, **query_kwargs)
 | 
				
			||||||
        except model.DoesNotExist:
 | 
					        except model.DoesNotExist:
 | 
				
			||||||
            raise ErrorResponse(status.HTTP_404_NOT_FOUND, None, {})
 | 
					            raise ErrorResponse(status.HTTP_404_NOT_FOUND, None, {})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -628,9 +630,9 @@ class ListModelMixin(ModelMixin):
 | 
				
			||||||
    def get(self, request, *args, **kwargs):
 | 
					    def get(self, request, *args, **kwargs):
 | 
				
			||||||
        queryset = self.get_queryset()
 | 
					        queryset = self.get_queryset()
 | 
				
			||||||
        ordering = self.get_ordering()
 | 
					        ordering = self.get_ordering()
 | 
				
			||||||
        query_kwargs = self.get_query_kwargs(request, *args, **kwargs)
 | 
					        query_args, query_kwargs = self.get_query_args(request, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        queryset = queryset.filter(**query_kwargs)
 | 
					        queryset = queryset.filter(*query_args, **query_kwargs)
 | 
				
			||||||
        if ordering:
 | 
					        if ordering:
 | 
				
			||||||
            queryset = queryset.order_by(*ordering)
 | 
					            queryset = queryset.order_by(*ordering)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -860,8 +862,11 @@ they should be extended by <a href="https://docs.djangoproject.com/en/1.4/ref/mo
 | 
				
			||||||
with a double underscore (e.g. <a href="./?%s="><code>?%s=</code></a>)
 | 
					with a double underscore (e.g. <a href="./?%s="><code>?%s=</code></a>)
 | 
				
			||||||
except for the <code>exact</code> suffix which is the default:</p>
 | 
					except for the <code>exact</code> suffix which is the default:</p>
 | 
				
			||||||
<ul>%s</ul>
 | 
					<ul>%s</ul>
 | 
				
			||||||
 | 
					<p>The default statement between multiple fields is <code>AND</code>, if the <code>or__</code> prefix is used then the statement will be <code>OR</code> (e.g. <a href="./?or__%s="><code>?or__%s=</code></a>)
 | 
				
			||||||
 | 
					.</p>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
"""  % (filter_desc_req, filter_desc_example, filter_desc_example, filter_desc_fields_html)
 | 
					"""  % (filter_desc_req, filter_desc_example, filter_desc_example,
 | 
				
			||||||
 | 
					        filter_desc_fields_html, filter_desc_example, filter_desc_example,)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return mark_safe(u'%s\n%s' % (desc, filter_desc))
 | 
					            return mark_safe(u'%s\n%s' % (desc, filter_desc))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -872,33 +877,45 @@ except for the <code>exact</code> suffix which is the default:</p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return u"""%s\n\nFilter options%s:\n\n%s""" % (desc, filter_desc_req, filter_desc_fields_txt)
 | 
					            return u"""%s\n\nFilter options%s:\n\n%s""" % (desc, filter_desc_req, filter_desc_fields_txt)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_query_kwargs(self, *args, **kwargs):
 | 
					    def get_query_args(self, *args, **kwargs):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Return the `QuerySet`'s args according to the GET request's arguments.
 | 
					        Return the `QuerySet`'s args and kwargs according to the GET request's arguments.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        kwargs = super(FilterMixin, self).get_query_kwargs(*args, **kwargs)
 | 
					        args, kwargs = super(FilterMixin, self).get_query_args(self, *args, **kwargs)
 | 
				
			||||||
        self._filter_triggered = False
 | 
					        self._filter_triggered = False
 | 
				
			||||||
 | 
					        q = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for k in self.request.GET:
 | 
					        for k, v in self.request.GET.items():
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if k.startswith('or__'):
 | 
				
			||||||
 | 
					                q_or = True
 | 
				
			||||||
 | 
					                k = k[4:]
 | 
				
			||||||
 | 
					            else: q_or = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            field = k.split('__')
 | 
					            field = k.split('__')
 | 
				
			||||||
            if len(field) == 2: lookup = field[1]
 | 
					            if len(field) == 2: lookup = field[1]
 | 
				
			||||||
            else: lookup = 'exact'
 | 
					            else: lookup = 'exact'
 | 
				
			||||||
            field = field[0]
 | 
					            field = field[0]
 | 
				
			||||||
            value = self.request.GET[k]
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if field in self.filter_fields and lookup in self.filter_fields[field]:
 | 
					            if v and field in self.filter_fields and lookup in self.filter_fields[field]:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                value = self._filter_lookups[lookup](field, value)
 | 
					                v = self._filter_lookups[lookup](field, v)
 | 
				
			||||||
                kwargs['%s__%s' % (field, lookup)] = value
 | 
					                if not q_or: kwargs['%s__%s' % (field, lookup)] = v
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    q_this = Q(**{'%s__%s' % (field, lookup): v})
 | 
				
			||||||
 | 
					                    if q: q = q | q_this
 | 
				
			||||||
 | 
					                    else: q = q_this
 | 
				
			||||||
                self._filter_triggered = True
 | 
					                self._filter_triggered = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return kwargs
 | 
					        if q: args.append(q)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return args, kwargs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get(self, *args, **kwargs):
 | 
					    def get(self, *args, **kwargs):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        queryset = super(FilterMixin, self).get(*args, **kwargs)
 | 
					        queryset = super(FilterMixin, self).get(*args, **kwargs)
 | 
				
			||||||
        if self.filter_required and not self._filter_triggered: return self.resource.model.objects.none()
 | 
					        if self.filter_required and not self._filter_triggered:
 | 
				
			||||||
 | 
					            return self.resource.model.objects.none()
 | 
				
			||||||
        return queryset
 | 
					        return queryset
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user