diff --git a/src/pretix/base/forms/questions.py b/src/pretix/base/forms/questions.py index 3645c5381..328387322 100644 --- a/src/pretix/base/forms/questions.py +++ b/src/pretix/base/forms/questions.py @@ -41,6 +41,7 @@ from pretix.base.settings import ( ) from pretix.base.templatetags.rich_text import rich_text from pretix.control.forms import SplitDateTimeField +from pretix.helpers.countries import CachedCountries from pretix.helpers.escapejson import escapejson_attr from pretix.helpers.i18n import get_format_without_seconds from pretix.presale.signals import question_form_fields @@ -297,7 +298,9 @@ class BaseQuestionsForm(forms.Form): }), ) country = (cartpos.country if cartpos else orderpos.country) or guess_country(event) - self.fields['country'] = CountryField().formfield( + self.fields['country'] = CountryField( + countries=CachedCountries + ).formfield( required=event.settings.attendee_addresses_required and not self.all_optional, label=_('Country'), initial=country, @@ -380,7 +383,9 @@ class BaseQuestionsForm(forms.Form): initial=initial.answer if initial else None, ) elif q.type == Question.TYPE_COUNTRYCODE: - field = CountryField().formfield( + field = CountryField( + countries=CachedCountries + ).formfield( label=label, required=required, help_text=help_text, widget=forms.Select, @@ -575,6 +580,8 @@ class BaseInvoiceAddressForm(forms.ModelForm): if not event.settings.invoice_address_vatid: del self.fields['vat_id'] + self.fields['country'].choices = CachedCountries() + c = [('', pgettext_lazy('address', 'Select state'))] fprefix = self.prefix + '-' if self.prefix else '' cc = None diff --git a/src/pretix/base/models/orders.py b/src/pretix/base/models/orders.py index f854d3e79..b79b668e1 100644 --- a/src/pretix/base/models/orders.py +++ b/src/pretix/base/models/orders.py @@ -44,6 +44,7 @@ from pretix.base.services.locking import NoLockManager from pretix.base.settings import PERSON_NAME_SCHEMES from pretix.base.signals import order_gracefully_delete +from ...helpers.countries import CachedCountries from .base import LockModel, LoggedModel from .event import Event, SubEvent from .items import Item, ItemVariation, Question, QuestionOption, Quota @@ -2113,7 +2114,8 @@ class InvoiceAddress(models.Model): zipcode = models.CharField(max_length=30, verbose_name=_('ZIP code'), blank=False) city = models.CharField(max_length=255, verbose_name=_('City'), blank=False) country_old = models.CharField(max_length=255, verbose_name=_('Country'), blank=False) - country = CountryField(verbose_name=_('Country'), blank=False, blank_label=_('Select country')) + country = CountryField(verbose_name=_('Country'), blank=False, blank_label=_('Select country'), + countries=CachedCountries) state = models.CharField(max_length=255, verbose_name=pgettext_lazy('address', 'State'), blank=True) vat_id = models.CharField(max_length=255, blank=True, verbose_name=_('VAT ID'), help_text=_('Only for business customers within the EU.')) diff --git a/src/pretix/helpers/countries.py b/src/pretix/helpers/countries.py new file mode 100644 index 000000000..c23adce5b --- /dev/null +++ b/src/pretix/helpers/countries.py @@ -0,0 +1,29 @@ +from django.core.cache import cache +from django.utils.translation import get_language +from django_countries import Countries + + +class CachedCountries(Countries): + _cached_lists = {} + + def __iter__(self): + """ + Iterate through countries, sorted by name, but cache the results based on the locale. + django-countries performs a unicode-aware sorting based on pyuca which is incredibly + slow. + """ + cache_key = "countries:all:{}".format(get_language()) + if cache_key in self._cached_lists: + yield from self._cached_lists[cache_key] + return + + val = cache.get(cache_key) + if val: + self._cached_lists[cache_key] = val + yield from val + return + + val = list(super().__iter__()) + self._cached_lists[cache_key] = val + cache.set(cache_key, val, 3600 * 24 * 30) + yield from val