Skip to content

Commit

Permalink
Merge pull request #26 from percipient/update-tox
Browse files Browse the repository at this point in the history
Add support for Django 1.11 (and master)
  • Loading branch information
clokep authored Sep 5, 2017
2 parents e67216a + bde8e2c commit 86b6af6
Show file tree
Hide file tree
Showing 9 changed files with 90 additions and 32 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
language: python
# This version of python is only used to run tox.
python: 3.5
python: 3.6
script: tox
notifications:
email: false
Expand Down
8 changes: 5 additions & 3 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
Changelog
#########

0.7.3 (xxxx-xx-xx)
==================
0.8 (2017-09-05)
================

* [Enhancement] Optimize iteration when *not* slicing a ``QuerySetSequence``.
See #29.
* [Enhancement] Officially support Django 1.11.
* [Enhancement] Officially support Django REST Framework 3.5 and 3.6.

0.7.2 (2017-04-04)
==================
Expand Down Expand Up @@ -43,7 +45,7 @@ Changelog
0.6.1 (2016-08-03)
==================

* [Enhancement] Officially, support Django 1.10.
* [Enhancement] Officially support Django 1.10.

0.6 (2016-06-07)
================
Expand Down
53 changes: 41 additions & 12 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,15 @@ multiple ``QuerySets``:
* - |all|_
- |check|
-
* - |union|_
- |xmark|
-
* - |intersection|_
- |xmark|
-
* - |difference|_
- |xmark|
-
* - |select_related|_
- |check|
-
Expand Down Expand Up @@ -155,7 +164,7 @@ multiple ``QuerySets``:
-
* - |as_manager|_
- |check|
-
-

.. |filter| replace:: ``filter()``
.. _filter: https://docs.djangoproject.com/en/dev/ref/models/querysets/#filter
Expand All @@ -172,7 +181,7 @@ multiple ``QuerySets``:
.. |values| replace:: ``values()``
.. _values: https://docs.djangoproject.com/en/dev/ref/models/querysets/#values
.. |values_list| replace:: ``values_list()``
.. _values_list: https://docs.djangoproject.com/en/dev/ref/models/querysets/#values_list
.. _values_list: https://docs.djangoproject.com/en/dev/ref/models/querysets/#values-list
.. |dates| replace:: ``dates()``
.. _dates: https://docs.djangoproject.com/en/dev/ref/models/querysets/#dates
.. |datetimes| replace:: ``datetimes()``
Expand All @@ -181,10 +190,16 @@ multiple ``QuerySets``:
.. _none: https://docs.djangoproject.com/en/dev/ref/models/querysets/#none
.. |all| replace:: ``all()``
.. _all: https://docs.djangoproject.com/en/dev/ref/models/querysets/#all
.. |union| replace:: ``union()``
.. _union: https://docs.djangoproject.com/en/dev/ref/models/querysets/#union
.. |intersection| replace:: ``intersection()``
.. _intersection: https://docs.djangoproject.com/en/dev/ref/models/querysets/#intersection
.. |difference| replace:: ``difference()``
.. _difference: https://docs.djangoproject.com/en/dev/ref/models/querysets/#difference
.. |select_related| replace:: ``select_related()``
.. _select_related: https://docs.djangoproject.com/en/dev/ref/models/querysets/#select_related
.. _select_related: https://docs.djangoproject.com/en/dev/ref/models/querysets/#select-related
.. |prefetch_related| replace:: ``prefetch_related()``
.. _prefetch_related: https://docs.djangoproject.com/en/dev/ref/models/querysets/#prefetch_related
.. _prefetch_related: https://docs.djangoproject.com/en/dev/ref/models/querysets/#prefetch-related
.. |extra| replace:: ``extra()``
.. _extra: https://docs.djangoproject.com/en/dev/ref/models/querysets/#extra
.. |defer| replace:: ``defer()``
Expand All @@ -194,19 +209,19 @@ multiple ``QuerySets``:
.. |using| replace:: ``using()``
.. _using: https://docs.djangoproject.com/en/dev/ref/models/querysets/#using
.. |select_for_update| replace:: ``select_for_update()``
.. _select_for_update: https://docs.djangoproject.com/en/dev/ref/models/querysets/#select_for_update
.. _select_for_update: https://docs.djangoproject.com/en/dev/ref/models/querysets/#select-for-update
.. |raw| replace:: ``raw()``
.. _raw: https://docs.djangoproject.com/en/dev/ref/models/querysets/#raw
.. |get| replace:: ``get()``
.. _get: https://docs.djangoproject.com/en/dev/ref/models/querysets/#get
.. |create| replace:: ``create()``
.. _create: https://docs.djangoproject.com/en/dev/ref/models/querysets/#create
.. |get_or_create| replace:: ``get_or_create()``
.. _get_or_create: https://docs.djangoproject.com/en/dev/ref/models/querysets/#get_or_create
.. _get_or_create: https://docs.djangoproject.com/en/dev/ref/models/querysets/#get-or-create
.. |update_or_create| replace:: ``update_or_create()``
.. _update_or_create: https://docs.djangoproject.com/en/dev/ref/models/querysets/#update_or_create
.. _update_or_create: https://docs.djangoproject.com/en/dev/ref/models/querysets/#update-or-create
.. |bulk_create| replace:: ``bulk_create()``
.. _bulk_create: https://docs.djangoproject.com/en/dev/ref/models/querysets/#bulk_create
.. _bulk_create: https://docs.djangoproject.com/en/dev/ref/models/querysets/#bulk-create
.. |count| replace:: ``count()``
.. _count: https://docs.djangoproject.com/en/dev/ref/models/querysets/#count
.. |in_bulk| replace:: ``in_bulk()``
Expand All @@ -230,7 +245,7 @@ multiple ``QuerySets``:
.. |delete| replace:: ``delete()``
.. _delete: https://docs.djangoproject.com/en/dev/ref/models/querysets/#delete
.. |as_manager| replace:: ``as_manager()``
.. _as_manager: https://docs.djangoproject.com/en/dev/ref/models/querysets/#as_manager
.. _as_manager: https://docs.djangoproject.com/en/dev/ref/models/querysets/#as-manager


