Skip to content

Commit

Permalink
Merge branch 'release/2.0.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
crucialfelix committed Oct 4, 2020
2 parents 2195fc9 + 459ba5b commit b7f1c55
Show file tree
Hide file tree
Showing 31 changed files with 129 additions and 183 deletions.
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
# Change Log

## [2.0.0]

Dropped support for older versions of Django and Python.

Supported:

- Django >= 2.2
- Python >= 3.6

Updates default frontend libraries to:
* //ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js'
* //code.jquery.com/ui/1.12.1/jquery-ui.js
* //code.jquery.com/ui/1.12.1/themes/smoothness/jquery-ui.css

(These can still be customized if you need to run a different version or use different default css)

Many thanks to @Cabilist and @teelee7133

## [1.8.0]

Added/fixed support for Django 2.2
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,14 @@ Read the full documention here: [outside of the admin](http://django-ajax-select

## Assets included by default

* //ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
* //code.jquery.com/ui/1.10.3/jquery-ui.js
* //code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css
* //ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js'
* //code.jquery.com/ui/1.12.1/jquery-ui.js
* //code.jquery.com/ui/1.12.1/themes/smoothness/jquery-ui.css

## Compatibility

* Django >=1.8, <=3
* Python >=2.7, >=3.5
* Django >=2.2
* Python >=3.6

## Contributors

Expand Down
6 changes: 3 additions & 3 deletions ajax_select/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@ class AjaxSelectAdmin(admin.ModelAdmin):
""" in order to get + popup functions subclass this or do the same hook inside of your get_form """

def get_form(self, request, obj=None, **kwargs):
form = super(AjaxSelectAdmin, self).get_form(request, obj, **kwargs)
form = super().get_form(request, obj, **kwargs)

autoselect_fields_check_can_add(form, self.model, request.user)
return form


class AjaxSelectAdminInlineFormsetMixin(object):
class AjaxSelectAdminInlineFormsetMixin:

def get_formset(self, request, obj=None, **kwargs):
fs = super(AjaxSelectAdminInlineFormsetMixin, self).get_formset(request, obj, **kwargs)
fs = super().get_formset(request, obj, **kwargs)
autoselect_fields_check_can_add(fs.form, self.model, request.user)
return fs

Expand Down
68 changes: 25 additions & 43 deletions ajax_select/fields.py
Original file line number Diff line number Diff line change
@@ -1,36 +1,19 @@
from __future__ import unicode_literals

import json
import sys

from ajax_select.registry import registry
from django import forms
from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.db.models import Model
from django.forms.utils import flatatt
from django.template.defaultfilters import force_escape
from django.template.loader import render_to_string
from django.utils.encoding import force_text
from django.urls import reverse
from django.utils.encoding import force_str
from django.utils.module_loading import import_string
from django.utils.safestring import mark_safe
from django.utils.translation import gettext as _

try:
from six import text_type
except ImportError:
from django.utils.six import text_type


if sys.version_info.major >= 3:
from django.utils.translation import gettext as _
else:
from django.utils.translation import ugettext as _

try:
from django.urls import reverse
except ImportError:
# < django 1.10
from django.core.urlresolvers import reverse
from ajax_select.registry import registry

as_default_help = 'Enter text to search.'

Expand Down Expand Up @@ -72,7 +55,7 @@ def __init__(self,
*args,
**kwargs):
self.plugin_options = plugin_options or {}
super(forms.widgets.TextInput, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
self.channel = channel
self.help_text = help_text
self.show_help_text = show_help_text
Expand All @@ -93,7 +76,7 @@ def render(self, name, value, attrs=None, renderer=None, **_kwargs):
try:
obj = objs[0]
except IndexError:
raise Exception("%s cannot find object:%s" % (lookup, value))
raise Exception(f"{lookup} cannot find object:{value}")
current_repr = lookup.format_item_display(obj)
initial = [current_repr, obj.pk]

Expand All @@ -115,7 +98,7 @@ def render(self, name, value, attrs=None, renderer=None, **_kwargs):
context.update(
make_plugin_options(lookup, self.channel, self.plugin_options, initial))
templates = (
'ajax_select/autocompleteselect_%s.html' % self.channel,
f'ajax_select/autocompleteselect_{self.channel}.html',
'ajax_select/autocompleteselect.html')
out = render_to_string(templates, context)
return mark_safe(out)
Expand All @@ -124,7 +107,7 @@ def value_from_datadict(self, data, files, name):
return data.get(name, None)

def id_for_label(self, id_):
return '%s_text' % id_
return f'{id_}_text'


class AutoCompleteSelectField(forms.fields.CharField):
Expand All @@ -143,8 +126,7 @@ def __init__(self, channel, *args, **kwargs):
)
widget_kwargs.update(kwargs.pop('widget_options', {}))
kwargs["widget"] = AutoCompleteSelectWidget(**widget_kwargs)
super(AutoCompleteSelectField, self).__init__(
max_length=255, *args, **kwargs)
super().__init__(max_length=255, *args, **kwargs)

def clean(self, value):
if value:
Expand All @@ -156,7 +138,7 @@ def clean(self, value):
# out of the scope of this field to do anything more than
# tell you it doesn't exist
raise forms.ValidationError(
"%s cannot find object: %s" % (lookup, value))
f"{lookup} cannot find object: {value}")
return objs[0]
else:
if self.required:
Expand All @@ -170,7 +152,7 @@ def has_changed(self, initial, data):
# 1 vs u'1'
initial_value = initial if initial is not None else ''
data_value = data if data is not None else ''
return text_type(initial_value) != text_type(data_value)
return str(initial_value) != str(data_value)


