Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion django_qbe/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '0.3.0'
__version__ = '0.3.2'
14 changes: 3 additions & 11 deletions django_qbe/exports.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
import csv
from collections import OrderedDict
from collections.abc import Callable
from io import StringIO, BytesIO
from io import StringIO

import six
from django.http import StreamingHttpResponse


Expand Down Expand Up @@ -41,16 +40,11 @@ class UnicodeWriter(object):

def __init__(self, dialect=csv.excel_tab, encoding="utf-8", **kwds):
# Redirect output to a queue
self.queue = BytesIO() if six.PY2 else StringIO()
self.queue = StringIO()
self.writer = csv.writer(self.queue, dialect=dialect, **kwds)

def _encode(self, item):
if six.PY2:
encoded = unicode(item).encode('utf-8')
else:
encoded = str(item)

return encoded
return str(item)

def writerow(self, row):
self.writer.writerow([self._encode(s) for s in row])
Expand All @@ -60,8 +54,6 @@ def get_values(self):
ret = self.queue.getvalue()
# empty queue
self.queue.truncate(0)
if six.PY2:
return ret.lstrip(b'\0')
return ret.encode('utf-8').lstrip(b'\0')

def writerows(self, rows):
Expand Down
20 changes: 4 additions & 16 deletions django_qbe/forms.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
from builtins import range
import collections
from collections.abc import Iterable
from django import forms
from django.db import connections
from django.db.models.fields import Field
Expand All @@ -17,17 +15,7 @@
from django_qbe.widgets import CriteriaInput


DATABASES = None
try:
DATABASES = settings.DATABASES
except AttributeError:
# Backwards compatibility for Django versions prior to 1.1.
DATABASES = {
'default': {
'ENGINE': "django.db.backends.%s" % settings.DATABASE_ENGINE,
'NAME': settings.DATABASE_NAME,
}
}
DATABASES = settings.DATABASES