.. [1] ``QuerySetSequence`` supports a special field lookup that looks up the
Expand Down Expand Up @@ -277,9 +292,9 @@ multiple ``QuerySets``:
Requirements
============

* Python (2.7, 3.4, 3.5)
* Django (1.8, 1.9, 1.10)
* (Optionally) Django REST Framework (3.2, 3.3, 3.4)
* Python (2.7, 3.4, 3.5, 3.6)
* Django (1.8, 1.9, 1.10, 1.11)
* (Optionally) Django REST Framework (3.2, 3.3, 3.4, 3.5, 3.6)

.. list-table:: ``QuerySetSequence`` versions with support for Django/Django REST Framework
:header-rows: 1
Expand All @@ -289,18 +304,32 @@ Requirements
- Django 1.8
- Django 1.9
- Django 1.10
- Django 1.11
* - Django REST Framework 3.2
- 0.7
- |xmark|
- |xmark|
- |xmark|
* - Django REST Framework 3.3
- 0.7
- 0.7
- |xmark|
- |xmark|
* - Django REST Framework 3.4
- 0.7
- 0.7
- 0.7
- 0.7.1
* - Django REST Framework 3.5
- 0.7.1
- 0.7.1
- 0.7.1
- 0.7.1
* - Django REST Framework 3.6
- 0.8
- 0.8
- 0.8
- 0.8

Installation
============
Expand Down
21 changes: 21 additions & 0 deletions queryset_sequence/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,16 @@ def cumsum(seq):
yield s


# Bridge the Django >= 1.11 Iterable object back to the Query object being an
# iterator.
class SequenceIterable(object):
def __init__(self, queryset, *args, **kwargs):
self.queryset = queryset._clone()

def __iter__(self):
return iter(self.queryset.query)


class QuerySequence(six.with_metaclass(PartialInheritanceMeta, Query)):
"""
A Query that handles multiple QuerySets.
Expand Down Expand Up @@ -106,6 +116,12 @@ def __str__(self):
"""Return the class-name and memory location; there's no SQL to show."""
return object.__str__(self)

def chain(self, *args, **kwargs):
obj = super(QuerySequence, self).chain(*args, **kwargs)

obj._querysets = [qs._chain() for qs in self._querysets]
return obj

def clone(self, *args, **kwargs):
obj = super(QuerySequence, self).clone(*args, **kwargs)

Expand Down Expand Up @@ -419,6 +435,7 @@ class QuerySetSequence(six.with_metaclass(PartialInheritanceMeta, QuerySet)):
'db',

# Private methods.
'_chain',
'_clone',
'_fetch_all',
'_merge_sanity_check',
Expand Down Expand Up @@ -472,6 +489,10 @@ def __init__(self, *args, **kwargs):

super(QuerySetSequence, self).__init__(**kwargs)

# Override the iterator that will be used. (Currently used only in
# Django >= 1.11.)
self._iterable_class = SequenceIterable

