Skip to content

Commit

Permalink
Merge branch 'pr/adamchainz/438'
Browse files Browse the repository at this point in the history
  • Loading branch information
SmileyChris committed Mar 27, 2024
2 parents 851ecd0 + 4d3d7b5 commit 8d8af20
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 39 deletions.
1 change: 1 addition & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ release, and any new translations added.
- Replace deprecated ``pkg_resources.iter_entry_points`` with
``importlib_metadata``.

- Support Django 5.0.

7.5.1 (1 February 2023)
=======================
Expand Down
75 changes: 57 additions & 18 deletions django_countries/fields.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import re
import sys
from typing import Any, Iterable, Optional, Tuple, Type, Union, cast
from urllib import parse as urlparse

import django
from django import forms
from django.contrib.admin.filters import FieldListFilter
from django.core import checks, exceptions
Expand All @@ -18,9 +20,14 @@
try:
import importlib.metadata

_entry_points = importlib.metadata.entry_points().get(
"django_countries.Country", []
)
if sys.version_info >= (3, 10):
_entry_points = importlib.metadata.entry_points(
group="django_countries.Country"
)
else:
_entry_points = importlib.metadata.entry_points().get(
"django_countries.Country", []
)
except ImportError: # Python <3.8
import pkg_resources

Expand Down Expand Up @@ -229,12 +236,14 @@ def __set__(self, instance, value):


class LazyChoicesMixin(widgets.LazyChoicesMixin):
def _set_choices(self, value):
"""
Also update the widget's choices.
"""
super()._set_choices(value)
self.widget.choices = value
if django.VERSION < (5, 0):

def _set_choices(self, value):
"""
Also update the widget's choices.
"""
super()._set_choices(value)
self.widget.choices = value


_Choice = Tuple[Any, str]
Expand Down Expand Up @@ -278,7 +287,11 @@ def __init__(self, *args: Any, **kwargs: Any):
self.multiple = kwargs.pop("multiple", None)
self.multiple_unique = kwargs.pop("multiple_unique", True)
self.multiple_sort = kwargs.pop("multiple_sort", True)
kwargs["choices"] = self.countries
if django.VERSION >= (5, 0):
# Use new lazy callable support
kwargs["choices"] = lambda: self.countries
else:
kwargs["choices"] = self.countries
if "max_length" not in kwargs:
# Allow explicit max_length so migrations can correctly identify
# changes in the multiple CountryField fields when new countries are
Expand Down Expand Up @@ -396,19 +409,45 @@ def deconstruct(self):
kwargs["countries"] = self.countries.__class__
return name, path, args, kwargs

def get_choices(self, include_blank=True, blank_choice=None, *args, **kwargs):
if blank_choice is None:
if django.VERSION >= (5, 0):

def get_choices(
self,
include_blank=True,
blank_choice=BLANK_CHOICE_DASH,
limit_choices_to=None,
ordering=(),
):
if self.multiple:
include_blank = False
if self.blank_label is None:
blank_choice = BLANK_CHOICE_DASH
else:
blank_choice = [("", self.blank_label)]
if self.multiple:
include_blank = False
return super().get_choices(
include_blank=include_blank, blank_choice=blank_choice, *args, **kwargs
)
return super().get_choices(
include_blank=include_blank,
blank_choice=blank_choice,
limit_choices_to=limit_choices_to,
ordering=ordering,
)

else:

def get_choices( # type: ignore [misc]
self, include_blank=True, blank_choice=None, *args, **kwargs
):
if blank_choice is None:
if self.blank_label is None:
blank_choice = BLANK_CHOICE_DASH
else:
blank_choice = [("", self.blank_label)]
if self.multiple:
include_blank = False
return super().get_choices(
include_blank=include_blank, blank_choice=blank_choice, *args, **kwargs
)

get_choices = lazy(get_choices, list)
get_choices = lazy(get_choices, list)

def formfield(self, **kwargs):
kwargs.setdefault(
Expand Down
7 changes: 6 additions & 1 deletion django_countries/filters.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import django
from django.contrib import admin
from django.utils.encoding import force_str
from django.utils.translation import gettext_lazy as _
Expand All @@ -22,8 +23,12 @@ def choices(self, changelist):
"display": _("All"),
}
for lookup, title in self.lookup_choices(changelist):
if django.VERSION >= (5, 0):
selected = force_str(lookup) in value
else:
selected = force_str(lookup) == value
yield {
"selected": value == force_str(lookup),
"selected": selected,
"query_string": changelist.get_query_string(
{self.field.name: lookup}, []
),
Expand Down
43 changes: 24 additions & 19 deletions django_countries/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from typing import List, Union
from urllib import parse as urlparse

import django
from django.forms import widgets
from django.utils.functional import Promise
from django.utils.html import escape
Expand All @@ -20,31 +21,35 @@


class LazyChoicesMixin:
def get_choices(self) -> ChoiceList:
"""
When it's time to get the choices, if it was a lazy then figure it out
now and memoize the result.
"""
if isinstance(self._choices, Promise):
self._choices: ChoiceList = list(self._choices)
return self._choices
if django.VERSION < (5, 0):

def set_choices(self, value: ChoiceList):
self._set_choices(value)
def get_choices(self) -> ChoiceList:
"""
When it's time to get the choices, if it was a lazy then figure it out
now and memoize the result.
"""
if isinstance(self._choices, Promise):
self._choices: ChoiceList = list(self._choices)
return self._choices

choices = property(get_choices, set_choices)
def set_choices(self, value: ChoiceList):
self._set_choices(value)

def _set_choices(self, value: ChoiceList):
self._choices = value
choices = property(get_choices, set_choices)

def _set_choices(self, value: ChoiceList):
self._choices = value


class LazySelectMixin(LazyChoicesMixin):
def __deepcopy__(self, memo):
obj = copy.copy(self)
obj.attrs = self.attrs.copy()
obj.choices = copy.copy(self._choices)
memo[id(self)] = obj
return obj
if django.VERSION < (5, 0):

def __deepcopy__(self, memo):
obj = copy.copy(self)
obj.attrs = self.attrs.copy()
obj.choices = copy.copy(self._choices)
memo[id(self)] = obj
return obj


class LazySelect(LazySelectMixin, widgets.Select): # type: ignore
Expand Down
2 changes: 2 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ classifiers =
Framework :: Django :: 3.2
Framework :: Django :: 4.0
Framework :: Django :: 4.1
Framework :: Django :: 4.2
Framework :: Django :: 5.0
project_urls =
Change Log = https://github.com/SmileyChris/django-countries/blob/main/CHANGES.rst
Source Code = https://github.com/SmileyChris/django-countries
Expand Down
2 changes: 1 addition & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ deps =
latest: Django==5.*
latest: graphene-django==3.0.*
depends = coverage_setup
commands = coverage run -m pytest
commands = coverage run -m pytest {posargs}

[testenv:readme]
skip_install = True
Expand Down

0 comments on commit 8d8af20

Please sign in to comment.