###############################################################################
Expand All @@ -192,7 +174,7 @@ def __init__(self,
plugin_options=None,
*args,
**kwargs):
super(AutoCompleteSelectMultipleWidget, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
self.channel = channel

self.help_text = help_text
Expand Down Expand Up @@ -245,7 +227,7 @@ def render(self, name, value, attrs=None, renderer=None, **_kwargs):
}
context.update(
make_plugin_options(lookup, self.channel, self.plugin_options, initial))
templates = ('ajax_select/autocompleteselectmultiple_%s.html' % self.channel,
templates = (f'ajax_select/autocompleteselectmultiple_{self.channel}.html',
'ajax_select/autocompleteselectmultiple.html')
out = render_to_string(templates, context)
return mark_safe(out)
Expand All @@ -254,8 +236,8 @@ def value_from_datadict(self, data, files, name):
# eg. 'members': ['|229|4688|190|']
return [val for val in data.get(name, '').split('|') if val]

def id_for_label(self, id_):
return '%s_text' % id_
def id_for_label(self, id_, index='0'):
return f'{id_}_text'


class AutoCompleteSelectMultipleField(forms.fields.CharField):
Expand All @@ -275,13 +257,13 @@ def __init__(self, channel, *args, **kwargs):
# '' will cause translation to fail
# should be ''
if isinstance(help_text, str):
help_text = force_text(help_text)
help_text = force_str(help_text)
# django admin appends "Hold down "Control",..." to the help text
# regardless of which widget is used. so even when you specify an
# explicit help text it appends this other default text onto the end.
# This monkey patches the help text to remove that
if help_text != '':
if not isinstance(help_text, text_type):
if not isinstance(help_text, str):
# ideally this could check request.LANGUAGE_CODE
translated = help_text.translate(settings.LANGUAGE_CODE)
else:
Expand Down Expand Up @@ -315,7 +297,7 @@ def __init__(self, channel, *args, **kwargs):
kwargs['widget'] = AutoCompleteSelectMultipleWidget(**widget_kwargs)
kwargs['help_text'] = help_text

super(AutoCompleteSelectMultipleField, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)

def clean(self, value):
if not value and self.required:
Expand All @@ -327,8 +309,8 @@ def check_can_add(self, user, model):

def has_changed(self, initial_value, data_value):
# [1, 2] vs [u'1', u'2']
ivs = [text_type(v) for v in (initial_value or [])]
dvs = [text_type(v) for v in (data_value or [])]
ivs = [str(v) for v in (initial_value or [])]
dvs = [str(v) for v in (data_value or [])]
return ivs != dvs


Expand All @@ -354,7 +336,7 @@ def __init__(self, channel, *args, **kwargs):
self.show_help_text = kwargs.pop('show_help_text', True)
self.plugin_options = kwargs.pop('plugin_options', {})

super(AutoCompleteWidget, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)

def render(self, name, value, attrs=None, renderer=None, **_kwargs):

Expand All @@ -381,7 +363,7 @@ def render(self, name, value, attrs=None, renderer=None, **_kwargs):
}
context.update(
make_plugin_options(lookup, self.channel, self.plugin_options, initial))
templates = ('ajax_select/autocomplete_%s.html' % self.channel,
templates = (f'ajax_select/autocomplete_{self.channel}.html',
'ajax_select/autocomplete.html')
return mark_safe(render_to_string(templates, context))

Expand Down Expand Up @@ -409,7 +391,7 @@ def __init__(self, channel, *args, **kwargs):
defaults = {'max_length': 255, 'widget': widget}
defaults.update(kwargs)

super(AutoCompleteField, self).__init__(*args, **defaults)
super().__init__(*args, **defaults)


###############################################################################
Expand All @@ -429,12 +411,12 @@ def _check_can_add(self, user, related_model):
can_add = lookup.can_add(user, related_model)
else:
ctype = ContentType.objects.get_for_model(related_model)
can_add = user.has_perm("%s.add_%s" % (ctype.app_label, ctype.model))
can_add = user.has_perm(f"{ctype.app_label}.add_{ctype.model}")
if can_add:
app_label = related_model._meta.app_label
model = related_model._meta.object_name.lower()
self.widget.add_link = reverse(
'admin:%s_%s_add' % (app_label, model)) + '?_popup=1'
f'admin:{app_label}_{model}_add') + '?_popup=1'