SORT_CHOICES = (
("", ""),
Expand Down Expand Up @@ -242,14 +230,14 @@ def get_query_parts(self):

# make sure the operators params are iterable:
custom_params = custom_operator.get_params()
if isinstance(custom_params, collections.Iterable):
if isinstance(custom_params, Iterable):
params += custom_params
else:
params += [custom_params, ]

# make sure the operators wheres are iterable:
custom_wheres = custom_operator.get_wheres()
if isinstance(custom_wheres, collections.Iterable):
if isinstance(custom_wheres, Iterable):
wheres += custom_wheres
else:
wheres += [custom_wheres, ]
Expand Down
4 changes: 1 addition & 3 deletions django_qbe/operators.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
from builtins import object
from django.conf import settings
from django.db import connections
from django.db.models.fields import Field
from importlib import import_module
from future.utils import with_metaclass

DATABASES = settings.DATABASES

Expand Down Expand Up @@ -41,7 +39,7 @@ def get_operators(self):
return self.operators


class CustomOperator(with_metaclass(OperatorMount, object)):
class CustomOperator(metaclass=OperatorMount):
"""
Mount point for operators which refer to actions that can be performed.

Expand Down
28 changes: 7 additions & 21 deletions django_qbe/savedqueries/admin.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,11 @@
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from django.contrib import admin
try:
from django.contrib.admin.utils import unquote
except ImportError:
# Backward compatibility for Django prior to 1.7
from django.contrib.admin.util import unquote
try:
from django.urls import re_path
except ImportError:
# Backward compatibility for Django prior to 1.6
from django.conf.urls.defaults import url
from functools import update_wrapper

from django.contrib import admin
from django.contrib.admin.utils import unquote
from django.shortcuts import redirect
try:
from functools import update_wrapper
except ImportError:
# Backward compatibility for Django prior to 1.6
from django.utils.functional import update_wrapper

from django.urls import reverse, re_path
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _

from django_qbe.savedqueries.models import SavedQuery
from django_qbe.settings import QBE_ADMIN
Expand All @@ -37,7 +23,7 @@ class SavedQueryAdmin(admin.ModelAdmin):
def run_link(self, obj):
info = (QBE_ADMIN,
self.model._meta.app_label,
self.model._meta.model_name or self.model._meta.module_name)
self.model._meta.model_name)
return mark_safe(u'<span class="nowrap"><a href="%s">%s</a>'
u' | <a href="%s">%s</a></span>' %
(reverse("%s:%s_%s_run" % info, args=(obj.pk,)), _("Run"),
Expand All @@ -50,7 +36,7 @@ def wrapper(*args, **kwargs):
return self.admin_site.admin_view(view)(*args, **kwargs)
return update_wrapper(wrapper, view)
info = (self.model._meta.app_label,
self.model._meta.model_name or self.model._meta.module_name)
self.model._meta.model_name)
urlpatterns = [
re_path(r'^(.+)/run/$', wrap(self.run_view), name='%s_%s_run' % info),
]
Expand Down
4 changes: 0 additions & 4 deletions django_qbe/savedqueries/management/commands/qbe_export.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
# -*- coding: utf-8 -*-
import json

from optparse import make_option

from django.core.management.base import BaseCommand

from django_qbe.forms import QueryByExampleFormSet
Expand Down
12 changes: 3 additions & 9 deletions django_qbe/savedqueries/models.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
from builtins import object
import pickle
from django.db import models
from django.utils.translation import gettext_lazy as _

try:
from django.utils.timezone import now
except ImportError:
from datetime import datetime
now = datetime.now
from django.utils.timezone import now

from picklefield.fields import PickledObjectField

Expand All @@ -22,11 +16,11 @@ class SavedQuery(models.Model):
editable=False)
date_updated = models.DateTimeField(_("date updated"), editable=False)

class Meta(object):
class Meta:
verbose_name = _("Saved query")
verbose_name_plural = _("Saved queries")

def __unicode__(self):
def __str__(self):
return self.name

def save(self, *args, **kwargs):
Expand Down
4 changes: 2 additions & 2 deletions django_qbe/templates/qbe.html
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,11 @@
{% trans "Database" %}
<select name="database_alias" id="id_database_alias">
{% for db_alias, database_properties in databases.items %}
{% ifequal database_alias db_alias %}
{% if database_alias == db_alias %}
<option value="{{ db_alias }}" selected="selected">{{ db_alias }}: {{ database_properties.NAME }} ({{ database_properties.ENGINE }})</option>
{% else %}
<option value="{{ db_alias }}">{{ db_alias }}: {{ database_properties.NAME }} ({{ database_properties.ENGINE }})</option>
{% endifequal %}
{% endif %}
{% endfor %}
</select>
</div>
Expand Down
8 changes: 4 additions & 4 deletions django_qbe/templates/qbe_results.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,17 @@ <h1>

{% block content %}
{% block object-tools %}
{% ifequal limit count %}
{% if limit == count %}
{% trans "Showing all" %} {{ count|floatformat:0 }} {{ results|length|pluralize:_("result,results") }}
{% else %}
{% trans "Showing from" %} {{ offset|floatformat:0 }} {% trans "to" %} {{ offset_limit|floatformat:0 }} {% trans "of" %} {{ count|floatformat:0 }} {{ results|length|pluralize:_("result,results") }}
{% endifequal %}
{% endif %}
<span id="qbeResultsOptions">
{% ifequal limit count %}
{% if limit == count %}
(<a href="{% url "qbe_results" query_hash %}">{% trans "show first ones" %}</a>
{% else %}
(<a href="{% url "qbe_results" query_hash %}?show=all">{% trans "show all" %}</a>
{% endifequal %}
{% endif %}
| <a href="{% url "qbe_form" query_hash %}">{% trans "edit query" %}</a>
| <a href="#" onclick="jQuery('#qbeSQL').toggle();return false;">{% trans "view query" %}</a>)
</span>
Expand Down
5 changes: 1 addition & 4 deletions django_qbe/templatetags/qbe_tags.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
# -*- coding: utf-8 -*-
from __future__ import division
from builtins import range
from past.utils import old_div
from django import template
from django.utils.safestring import mark_safe

Expand Down Expand Up @@ -32,7 +29,7 @@ def _get_range_markup(range_from, range_to):
if total_pages < rows_per_page or not rows_per_page:
pages = 1
else:
pages = (old_div(total_pages, rows_per_page))
pages = total_pages // rows_per_page
if total_pages % rows_per_page != 0:
pages += 1
output = []
Expand Down
9 changes: 3 additions & 6 deletions django_qbe/urls.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
# -*- coding: utf-8 -*-
try:
from django.urls import path, re_path
except ImportError:
# Backward compatibility for Django prior to 1.6
from django.conf.urls.defaults import url
from django.urls import path, re_path

from django_qbe.exports import formats
from . import views

urlpatterns = [
path('', views.qbe_form, name="qbe_form"),
re_path(r'^qbe.js$', views.qbe_js, name="qbe_js"),
path('qbe.js', views.qbe_js, name="qbe_js"),
path('bookmark/', views.qbe_bookmark, name="qbe_bookmark"),
path('proxy/', views.qbe_proxy, name="qbe_proxy"),
path('auto/', views.qbe_autocomplete, name="qbe_autocomplete"),
Expand Down
63 changes: 15 additions & 48 deletions django_qbe/utils.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,4 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
from __future__ import division
import six
from past.builtins import cmp
from builtins import zip
from builtins import filter
from builtins import range
from past.utils import old_div
import base64
import pickle
import random
Expand All @@ -15,17 +7,7 @@
from hashlib import md5
from json import dumps
from functools import reduce
try:
from itertools import combinations
except ImportError:

def combinations(items, n):
if n == 0:
yield []
else:
for i in range(len(items)):
for cc in combinations(items[i + 1:], n - 1):
yield [items[i]] + cc
from itertools import combinations

from django.apps import apps as django_apps
from django.db.models.fields.related import (ForeignKey, OneToOneField,
Expand All @@ -51,14 +33,7 @@ def combinations(items, n):
from django.contrib.admin import site as admin_site
admin_site

try:
from django.contrib.contenttypes.fields import GenericRelation
except ImportError:
# Backward compatibility for Django prior to 1.7
try:
from django.db.models.fields.generic import GenericRelation
except ImportError:
from django.contrib.contenttypes.generic import GenericRelation
from django.contrib.contenttypes.fields import GenericRelation

try:
qbe_formats = QBE_FORMATS_EXPORT
Expand Down Expand Up @@ -306,7 +281,7 @@ def qbe_forest(graph, nodes):
tree, are_all = qbe_tree(graph, copy(nodes), root=node)
if are_all and tree not in forest:
forest.append(tree)
return sorted(forest, cmp=lambda x, y: cmp(len(x), len(y)))
return sorted(forest, key=len)


def find_all_paths(graph, start_node, end_node, path=None):
Expand Down Expand Up @@ -394,8 +369,8 @@ def combine(items, k=None):
for i in range(1, length_items)] + [1]
if k is not None:
k = k % length
# Python division by default is integer division (~ floor(a/b))
indices = [old_div((k % (lengths[i] * repeats[i])), repeats[i])
# Python 3 uses true division by default, use // for integer division
indices = [(k % (lengths[i] * repeats[i])) // repeats[i]
for i in range(length_items)]
return [items[i][indices[i]] for i in range(length_items)]
else:
Expand All @@ -404,7 +379,7 @@ def combine(items, k=None):
row = []
for subset in item:
row.extend([subset] * repeats[i])
times = old_div(length, len(row))
times = length // len(row)
matrix.append(row * times)
# Transpose the matrix or return the columns instead rows
return list(zip(*matrix))
Expand All @@ -428,7 +403,7 @@ def autocomplete_graph(admin_site, current_models, directed=False):
# if all(map(lambda x: x in path, current_models)):
# if path not in valid_paths:
# valid_paths.append(path)
return sorted(valid_paths, cmp=lambda x, y: cmp(len(x), len(y)))
return sorted(valid_paths, key=len)


# Taken from django.contrib.sessions.backends.base
Expand All @@ -443,16 +418,11 @@ def pickle_decode(session_data):
# The '+' character is translated to ' ' in request
session_data = session_data.replace(u" ", u"+")
# The length of the encoded string should be a multiple of 4
while (((old_div(len(session_data), 4.0)) - (old_div(len(session_data), 4))) != 0):
while len(session_data) % 4 != 0:
session_data += u"="
if six.PY3:
encoded_data = base64.decodebytes(str.encode(session_data))
pickled = encoded_data[:-32]
tamper_check = encoded_data[-32:].decode()
else:
encoded_data = base64.decodestring(session_data)
pickled = encoded_data[:-32]
tamper_check = encoded_data[-32:]
encoded_data = base64.decodebytes(str.encode(session_data))
pickled = encoded_data[:-32]
tamper_check = encoded_data[-32:].decode()
pickled_md5 = get_query_hash(pickled)
if pickled_md5 != tamper_check:
raise SuspiciousOperation(u"User tampered with session cookie.")
Expand All @@ -465,10 +435,7 @@ def pickle_decode(session_data):


def get_query_hash(data):
if six.PY3:
bytes_ = bytes()
bytes_ += data if isinstance(data, bytes) else str.encode(data)
bytes_ += str.encode(settings.SECRET_KEY)
return md5(bytes_).hexdigest()
else:
return md5(data + settings.SECRET_KEY).hexdigest()
bytes_ = bytes()
bytes_ += data if isinstance(data, bytes) else str.encode(data)
bytes_ += str.encode(settings.SECRET_KEY)
return md5(bytes_).hexdigest()
2 changes: 1 addition & 1 deletion django_qbe/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,6 @@ def qbe_js(request):
@user_passes_test(qbe_access_for)
def qbe_autocomplete(request):
nodes = None
if request.is_ajax() and request.POST:
if request.headers.get('x-requested-with') == 'XMLHttpRequest' and request.POST:
models = request.POST.get('models', []).split(",")
nodes = autocomplete_graph(admin_site, models)
Loading