def iterator(self):
# Create a clone so that each call re-evaluates the QuerySets.
return self.query.clone()
Expand Down
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def long_description():
setup(
name='django-querysetsequence',
packages=find_packages(),
version='0.7.2',
version='0.8',
description='Chain together multiple (disparate) QuerySets to treat them as a single QuerySet.',
long_description=long_description(),
author='Percipient Networks, LLC',
Expand All @@ -30,6 +30,7 @@ def long_description():
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Framework :: Django',
'License :: OSI Approved :: ISC License (ISCL)',
],
Expand Down
12 changes: 6 additions & 6 deletions tests/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ class Meta:

class Article(models.Model):
title = models.CharField(max_length=100)
author = models.ForeignKey(Author)
publisher = models.ForeignKey(PeriodicalPublisher)
author = models.ForeignKey(Author, on_delete=models.CASCADE)
publisher = models.ForeignKey(PeriodicalPublisher, on_delete=models.CASCADE)
release = models.DateTimeField(auto_now_add=True)

def __str__(self):
Expand All @@ -41,14 +41,14 @@ def __str__(self):

class BlogPost(models.Model):
title = models.CharField(max_length=100)
author = models.ForeignKey(Author)
publisher = models.ForeignKey(OnlinePublisher)
author = models.ForeignKey(Author, on_delete=models.CASCADE)
publisher = models.ForeignKey(OnlinePublisher, on_delete=models.CASCADE)


class Book(models.Model):
title = models.CharField(max_length=50)
author = models.ForeignKey(Author)
publisher = models.ForeignKey(Publisher)
author = models.ForeignKey(Author, on_delete=models.CASCADE)
publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)
release = models.DateTimeField(auto_now_add=True)
pages = models.PositiveSmallIntegerField()

Expand Down
3 changes: 0 additions & 3 deletions tests/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
}
}

ROOT_URLCONF = 'tests/urls'

TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
Expand All @@ -29,7 +27,6 @@
MIDDLEWARE_CLASSES = tuple()

EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'
# EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

INSTALLED_APPS = (
'tests',
Expand Down
11 changes: 9 additions & 2 deletions tests/test_querysetsequence.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from operator import attrgetter

from django import VERSION as DJANGO_VERSION
from django.core.exceptions import (FieldError, MultipleObjectsReturned,
ObjectDoesNotExist)
from django.db.models.query import EmptyQuerySet, QuerySet
Expand Down Expand Up @@ -896,7 +897,10 @@ def test_order_by_queryset(self):
with self.assertNumQueries(0):
qss = self.all.order_by('#', 'title')
self.assertEqual(qss.query.order_by, ['#', 'title'])
self.assertEqual(qss.query._querysets[0].query.order_by, ['title'])
self.assertEqual(
qss.query._querysets[0].query.order_by,
('title',) if DJANGO_VERSION >= (2,) else ['title'],
)

# Ensure that _ordered_iterator isn't called.
with patch('queryset_sequence.QuerySequence._ordered_iterator',
Expand Down Expand Up @@ -926,7 +930,10 @@ def test_order_by_queryset_reverse(self):
with self.assertNumQueries(0):
qss = self.all.order_by('-#', 'title')
self.assertEqual(qss.query.order_by, ['-#', 'title'])
self.assertEqual(qss.query._querysets[0].query.order_by, ['title'])
self.assertEqual(
qss.query._querysets[0].query.order_by,
('title',) if DJANGO_VERSION >= (2,) else ['title'],
)

# Ensure that _ordered_iterator isn't called.
with patch('queryset_sequence.QuerySequence._ordered_iterator',
Expand Down
9 changes: 5 additions & 4 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@
# versions.
envlist =
# Without Django REST Framework.
py27-django{18,19,110},
py{34,35,36}-django{18,19,110},
py27-django{18,19,110,111},
py{34,35,36}-django{18,19,110,111,master},
# Django REST Framework 3.2 added support for Django 1.8.
py{27,34,35,36}-django18-drf32,
# Django REST Framework 3.3 added support for Django 1.9.
py{27,34,35,36}-django{18,19}-drf{33,34,35,36,master},
# Django REST Framework 3.4 added support for Django 1.10.
py{27,34,35,36}-django{110}-drf{34,35,36,master}
py{27,34,35,36}-django{110,111}-drf{34,35,36,master},
py{34,35,36}-django{master}-drf{36,master}
skip_missing_interpreters = True

[testenv]
Expand All @@ -31,7 +32,7 @@ deps =
django18: Django>=1.8,<1.9
django19: Django>=1.9,<1.10
django110: Django>=1.10,<1.11
django111: Django>=1.11a,<2.0
django111: Django>=1.11,<2.0
djangomaster: https://codeload.github.com/django/django/zip/master
drf32: djangorestframework>=3.2,<3.3
drf33: djangorestframework>=3.3,<3.4
Expand Down

0 comments on commit 86b6af6

Please sign in to comment.