def autoselect_fields_check_can_add(form, model, user):
Expand Down
6 changes: 3 additions & 3 deletions ajax_select/helpers.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from django.db.models.fields.related import ForeignKey, ManyToManyField
from django.forms.models import ModelForm
from django.utils.encoding import force_text
from django.utils.encoding import force_str
from django.utils.text import capfirst
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _


def make_ajax_form(model, fieldlist, superclass=ModelForm, show_help_text=False, **kwargs):
Expand Down Expand Up @@ -89,7 +89,7 @@ def make_ajax_field(related_model, fieldname_on_model, channel, show_help_text=F

field = related_model._meta.get_field(fieldname_on_model)
if 'label' not in kwargs:
kwargs['label'] = _(capfirst(force_text(field.verbose_name)))
kwargs['label'] = _(capfirst(force_str(field.verbose_name)))

if ('help_text' not in kwargs) and field.help_text:
kwargs['help_text'] = field.help_text
Expand Down
14 changes: 7 additions & 7 deletions ajax_select/lookup_channel.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from django.core.exceptions import PermissionDenied
from django.utils.encoding import force_text
from django.utils.encoding import force_str
from django.utils.html import escape


class LookupChannel(object):
class LookupChannel:
"""
Subclass this, setting the model and implementing methods to taste.
Expand Down Expand Up @@ -40,7 +40,7 @@ def get_query(self, q, request):
Returns:
(QuerySet, list, generator): iterable of related_models
"""
kwargs = {"%s__icontains" % self.search_field: q}
kwargs = {f"{self.search_field}__icontains": q}
return self.model.objects.filter(**kwargs).order_by(self.search_field)

def get_result(self, obj):
Expand All @@ -60,7 +60,7 @@ def get_result(self, obj):
Returns:
str: The object as string
"""
return escape(force_text(obj))
return escape(force_str(obj))

def format_match(self, obj):
"""
Expand All @@ -71,7 +71,7 @@ def format_match(self, obj):
Returns:
str: formatted string, may contain HTML.
"""
return escape(force_text(obj))
return escape(force_str(obj))

def format_item_display(self, obj):
"""
Expand All @@ -82,7 +82,7 @@ def format_item_display(self, obj):
Returns:
str: formatted string, may contain HTML.
"""
return escape(force_text(obj))
return escape(force_str(obj))

def get_objects(self, ids):
"""
Expand Down Expand Up @@ -123,7 +123,7 @@ def can_add(self, user, other_model):
"""
from django.contrib.contenttypes.models import ContentType
ctype = ContentType.objects.get_for_model(other_model)
return user.has_perm("%s.add_%s" % (ctype.app_label, ctype.model))
return user.has_perm(f"{ctype.app_label}.add_{ctype.model}")

def check_auth(self, request):
"""
Expand Down
6 changes: 3 additions & 3 deletions ajax_select/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from django.utils.module_loading import autodiscover_modules


class LookupChannelRegistry(object):
class LookupChannelRegistry:
"""
Registry for LookupChannels activated for your django project.
Expand Down Expand Up @@ -56,7 +56,7 @@ def get(self, channel):
lookup_spec = self._registry[channel]
except KeyError:
raise ImproperlyConfigured(
"No ajax_select LookupChannel named %(channel)r is registered." % {'channel': channel})
f"No ajax_select LookupChannel named {channel!r} is registered.")

if (type(lookup_spec) is type) and issubclass(lookup_spec, LookupChannel):
return lookup_spec()
Expand All @@ -77,7 +77,7 @@ def get(self, channel):
lookup_class = getattr(lookup_module, lookup_spec[1])
return lookup_class()
else:
raise Exception("Invalid lookup spec: %s" % lookup_spec)
raise Exception(f"Invalid lookup spec: {lookup_spec}")

def is_registered(self, channel):
return channel in self._registry
Expand Down

0 comments on commit b7f1c55

Please sign in to comment.