django-countries-5.2/0000755000175000017500000000000013250336536015103 5ustar chrischris00000000000000django-countries-5.2/setup.cfg0000644000175000017500000000305213250336536016724 0ustar chrischris00000000000000[metadata] name = django-countries version = 5.2 description = Provides a country field for Django models. long_description = file: README.rst, CHANGES.rst author = Chris Beaven author_email = smileychris@gmail.com url = https://github.com/SmileyChris/django-countries/ keywords = django, countries, flags license = MIT classifiers = Development Status :: 5 - Production/Stable Environment :: Web Environment Intended Audience :: Developers License :: OSI Approved :: MIT License Operating System :: OS Independent Programming Language :: Python Programming Language :: Python :: 2.7 Programming Language :: Python :: 3.4 Programming Language :: Python :: 3.5 Programming Language :: Python :: 3.6 Framework :: Django [options] zip_safe = False include_package_data = True packages = find: [options.extras_require] maintainer = transifex-client zest.releaser[recommended] django dev = tox django pytest pytest-django test = pytest pytest-django pytest-cov [bdist_wheel] universal = 1 [flake8] exclude = .tox, .git, __pycache__, build, dist [coverage:run] source = django_countries omit = django_countries/release.py django_countries/makesprite.py [zest.releaser] less-zeros = yes version-levels = 2 tag-format = v{version} tag-message = Version {version} tag-signing = yes date-format = %%-d %%B %%Y prereleaser.middle = django_countries.release.translations [check-manifest] ignore-bad-ideas = *.mo [tool:pytest] django_settings_module = django_countries.tests.settings filterwarnings = module [egg_info] tag_build = tag_date = 0 django-countries-5.2/django_countries.egg-info/0000755000175000017500000000000013250336536022132 5ustar chrischris00000000000000django-countries-5.2/django_countries.egg-info/dependency_links.txt0000644000175000017500000000000113250336536026200 0ustar chrischris00000000000000 django-countries-5.2/django_countries.egg-info/not-zip-safe0000644000175000017500000000000113250336536024360 0ustar chrischris00000000000000 django-countries-5.2/django_countries.egg-info/PKG-INFO0000644000175000017500000006304013250336536023232 0ustar chrischris00000000000000Metadata-Version: 1.1 Name: django-countries Version: 5.2 Summary: Provides a country field for Django models. Home-page: https://github.com/SmileyChris/django-countries/ Author: Chris Beaven Author-email: smileychris@gmail.com License: MIT Description-Content-Type: UNKNOWN Description: ================ Django Countries ================ .. image:: https://api.travis-ci.org/SmileyChris/django-countries.svg?branch=master :alt: Build Status :target: http://travis-ci.org/SmileyChris/django-countries A Django application that provides country choices for use with forms, flag icons static files, and a country field for models. Installation ============ 1. ``pip install django-countries`` 2. Add ``django_countries`` to ``INSTALLED_APPS`` For more accurate sorting of translated country names, install the optional pyuca_ package. .. _pyuca: https://pypi.python.org/pypi/pyuca/ CountryField ============ A country field for Django models that provides all ISO 3166-1 countries as choices. ``CountryField`` is based on Django's ``CharField``, providing choices corresponding to the official ISO 3166-1 list of countries (with a default ``max_length`` of 2). Consider the following model using a ``CountryField``: .. code:: python from django.db import models from django_countries.fields import CountryField class Person(models.Model): name = models.CharField(max_length=100) country = CountryField() Any ``Person`` instance will have a ``country`` attribute that you can use to get details of the person's country: .. code:: python >>> person = Person(name='Chris', country='NZ') >>> person.country Country(code='NZ') >>> person.country.name 'New Zealand' >>> person.country.flag '/static/flags/nz.gif' This object (``person.country`` in the example) is a ``Country`` instance, which is described below. Use ``blank_label`` to set the label for the initial blank choice shown in forms: .. code:: python country = CountryField(blank_label='(select country)') Multi-choice ------------ This field can also allow multiple selections of countries (saved as a comma separated string). The field will always output a list of countries in this mode. For example: .. code:: python class Incident(models.Model): title = models.CharField(max_length=100) countries = CountryField(multiple=True) >>> for country in Incident.objects.get(title='Pavlova dispute').countries: ... print(country.name) Australia New Zealand The ``Country`` object ---------------------- An object used to represent a country, instanciated with a two character country code. It can be compared to other objects as if it was a string containing the country code and when evaluated as text, returns the country code. name Contains the full country name. flag Contains a URL to the flag. If you page could have lots of different flags then consider using ``flag_css`` instead to avoid excessive HTTP requests. flag_css Output the css classes needed to display an HTML element as the correct flag from within a single sprite image that contains all flags. For example: .. code:: jinja For multiple flag resolutions, use ``sprite-hq.css`` instead and add the ``flag2x``, ``flag3x``, or ``flag4x`` class. For example: .. code:: jinja Normal: Bigger: You might also want to consider using ``aria-label`` for better accessibility: .. code:: jinja unicode_flag A unicode glyph for the flag for this country. Currently well-supported in iOS and OS X. See https://en.wikipedia.org/wiki/Regional_Indicator_Symbol for details. alpha3 The three letter country code for this country. numeric The numeric country code for this country (as an integer). numeric_padded The numeric country code as a three character 0-padded string. ``CountrySelectWidget`` ----------------------- A widget is included that can show the flag image after the select box (updated with JavaScript when the selection changes). When you create your form, you can use this custom widget like normal: .. code:: python from django_countries.widgets import CountrySelectWidget class PersonForm(forms.ModelForm): class Meta: model = models.Person fields = ('name', 'country') widgets = {'country': CountrySelectWidget()} Pass a ``layout`` text argument to the widget to change the positioning of the flag and widget. The default layout is: .. code:: python '{widget}' Custom forms ============ If you want to use the countries in a custom form, use the following custom field to ensure the translatable strings for the country choices are left lazy until the widget renders: .. code:: python from django_countries.fields import LazyTypedChoiceField class CustomForm(forms.Form): country = LazyTypedChoiceField(choices=countries) You can also use the CountrySelectWidget_ as the widget for this field if you want the flag image after the select box. Get the countries from Python ============================= Use the ``django_countries.countries`` object instance as an iterator of ISO 3166-1 country codes and names (sorted by name). For example: .. code:: python >>> from django_countries import countries >>> dict(countries)['NZ'] 'New Zealand' >>> for code, name in list(countries)[:3]: ... print("{name} ({code})".format(name=name, code=code)) ... Afghanistan (AF) Åland Islands (AX) Albania (AL) Country names are translated using Django's standard ``ugettext``. If you would like to help by adding a translation, please visit https://www.transifex.com/projects/p/django-countries/ Template Tags ============= If you have your country code stored in a different place than a `CountryField` you can use the template tag to get a `Country` object and have access to all of its properties: .. code:: jinja {% load countries %} {% get_country 'BR' as country %} {{ country.name }} If you need a list of countries, there's also a simple tag for that: .. code:: jinja {% load countries %} {% get_countries as countries %} Customization ============= Customize the country list -------------------------- Country names are taken from the official ISO 3166-1 list. If your project requires the use of alternative names, the inclusion or exclusion of specific countries then use the ``COUNTRIES_OVERRIDE`` setting. A dictionary of names to override the defaults. Note that you will need to handle translation of customised country names. Setting a country's name to ``None`` will exclude it from the country list. For example: .. code:: python from django.utils.translation import ugettext_lazy as _ COUNTRIES_OVERRIDE = { 'NZ': _('Middle Earth'), 'AU': None } If you have a specific list of countries that should be used, use ``COUNTRIES_ONLY``: .. code:: python COUNTRIES_ONLY = ['NZ', 'AU'] or to specify your own country names, use a dictionary or two-tuple list (string items will use the standard country name): .. code:: python COUNTRIES_ONLY = [ 'US', 'GB', ('NZ', _('Middle Earth')), ('AU', _('Desert')), ] Show certain countries first ---------------------------- Provide a list of country codes as the ``COUNTRIES_FIRST`` setting and they will be shown first in the countries list (in the order specified) before all the alphanumerically sorted countries. If you want to sort these initial countries too, set the ``COUNTRIES_FIRST_SORT`` setting to ``True``. By default, these initial countries are not repeated again in the alphanumerically sorted list. If you would like them to be repeated, set the ``COUNTRIES_FIRST_REPEAT`` setting to ``True``. Finally, you can optionally separate these 'first' countries with an empty choice by providing the choice label as the ``COUNTRIES_FIRST_BREAK`` setting. Customize the flag URL ---------------------- The ``COUNTRIES_FLAG_URL`` setting can be used to set the url for the flag image assets. It defaults to:: COUNTRIES_FLAG_URL = 'flags/{code}.gif' The URL can be relative to the STATIC_URL setting, or an absolute URL. The location is parsed using Python's string formatting and is passed the following arguments: * code * code_upper For example: ``COUNTRIES_FLAG_URL = 'flags/16x10/{code_upper}.png'`` No checking is done to ensure that a static flag actually exists. Alternatively, you can specify a different URL on a specific ``CountryField``: .. code:: python class Person(models.Model): name = models.CharField(max_length=100) country = CountryField( countries_flag_url='//flags.example.com/{code}.png') Single field customization -------------------------- To customize an individual field, rather than rely on project level settings, create a ``Countries`` subclass which overrides settings. To override a setting, give the class an attribute matching the lowercased setting without the ``COUNTRIES_`` prefix. Then just reference this class in a field. For example, this ``CountryField`` uses a custom country list that only includes the G8 countries: .. code:: python from django_countries import Countries class G8Countries(Countries): only = [ 'CA', 'FR', 'DE', 'IT', 'JP', 'RU', 'GB', ('EU', _('European Union')) ] class Vote(models.Model): country = CountryField(countries=G8Countries) approve = models.BooleanField() Django Rest Framework ===================== Django Countries ships with a ``CountryFieldMixin`` to make the `CountryField`_ model field compatible with DRF serializers. Use the following mixin with your model serializer: .. code:: python from django_countries.serializers import CountryFieldMixin class CountrySerializer(CountryFieldMixin, serializers.ModelSerializer): class Meta: model = models.Person fields = ('name', 'email', 'country') This mixin handles both standard and `multi-choice`_ country fields. Django Rest Framework field --------------------------- For lower level use (or when not dealing with model fields), you can use the included ``CountryField`` serializer field. For example: .. code:: python from django_countries.serializer_fields import CountryField class CountrySerializer(serializers.Serializer): country = CountryField() You can optionally instantiate the field with ``countries`` with a custom Countries_ instance. .. _Countries: `Single field customization`_ OPTIONS request --------------- When you request OPTIONS against a resource (using the DRF `metadata support`_) the countries will be returned in the response as choices: .. code:: text OPTIONS /api/address/ HTTP/1.1 HTTP/1.1 200 OK Content-Type: application/json Allow: GET, POST, HEAD, OPTIONS { "actions": { "POST": { "country": { "type": "choice", "label": "Country", "choices": [ { "display_name": "Australia", "value": "AU" }, [...] { "display_name": "United Kingdom", "value": "GB" } ] } } .. _metadata support: http://www.django-rest-framework.org/api-guide/metadata/ REST output format ------------------ By default, the field will output just the country code. If you would rather have more verbose output, instantiate the field with ``country_dict=True``, which will result in the field having the following output structure:: {"code": "NZ", "name": "New Zealand"} Either the code or this dict output structure are acceptable as input irregardless of the ``country_dict`` argument's value. ========== Change Log ========== This log shows interesting changes that happen for each version, latest versions first. It can be assumed that translations have been updated each release, and any new translations added. 5.2 (9 March 2018) ================== - Ensure Django 2.1 compatibility for ``CountrySelectWidget``. - Fix regression introduced into 5.1 when using Django 1.8 and certain queryset lookup types (like ``__in``). 5.1.1 (31 January 2018) ======================= - Fix some translations that were included in 5.1 but not compiled. 5.1 (30 January 2018) ===================== * Tests now also cover Django Rest Framework 3.7 and Django 2.0. * Allow for creating country fields using (valid) alpha-3 or numeric codes. * Fix migration error with blank default (thanks Jens Diemer). * Add a ``{% get_countries %}`` template tag (thanks Matija Čvrk). 5.0 (10 October 2017) ===================== * No longer allow ``multiple=True`` and ``null=True`` together. This causes problems saving the field, and ``null`` shouldn't really be used anyway because the country field is a subclass of ``CharField``. 4.6 (16 June 2017) ================== * Add a ``CountryFieldMixin`` Django Rest Framework serializer mixin that automatically picks the right field type for a ``CountryField`` (both single and multi-choice). * Validation for Django Rest Framework field (thanks Simon Meers). * Allow case-insensitive ``.by_name()`` matching (thanks again, Simon). * Ensure a multiple-choice ``CountryField.max_length`` is enough to hold all countries. * Fix inefficient pickling of countries (thanks Craig de Stigter for the report and tests). * Stop adding a blank choice when dealing with a multi-choice ``CountryField``. * Tests now cover multiple Django Rest Framework versions (back to 3.3). 4.6.1 ----- * Fix invalid reStructuredText in CHANGES. 4.6.2 ----- * Use transparency layer for flag sprites. 4.5 (18 April 2017) =================== * Change rest framework field to be based on ``ChoiceField``. * Allow for the rest framework field to deserialize by full country name (specifically the English name for now). 4.4 (6 April 2017) ================== * Fix for broken CountryField on certain models in Django 1.11. Thanks aktiur for the test case. * Update tests to cover Django 1.11 4.3 (29 March 2017) =================== * Handle "Czechia" translations in a nicer way (fall back to "Czech Republic" until new translations are available). * Fix for an import error in Django 1.9+ due to use of non-lazy ``ugettext`` in the django-countries custom admin filter. * Back to 100% test coverage. 4.2 (10 March 2017) =================== * Add sprite flag files (and ``Country.flag_css`` property) to help minimize HTTP requests. 4.1 (22 February 2017) ====================== * Better default Django admin filter when filtering a country field in a ``ModelAdmin``. * Fix settings to support Django 1.11 * Fix when using a model instance with a deferred country field. * Allow ``CountryField`` to handle multiple countries at once! * Allow CountryField to still work if Deferred. * Fix a field with customized country list. Thanks pilmie! 4.0 (16 August 2016) ==================== Django supported versions are now 1.8+ * Drop legacy code * Fix tests, 100% coverage * IOS / OSX unicode flags function * Fix widget choices on Django 1.9+ * Add ``COUNTRIES_FIRST_SORT``. Thanks Edraak! 4.0.1 ----- * Fix tests for ``COUNTRIES_FIRST_SORT`` (feature still worked, tests didn't). 3.4 (22 October 2015) ===================== * Extend test suite to cover Django 1.8 * Fix XSS escaping issue in CountrySelectWidget * Common name changes: fix typo of Moldova, add United Kingdom * Add ``{% get_country %}`` template tag. * New ``CountryField`` Django Rest Framework serializer field. 3.4.1 ----- * Fix minor packaging error. 3.3 (30 Mar 2015) ================= * Add the attributes to ``Countries`` class that can override the default settings. * CountriesField can now be passed a custom countries subclass to use, which combined with the previous change allows for different country choices for different fields. * Allow ``COUNTRIES_ONLY`` to also accept just country codes in its list (rather than only two-tuples), looking up the translatable country name from the full country list. * Fix Montenegro flag size (was 12px high rather than the standard 11px). * Fix outdated ISO country name formatting for Bolivia, Gambia, Holy See, Iran, Micronesia, and Venezuela. 3.2 (24 Feb 2015) ================= * Fixes initial iteration failing for a fresh ``Countries`` object. * Fix widget's flag URLs (and use ensure widget is HTML encoded safely). * Add ``countries.by_name(country, language='en')`` method, allowing lookup of a country code by its full country name. Thanks Josh Schneier. 3.1 (15 Jan 2015) ================= * Start change log :) * Add a ``COUNTRIES_FIRST`` setting (and some other related ones) to allow for specific countries to be shown before the entire alphanumeric list. * Add a ``blank_label`` argument to ``CountryField`` to allow customization of the label shown in the initial blank choice shown in the select widget. 3.1.1 (15 Jan 2015) ------------------- * Packaging fix (``CHANGES.rst`` wasn't in the manifest) 3.0 (22 Oct 2014) ================= Django supported versions are now 1.4 (LTS) and 1.6+ * Add ``COUNTRIES_ONLY`` setting to restrict to a specific list of countries. * Optimize country name translations to avoid exessive translation calls that were causing a notable performance impact. * PyUCA integration, allowing for more accurate sorting across all locales. Also, a better sorting method when PyUCA isn't installed. * Better tests (now at 100% test coverage). * Add a ``COUNTRIES_FLAG_URL`` setting to allow custom flag urls. * Support both IOC and numeric country codes, allowing more flexible lookup of countries and specific code types. * Field descriptor now returns ``None`` if no country matches (*reverted in v3.0.1*) 3.0.1 (27 Oct 2014) ------------------- * Revert descriptor to always return a Country object. * Fix the ``CountryField`` widget choices appearing empty due to a translation change in v3.0. 3.0.2 (29 Dec 2014) ------------------- * Fix ``CountrySelectWidget`` failing when used with a model form that is passed a model instance. 2.1 (24 Mar 2014) ================= * Add IOC (3 letter) country codes. * Fix bug when loading fixtures. 2.1.1 (28 Mar 2014) ------------------- * Fix issue with translations getting evaluated early. 2.1.2 (28 Mar 2014) ------------------- * Fix Python 3 compatibility. 2.0 (18 Feb 2014) ================= This is the first entry to the change log. The previous was 1.5, released 19 Nov 2012. * Optimized flag images, adding flags missing from original source. * Better storage of settings and country list. * New country list format for fields. * Better tests. * Changed ``COUNTRIES_FLAG_STATIC`` setting to ``COUNTRIES_FLAG_URL``. Keywords: django,countries,flags Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Web Environment Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Framework :: Django django-countries-5.2/django_countries.egg-info/top_level.txt0000644000175000017500000000002113250336536024655 0ustar chrischris00000000000000django_countries django-countries-5.2/django_countries.egg-info/requires.txt0000644000175000017500000000022013250336536024524 0ustar chrischris00000000000000 [dev] tox django pytest pytest-django [maintainer] transifex-client zest.releaser[recommended] django [test] pytest pytest-django pytest-cov django-countries-5.2/django_countries.egg-info/SOURCES.txt0000644000175000017500000003335613250336536024030 0ustar chrischris00000000000000CHANGES.rst LICENSE MANIFEST.in README.rst setup.cfg setup.py tox.ini .tx/config django_countries/__init__.py django_countries/base.py django_countries/conf.py django_countries/data.py django_countries/fields.py django_countries/filters.py django_countries/ioc_data.py django_countries/makesprite.py django_countries/models.py django_countries/release.py django_countries/serializer_fields.py django_countries/serializers.py django_countries/widgets.py django_countries.egg-info/PKG-INFO django_countries.egg-info/SOURCES.txt django_countries.egg-info/dependency_links.txt django_countries.egg-info/not-zip-safe django_countries.egg-info/requires.txt django_countries.egg-info/top_level.txt django_countries/locale/ar/LC_MESSAGES/django.mo django_countries/locale/ar/LC_MESSAGES/django.po django_countries/locale/bg/LC_MESSAGES/django.mo django_countries/locale/bg/LC_MESSAGES/django.po django_countries/locale/ca/LC_MESSAGES/django.mo django_countries/locale/ca/LC_MESSAGES/django.po django_countries/locale/cs/LC_MESSAGES/django.mo django_countries/locale/cs/LC_MESSAGES/django.po django_countries/locale/de/LC_MESSAGES/django.mo django_countries/locale/de/LC_MESSAGES/django.po django_countries/locale/el/LC_MESSAGES/django.mo django_countries/locale/el/LC_MESSAGES/django.po django_countries/locale/en/LC_MESSAGES/django.mo django_countries/locale/en/LC_MESSAGES/django.po django_countries/locale/eo/LC_MESSAGES/django.mo django_countries/locale/eo/LC_MESSAGES/django.po django_countries/locale/es/LC_MESSAGES/django.mo django_countries/locale/es/LC_MESSAGES/django.po django_countries/locale/et/LC_MESSAGES/django.mo django_countries/locale/et/LC_MESSAGES/django.po django_countries/locale/eu/LC_MESSAGES/django.mo django_countries/locale/eu/LC_MESSAGES/django.po django_countries/locale/eu_ES/LC_MESSAGES/django.mo django_countries/locale/eu_ES/LC_MESSAGES/django.po django_countries/locale/fa/LC_MESSAGES/django.mo django_countries/locale/fa/LC_MESSAGES/django.po django_countries/locale/fi/LC_MESSAGES/django.mo django_countries/locale/fi/LC_MESSAGES/django.po django_countries/locale/fr/LC_MESSAGES/django.mo django_countries/locale/fr/LC_MESSAGES/django.po django_countries/locale/hr/LC_MESSAGES/django.mo django_countries/locale/hr/LC_MESSAGES/django.po django_countries/locale/hu/LC_MESSAGES/django.mo django_countries/locale/hu/LC_MESSAGES/django.po django_countries/locale/it/LC_MESSAGES/django.mo django_countries/locale/it/LC_MESSAGES/django.po django_countries/locale/ja/LC_MESSAGES/django.mo django_countries/locale/ja/LC_MESSAGES/django.po django_countries/locale/ko_KR/LC_MESSAGES/django.mo django_countries/locale/ko_KR/LC_MESSAGES/django.po django_countries/locale/lt/LC_MESSAGES/django.mo django_countries/locale/lt/LC_MESSAGES/django.po django_countries/locale/lv/LC_MESSAGES/django.mo django_countries/locale/lv/LC_MESSAGES/django.po django_countries/locale/nb/LC_MESSAGES/django.mo django_countries/locale/nb/LC_MESSAGES/django.po django_countries/locale/nl/LC_MESSAGES/django.mo django_countries/locale/nl/LC_MESSAGES/django.po django_countries/locale/pl/LC_MESSAGES/django.mo django_countries/locale/pl/LC_MESSAGES/django.po django_countries/locale/pt_BR/LC_MESSAGES/django.mo django_countries/locale/pt_BR/LC_MESSAGES/django.po django_countries/locale/pt_PT/LC_MESSAGES/django.mo django_countries/locale/pt_PT/LC_MESSAGES/django.po django_countries/locale/ru/LC_MESSAGES/django.mo django_countries/locale/ru/LC_MESSAGES/django.po django_countries/locale/sk/LC_MESSAGES/django.mo django_countries/locale/sk/LC_MESSAGES/django.po django_countries/locale/sv/LC_MESSAGES/django.mo django_countries/locale/sv/LC_MESSAGES/django.po django_countries/locale/tr_TR/LC_MESSAGES/django.mo django_countries/locale/tr_TR/LC_MESSAGES/django.po django_countries/locale/uk/LC_MESSAGES/django.mo django_countries/locale/uk/LC_MESSAGES/django.po django_countries/locale/zh-Hans/LC_MESSAGES/django.mo django_countries/locale/zh-Hans/LC_MESSAGES/django.po django_countries/locale/zh_CN/LC_MESSAGES/django.mo django_countries/locale/zh_CN/LC_MESSAGES/django.po django_countries/static/flags/__.gif django_countries/static/flags/ad.gif django_countries/static/flags/ae.gif django_countries/static/flags/af.gif django_countries/static/flags/ag.gif django_countries/static/flags/ai.gif django_countries/static/flags/al.gif django_countries/static/flags/am.gif django_countries/static/flags/ao.gif django_countries/static/flags/aq.gif django_countries/static/flags/ar.gif django_countries/static/flags/as.gif django_countries/static/flags/at.gif django_countries/static/flags/au.gif django_countries/static/flags/aw.gif django_countries/static/flags/ax.gif django_countries/static/flags/az.gif django_countries/static/flags/ba.gif django_countries/static/flags/bb.gif django_countries/static/flags/bd.gif django_countries/static/flags/be.gif django_countries/static/flags/bf.gif django_countries/static/flags/bg.gif django_countries/static/flags/bh.gif django_countries/static/flags/bi.gif django_countries/static/flags/bj.gif django_countries/static/flags/bl.gif django_countries/static/flags/bm.gif django_countries/static/flags/bn.gif django_countries/static/flags/bo.gif django_countries/static/flags/bq.gif django_countries/static/flags/br.gif django_countries/static/flags/bs.gif django_countries/static/flags/bt.gif django_countries/static/flags/bv.gif django_countries/static/flags/bw.gif django_countries/static/flags/by.gif django_countries/static/flags/bz.gif django_countries/static/flags/ca.gif django_countries/static/flags/cc.gif django_countries/static/flags/cd.gif django_countries/static/flags/cf.gif django_countries/static/flags/cg.gif django_countries/static/flags/ch.gif django_countries/static/flags/ci.gif django_countries/static/flags/ck.gif django_countries/static/flags/cl.gif django_countries/static/flags/cm.gif django_countries/static/flags/cn.gif django_countries/static/flags/co.gif django_countries/static/flags/cr.gif django_countries/static/flags/cu.gif django_countries/static/flags/cv.gif django_countries/static/flags/cw.gif django_countries/static/flags/cx.gif django_countries/static/flags/cy.gif django_countries/static/flags/cz.gif django_countries/static/flags/de.gif django_countries/static/flags/dj.gif django_countries/static/flags/dk.gif django_countries/static/flags/dm.gif django_countries/static/flags/do.gif django_countries/static/flags/dz.gif django_countries/static/flags/ec.gif django_countries/static/flags/ee.gif django_countries/static/flags/eg.gif django_countries/static/flags/eh.gif django_countries/static/flags/er.gif django_countries/static/flags/es.gif django_countries/static/flags/et.gif django_countries/static/flags/eu.gif django_countries/static/flags/fi.gif django_countries/static/flags/fj.gif django_countries/static/flags/fk.gif django_countries/static/flags/fm.gif django_countries/static/flags/fo.gif django_countries/static/flags/fr.gif django_countries/static/flags/ga.gif django_countries/static/flags/gb.gif django_countries/static/flags/gd.gif django_countries/static/flags/ge.gif django_countries/static/flags/gf.gif django_countries/static/flags/gg.gif django_countries/static/flags/gh.gif django_countries/static/flags/gi.gif django_countries/static/flags/gl.gif django_countries/static/flags/gm.gif django_countries/static/flags/gn.gif django_countries/static/flags/gp.gif django_countries/static/flags/gq.gif django_countries/static/flags/gr.gif django_countries/static/flags/gs.gif django_countries/static/flags/gt.gif django_countries/static/flags/gu.gif django_countries/static/flags/gw.gif django_countries/static/flags/gy.gif django_countries/static/flags/hk.gif django_countries/static/flags/hm.gif django_countries/static/flags/hn.gif django_countries/static/flags/hr.gif django_countries/static/flags/ht.gif django_countries/static/flags/hu.gif django_countries/static/flags/id.gif django_countries/static/flags/ie.gif django_countries/static/flags/il.gif django_countries/static/flags/im.gif django_countries/static/flags/in.gif django_countries/static/flags/io.gif django_countries/static/flags/iq.gif django_countries/static/flags/ir.gif django_countries/static/flags/is.gif django_countries/static/flags/it.gif django_countries/static/flags/je.gif django_countries/static/flags/jm.gif django_countries/static/flags/jo.gif django_countries/static/flags/jp.gif django_countries/static/flags/ke.gif django_countries/static/flags/kg.gif django_countries/static/flags/kh.gif django_countries/static/flags/ki.gif django_countries/static/flags/km.gif django_countries/static/flags/kn.gif django_countries/static/flags/kp.gif django_countries/static/flags/kr.gif django_countries/static/flags/kw.gif django_countries/static/flags/ky.gif django_countries/static/flags/kz.gif django_countries/static/flags/la.gif django_countries/static/flags/lb.gif django_countries/static/flags/lc.gif django_countries/static/flags/li.gif django_countries/static/flags/lk.gif django_countries/static/flags/lr.gif django_countries/static/flags/ls.gif django_countries/static/flags/lt.gif django_countries/static/flags/lu.gif django_countries/static/flags/lv.gif django_countries/static/flags/ly.gif django_countries/static/flags/ma.gif django_countries/static/flags/mc.gif django_countries/static/flags/md.gif django_countries/static/flags/me.gif django_countries/static/flags/mf.gif django_countries/static/flags/mg.gif django_countries/static/flags/mh.gif django_countries/static/flags/mk.gif django_countries/static/flags/ml.gif django_countries/static/flags/mm.gif django_countries/static/flags/mn.gif django_countries/static/flags/mo.gif django_countries/static/flags/mp.gif django_countries/static/flags/mq.gif django_countries/static/flags/mr.gif django_countries/static/flags/ms.gif django_countries/static/flags/mt.gif django_countries/static/flags/mu.gif django_countries/static/flags/mv.gif django_countries/static/flags/mw.gif django_countries/static/flags/mx.gif django_countries/static/flags/my.gif django_countries/static/flags/mz.gif django_countries/static/flags/na.gif django_countries/static/flags/nc.gif django_countries/static/flags/ne.gif django_countries/static/flags/nf.gif django_countries/static/flags/ng.gif django_countries/static/flags/ni.gif django_countries/static/flags/nl.gif django_countries/static/flags/no.gif django_countries/static/flags/np.gif django_countries/static/flags/nr.gif django_countries/static/flags/nu.gif django_countries/static/flags/nz.gif django_countries/static/flags/om.gif django_countries/static/flags/pa.gif django_countries/static/flags/pe.gif django_countries/static/flags/pf.gif django_countries/static/flags/pg.gif django_countries/static/flags/ph.gif django_countries/static/flags/pk.gif django_countries/static/flags/pl.gif django_countries/static/flags/pm.gif django_countries/static/flags/pn.gif django_countries/static/flags/pr.gif django_countries/static/flags/ps.gif django_countries/static/flags/pt.gif django_countries/static/flags/pw.gif django_countries/static/flags/py.gif django_countries/static/flags/qa.gif django_countries/static/flags/re.gif django_countries/static/flags/ro.gif django_countries/static/flags/rs.gif django_countries/static/flags/ru.gif django_countries/static/flags/rw.gif django_countries/static/flags/sa.gif django_countries/static/flags/sb.gif django_countries/static/flags/sc.gif django_countries/static/flags/sd.gif django_countries/static/flags/se.gif django_countries/static/flags/sg.gif django_countries/static/flags/sh.gif django_countries/static/flags/si.gif django_countries/static/flags/sj.gif django_countries/static/flags/sk.gif django_countries/static/flags/sl.gif django_countries/static/flags/sm.gif django_countries/static/flags/sn.gif django_countries/static/flags/so.gif django_countries/static/flags/sprite-hq.css django_countries/static/flags/sprite-hq.png django_countries/static/flags/sprite.css django_countries/static/flags/sprite.png django_countries/static/flags/sr.gif django_countries/static/flags/ss.gif django_countries/static/flags/st.gif django_countries/static/flags/sv.gif django_countries/static/flags/sx.gif django_countries/static/flags/sy.gif django_countries/static/flags/sz.gif django_countries/static/flags/tc.gif django_countries/static/flags/td.gif django_countries/static/flags/tf.gif django_countries/static/flags/tg.gif django_countries/static/flags/th.gif django_countries/static/flags/tj.gif django_countries/static/flags/tk.gif django_countries/static/flags/tl.gif django_countries/static/flags/tm.gif django_countries/static/flags/tn.gif django_countries/static/flags/to.gif django_countries/static/flags/tr.gif django_countries/static/flags/tt.gif django_countries/static/flags/tv.gif django_countries/static/flags/tw.gif django_countries/static/flags/tz.gif django_countries/static/flags/ua.gif django_countries/static/flags/ug.gif django_countries/static/flags/um.gif django_countries/static/flags/us.gif django_countries/static/flags/uy.gif django_countries/static/flags/uz.gif django_countries/static/flags/va.gif django_countries/static/flags/vc.gif django_countries/static/flags/ve.gif django_countries/static/flags/vg.gif django_countries/static/flags/vi.gif django_countries/static/flags/vn.gif django_countries/static/flags/vu.gif django_countries/static/flags/wf.gif django_countries/static/flags/ws.gif django_countries/static/flags/ye.gif django_countries/static/flags/yt.gif django_countries/static/flags/za.gif django_countries/static/flags/zm.gif django_countries/static/flags/zw.gif django_countries/templatetags/__init__.py django_countries/templatetags/countries.py django_countries/tests/__init__.py django_countries/tests/custom_countries.py django_countries/tests/forms.py django_countries/tests/models.py django_countries/tests/settings.py django_countries/tests/test_admin_filters.py django_countries/tests/test_countries.py django_countries/tests/test_drf.py django_countries/tests/test_fields.py django_countries/tests/test_settings.py django_countries/tests/test_tags.py django_countries/tests/test_widgets.pydjango-countries-5.2/setup.py0000755000175000017500000000007413250336536016621 0ustar chrischris00000000000000#!/usr/bin/env python from setuptools import setup setup() django-countries-5.2/README.rst0000644000175000017500000002775013250336536016605 0ustar chrischris00000000000000================ Django Countries ================ .. image:: https://api.travis-ci.org/SmileyChris/django-countries.svg?branch=master :alt: Build Status :target: http://travis-ci.org/SmileyChris/django-countries A Django application that provides country choices for use with forms, flag icons static files, and a country field for models. Installation ============ 1. ``pip install django-countries`` 2. Add ``django_countries`` to ``INSTALLED_APPS`` For more accurate sorting of translated country names, install the optional pyuca_ package. .. _pyuca: https://pypi.python.org/pypi/pyuca/ CountryField ============ A country field for Django models that provides all ISO 3166-1 countries as choices. ``CountryField`` is based on Django's ``CharField``, providing choices corresponding to the official ISO 3166-1 list of countries (with a default ``max_length`` of 2). Consider the following model using a ``CountryField``: .. code:: python from django.db import models from django_countries.fields import CountryField class Person(models.Model): name = models.CharField(max_length=100) country = CountryField() Any ``Person`` instance will have a ``country`` attribute that you can use to get details of the person's country: .. code:: python >>> person = Person(name='Chris', country='NZ') >>> person.country Country(code='NZ') >>> person.country.name 'New Zealand' >>> person.country.flag '/static/flags/nz.gif' This object (``person.country`` in the example) is a ``Country`` instance, which is described below. Use ``blank_label`` to set the label for the initial blank choice shown in forms: .. code:: python country = CountryField(blank_label='(select country)') Multi-choice ------------ This field can also allow multiple selections of countries (saved as a comma separated string). The field will always output a list of countries in this mode. For example: .. code:: python class Incident(models.Model): title = models.CharField(max_length=100) countries = CountryField(multiple=True) >>> for country in Incident.objects.get(title='Pavlova dispute').countries: ... print(country.name) Australia New Zealand The ``Country`` object ---------------------- An object used to represent a country, instanciated with a two character country code. It can be compared to other objects as if it was a string containing the country code and when evaluated as text, returns the country code. name Contains the full country name. flag Contains a URL to the flag. If you page could have lots of different flags then consider using ``flag_css`` instead to avoid excessive HTTP requests. flag_css Output the css classes needed to display an HTML element as the correct flag from within a single sprite image that contains all flags. For example: .. code:: jinja For multiple flag resolutions, use ``sprite-hq.css`` instead and add the ``flag2x``, ``flag3x``, or ``flag4x`` class. For example: .. code:: jinja Normal: Bigger: You might also want to consider using ``aria-label`` for better accessibility: .. code:: jinja unicode_flag A unicode glyph for the flag for this country. Currently well-supported in iOS and OS X. See https://en.wikipedia.org/wiki/Regional_Indicator_Symbol for details. alpha3 The three letter country code for this country. numeric The numeric country code for this country (as an integer). numeric_padded The numeric country code as a three character 0-padded string. ``CountrySelectWidget`` ----------------------- A widget is included that can show the flag image after the select box (updated with JavaScript when the selection changes). When you create your form, you can use this custom widget like normal: .. code:: python from django_countries.widgets import CountrySelectWidget class PersonForm(forms.ModelForm): class Meta: model = models.Person fields = ('name', 'country') widgets = {'country': CountrySelectWidget()} Pass a ``layout`` text argument to the widget to change the positioning of the flag and widget. The default layout is: .. code:: python '{widget}' Custom forms ============ If you want to use the countries in a custom form, use the following custom field to ensure the translatable strings for the country choices are left lazy until the widget renders: .. code:: python from django_countries.fields import LazyTypedChoiceField class CustomForm(forms.Form): country = LazyTypedChoiceField(choices=countries) You can also use the CountrySelectWidget_ as the widget for this field if you want the flag image after the select box. Get the countries from Python ============================= Use the ``django_countries.countries`` object instance as an iterator of ISO 3166-1 country codes and names (sorted by name). For example: .. code:: python >>> from django_countries import countries >>> dict(countries)['NZ'] 'New Zealand' >>> for code, name in list(countries)[:3]: ... print("{name} ({code})".format(name=name, code=code)) ... Afghanistan (AF) Åland Islands (AX) Albania (AL) Country names are translated using Django's standard ``ugettext``. If you would like to help by adding a translation, please visit https://www.transifex.com/projects/p/django-countries/ Template Tags ============= If you have your country code stored in a different place than a `CountryField` you can use the template tag to get a `Country` object and have access to all of its properties: .. code:: jinja {% load countries %} {% get_country 'BR' as country %} {{ country.name }} If you need a list of countries, there's also a simple tag for that: .. code:: jinja {% load countries %} {% get_countries as countries %} Customization ============= Customize the country list -------------------------- Country names are taken from the official ISO 3166-1 list. If your project requires the use of alternative names, the inclusion or exclusion of specific countries then use the ``COUNTRIES_OVERRIDE`` setting. A dictionary of names to override the defaults. Note that you will need to handle translation of customised country names. Setting a country's name to ``None`` will exclude it from the country list. For example: .. code:: python from django.utils.translation import ugettext_lazy as _ COUNTRIES_OVERRIDE = { 'NZ': _('Middle Earth'), 'AU': None } If you have a specific list of countries that should be used, use ``COUNTRIES_ONLY``: .. code:: python COUNTRIES_ONLY = ['NZ', 'AU'] or to specify your own country names, use a dictionary or two-tuple list (string items will use the standard country name): .. code:: python COUNTRIES_ONLY = [ 'US', 'GB', ('NZ', _('Middle Earth')), ('AU', _('Desert')), ] Show certain countries first ---------------------------- Provide a list of country codes as the ``COUNTRIES_FIRST`` setting and they will be shown first in the countries list (in the order specified) before all the alphanumerically sorted countries. If you want to sort these initial countries too, set the ``COUNTRIES_FIRST_SORT`` setting to ``True``. By default, these initial countries are not repeated again in the alphanumerically sorted list. If you would like them to be repeated, set the ``COUNTRIES_FIRST_REPEAT`` setting to ``True``. Finally, you can optionally separate these 'first' countries with an empty choice by providing the choice label as the ``COUNTRIES_FIRST_BREAK`` setting. Customize the flag URL ---------------------- The ``COUNTRIES_FLAG_URL`` setting can be used to set the url for the flag image assets. It defaults to:: COUNTRIES_FLAG_URL = 'flags/{code}.gif' The URL can be relative to the STATIC_URL setting, or an absolute URL. The location is parsed using Python's string formatting and is passed the following arguments: * code * code_upper For example: ``COUNTRIES_FLAG_URL = 'flags/16x10/{code_upper}.png'`` No checking is done to ensure that a static flag actually exists. Alternatively, you can specify a different URL on a specific ``CountryField``: .. code:: python class Person(models.Model): name = models.CharField(max_length=100) country = CountryField( countries_flag_url='//flags.example.com/{code}.png') Single field customization -------------------------- To customize an individual field, rather than rely on project level settings, create a ``Countries`` subclass which overrides settings. To override a setting, give the class an attribute matching the lowercased setting without the ``COUNTRIES_`` prefix. Then just reference this class in a field. For example, this ``CountryField`` uses a custom country list that only includes the G8 countries: .. code:: python from django_countries import Countries class G8Countries(Countries): only = [ 'CA', 'FR', 'DE', 'IT', 'JP', 'RU', 'GB', ('EU', _('European Union')) ] class Vote(models.Model): country = CountryField(countries=G8Countries) approve = models.BooleanField() Django Rest Framework ===================== Django Countries ships with a ``CountryFieldMixin`` to make the `CountryField`_ model field compatible with DRF serializers. Use the following mixin with your model serializer: .. code:: python from django_countries.serializers import CountryFieldMixin class CountrySerializer(CountryFieldMixin, serializers.ModelSerializer): class Meta: model = models.Person fields = ('name', 'email', 'country') This mixin handles both standard and `multi-choice`_ country fields. Django Rest Framework field --------------------------- For lower level use (or when not dealing with model fields), you can use the included ``CountryField`` serializer field. For example: .. code:: python from django_countries.serializer_fields import CountryField class CountrySerializer(serializers.Serializer): country = CountryField() You can optionally instantiate the field with ``countries`` with a custom Countries_ instance. .. _Countries: `Single field customization`_ OPTIONS request --------------- When you request OPTIONS against a resource (using the DRF `metadata support`_) the countries will be returned in the response as choices: .. code:: text OPTIONS /api/address/ HTTP/1.1 HTTP/1.1 200 OK Content-Type: application/json Allow: GET, POST, HEAD, OPTIONS { "actions": { "POST": { "country": { "type": "choice", "label": "Country", "choices": [ { "display_name": "Australia", "value": "AU" }, [...] { "display_name": "United Kingdom", "value": "GB" } ] } } .. _metadata support: http://www.django-rest-framework.org/api-guide/metadata/ REST output format ------------------ By default, the field will output just the country code. If you would rather have more verbose output, instantiate the field with ``country_dict=True``, which will result in the field having the following output structure:: {"code": "NZ", "name": "New Zealand"} Either the code or this dict output structure are acceptable as input irregardless of the ``country_dict`` argument's value. django-countries-5.2/LICENSE0000644000175000017500000000206013250336536016106 0ustar chrischris00000000000000Copyright (c) 2010 Chris Beaven and contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.django-countries-5.2/CHANGES.rst0000644000175000017500000001567713250336536016725 0ustar chrischris00000000000000========== Change Log ========== This log shows interesting changes that happen for each version, latest versions first. It can be assumed that translations have been updated each release, and any new translations added. 5.2 (9 March 2018) ================== - Ensure Django 2.1 compatibility for ``CountrySelectWidget``. - Fix regression introduced into 5.1 when using Django 1.8 and certain queryset lookup types (like ``__in``). 5.1.1 (31 January 2018) ======================= - Fix some translations that were included in 5.1 but not compiled. 5.1 (30 January 2018) ===================== * Tests now also cover Django Rest Framework 3.7 and Django 2.0. * Allow for creating country fields using (valid) alpha-3 or numeric codes. * Fix migration error with blank default (thanks Jens Diemer). * Add a ``{% get_countries %}`` template tag (thanks Matija Čvrk). 5.0 (10 October 2017) ===================== * No longer allow ``multiple=True`` and ``null=True`` together. This causes problems saving the field, and ``null`` shouldn't really be used anyway because the country field is a subclass of ``CharField``. 4.6 (16 June 2017) ================== * Add a ``CountryFieldMixin`` Django Rest Framework serializer mixin that automatically picks the right field type for a ``CountryField`` (both single and multi-choice). * Validation for Django Rest Framework field (thanks Simon Meers). * Allow case-insensitive ``.by_name()`` matching (thanks again, Simon). * Ensure a multiple-choice ``CountryField.max_length`` is enough to hold all countries. * Fix inefficient pickling of countries (thanks Craig de Stigter for the report and tests). * Stop adding a blank choice when dealing with a multi-choice ``CountryField``. * Tests now cover multiple Django Rest Framework versions (back to 3.3). 4.6.1 ----- * Fix invalid reStructuredText in CHANGES. 4.6.2 ----- * Use transparency layer for flag sprites. 4.5 (18 April 2017) =================== * Change rest framework field to be based on ``ChoiceField``. * Allow for the rest framework field to deserialize by full country name (specifically the English name for now). 4.4 (6 April 2017) ================== * Fix for broken CountryField on certain models in Django 1.11. Thanks aktiur for the test case. * Update tests to cover Django 1.11 4.3 (29 March 2017) =================== * Handle "Czechia" translations in a nicer way (fall back to "Czech Republic" until new translations are available). * Fix for an import error in Django 1.9+ due to use of non-lazy ``ugettext`` in the django-countries custom admin filter. * Back to 100% test coverage. 4.2 (10 March 2017) =================== * Add sprite flag files (and ``Country.flag_css`` property) to help minimize HTTP requests. 4.1 (22 February 2017) ====================== * Better default Django admin filter when filtering a country field in a ``ModelAdmin``. * Fix settings to support Django 1.11 * Fix when using a model instance with a deferred country field. * Allow ``CountryField`` to handle multiple countries at once! * Allow CountryField to still work if Deferred. * Fix a field with customized country list. Thanks pilmie! 4.0 (16 August 2016) ==================== Django supported versions are now 1.8+ * Drop legacy code * Fix tests, 100% coverage * IOS / OSX unicode flags function * Fix widget choices on Django 1.9+ * Add ``COUNTRIES_FIRST_SORT``. Thanks Edraak! 4.0.1 ----- * Fix tests for ``COUNTRIES_FIRST_SORT`` (feature still worked, tests didn't). 3.4 (22 October 2015) ===================== * Extend test suite to cover Django 1.8 * Fix XSS escaping issue in CountrySelectWidget * Common name changes: fix typo of Moldova, add United Kingdom * Add ``{% get_country %}`` template tag. * New ``CountryField`` Django Rest Framework serializer field. 3.4.1 ----- * Fix minor packaging error. 3.3 (30 Mar 2015) ================= * Add the attributes to ``Countries`` class that can override the default settings. * CountriesField can now be passed a custom countries subclass to use, which combined with the previous change allows for different country choices for different fields. * Allow ``COUNTRIES_ONLY`` to also accept just country codes in its list (rather than only two-tuples), looking up the translatable country name from the full country list. * Fix Montenegro flag size (was 12px high rather than the standard 11px). * Fix outdated ISO country name formatting for Bolivia, Gambia, Holy See, Iran, Micronesia, and Venezuela. 3.2 (24 Feb 2015) ================= * Fixes initial iteration failing for a fresh ``Countries`` object. * Fix widget's flag URLs (and use ensure widget is HTML encoded safely). * Add ``countries.by_name(country, language='en')`` method, allowing lookup of a country code by its full country name. Thanks Josh Schneier. 3.1 (15 Jan 2015) ================= * Start change log :) * Add a ``COUNTRIES_FIRST`` setting (and some other related ones) to allow for specific countries to be shown before the entire alphanumeric list. * Add a ``blank_label`` argument to ``CountryField`` to allow customization of the label shown in the initial blank choice shown in the select widget. 3.1.1 (15 Jan 2015) ------------------- * Packaging fix (``CHANGES.rst`` wasn't in the manifest) 3.0 (22 Oct 2014) ================= Django supported versions are now 1.4 (LTS) and 1.6+ * Add ``COUNTRIES_ONLY`` setting to restrict to a specific list of countries. * Optimize country name translations to avoid exessive translation calls that were causing a notable performance impact. * PyUCA integration, allowing for more accurate sorting across all locales. Also, a better sorting method when PyUCA isn't installed. * Better tests (now at 100% test coverage). * Add a ``COUNTRIES_FLAG_URL`` setting to allow custom flag urls. * Support both IOC and numeric country codes, allowing more flexible lookup of countries and specific code types. * Field descriptor now returns ``None`` if no country matches (*reverted in v3.0.1*) 3.0.1 (27 Oct 2014) ------------------- * Revert descriptor to always return a Country object. * Fix the ``CountryField`` widget choices appearing empty due to a translation change in v3.0. 3.0.2 (29 Dec 2014) ------------------- * Fix ``CountrySelectWidget`` failing when used with a model form that is passed a model instance. 2.1 (24 Mar 2014) ================= * Add IOC (3 letter) country codes. * Fix bug when loading fixtures. 2.1.1 (28 Mar 2014) ------------------- * Fix issue with translations getting evaluated early. 2.1.2 (28 Mar 2014) ------------------- * Fix Python 3 compatibility. 2.0 (18 Feb 2014) ================= This is the first entry to the change log. The previous was 1.5, released 19 Nov 2012. * Optimized flag images, adding flags missing from original source. * Better storage of settings and country list. * New country list format for fields. * Better tests. * Changed ``COUNTRIES_FLAG_STATIC`` setting to ``COUNTRIES_FLAG_URL``. django-countries-5.2/django_countries/0000755000175000017500000000000013250336536020440 5ustar chrischris00000000000000django-countries-5.2/django_countries/ioc_data.py0000644000175000017500000001342313250336536022560 0ustar chrischris00000000000000IOC_TO_ISO = { 'AFG': 'AF', 'ALB': 'AL', 'ALG': 'DZ', 'AND': 'AD', 'ANG': 'AO', 'ANT': 'AG', 'ARG': 'AR', 'ARM': 'AM', 'ARU': 'AW', 'ASA': 'AS', 'AUS': 'AU', 'AUT': 'AT', 'AZE': 'AZ', 'BAH': 'BS', 'BAN': 'BD', 'BAR': 'BB', 'BDI': 'BI', 'BEL': 'BE', 'BEN': 'BJ', 'BER': 'BM', 'BHU': 'BT', 'BIH': 'BA', 'BIZ': 'BZ', 'BLR': 'BY', 'BOL': 'BO', 'BOT': 'BW', 'BRA': 'BR', 'BRN': 'BH', 'BRU': 'BN', 'BUL': 'BG', 'BUR': 'BF', 'CAF': 'CF', 'CAM': 'KH', 'CAN': 'CA', 'CAY': 'KY', 'CGO': 'CG', 'CHA': 'TD', 'CHI': 'CL', 'CHN': 'CN', 'CIV': 'CI', 'CMR': 'CM', 'COD': 'CD', 'COK': 'CK', 'COL': 'CO', 'COM': 'KM', 'CPV': 'CV', 'CRC': 'CR', 'CRO': 'HR', 'CUB': 'CU', 'CYP': 'CY', 'CZE': 'CZ', 'DEN': 'DK', 'DJI': 'DJ', 'DMA': 'DM', 'DOM': 'DO', 'ECU': 'EC', 'EGY': 'EG', 'ERI': 'ER', 'ESA': 'SV', 'ESP': 'ES', 'EST': 'EE', 'ETH': 'ET', 'FIJ': 'FJ', 'FIN': 'FI', 'FRA': 'FR', 'FSM': 'FM', 'GAB': 'GA', 'GAM': 'GM', 'GBR': 'GB', 'GBS': 'GW', 'GEO': 'GE', 'GEQ': 'GQ', 'GER': 'DE', 'GHA': 'GH', 'GRE': 'GR', 'GRN': 'GD', 'GUA': 'GT', 'GUI': 'GN', 'GUM': 'GU', 'GUY': 'GY', 'HAI': 'HT', 'HKG': 'HK', 'HON': 'HN', 'HUN': 'HU', 'INA': 'ID', 'IND': 'IN', 'IRI': 'IR', 'IRL': 'IE', 'IRQ': 'IQ', 'ISL': 'IS', 'ISR': 'IL', 'ISV': 'VI', 'ITA': 'IT', 'IVB': 'VG', 'JAM': 'JM', 'JOR': 'JO', 'JPN': 'JP', 'KAZ': 'KZ', 'KEN': 'KE', 'KGZ': 'KG', 'KIR': 'KI', 'KOR': 'KR', 'KSA': 'SA', 'KUW': 'KW', 'LAO': 'LA', 'LAT': 'LV', 'LBA': 'LY', 'LBR': 'LR', 'LCA': 'LC', 'LES': 'LS', 'LBN': 'LB', 'LIE': 'LI', 'LTU': 'LT', 'LUX': 'LU', 'MAD': 'MG', 'MAR': 'MA', 'MAS': 'MY', 'MAW': 'MW', 'MDA': 'MD', 'MDV': 'MV', 'MEX': 'MX', 'MGL': 'MN', 'MHL': 'MH', 'MKD': 'MK', 'MLI': 'ML', 'MLT': 'MT', 'MNE': 'ME', 'MON': 'MC', 'MOZ': 'MZ', 'MRI': 'MU', 'MTN': 'MR', 'MYA': 'MM', 'NAM': 'NA', 'NCA': 'NI', 'NED': 'NL', 'NEP': 'NP', 'NGR': 'NG', 'NIG': 'NE', 'NOR': 'NO', 'NRU': 'NR', 'NZL': 'NZ', 'OMA': 'OM', 'PAK': 'PK', 'PAN': 'PA', 'PAR': 'PY', 'PER': 'PE', 'PHI': 'PH', 'PLE': 'PS', 'PLW': 'PW', 'PNG': 'PG', 'POL': 'PL', 'POR': 'PT', 'PRK': 'KP', 'PUR': 'PR', 'QAT': 'QA', 'ROU': 'RO', 'RSA': 'ZA', 'RUS': 'RU', 'RWA': 'RW', 'SAM': 'WS', 'SEN': 'SN', 'SEY': 'SC', 'SKN': 'KN', 'SLE': 'SL', 'SLO': 'SI', 'SMR': 'SM', 'SNG': 'SG', 'SOL': 'SB', 'SOM': 'SO', 'SRB': 'RS', 'SRI': 'LK', 'STP': 'ST', 'SUD': 'SD', 'SUI': 'CH', 'SUR': 'SR', 'SVK': 'SK', 'SWE': 'SE', 'SWZ': 'SZ', 'SYR': 'SY', 'TAN': 'TZ', 'TGA': 'TO', 'THA': 'TH', 'TJK': 'TJ', 'TKM': 'TM', 'TLS': 'TL', 'TOG': 'TG', 'TPE': 'TW', 'TTO': 'TT', 'TUN': 'TN', 'TUR': 'TR', 'TUV': 'TV', 'UAE': 'AE', 'UGA': 'UG', 'UKR': 'UA', 'URU': 'UY', 'USA': 'US', 'UZB': 'UZ', 'VAN': 'VU', 'VEN': 'VE', 'VIE': 'VN', 'VIN': 'VC', 'YEM': 'YE', 'ZAM': 'ZM', 'ZIM': 'ZW', } IOC_HISTORICAL_TO_ISO = { 'AGR': 'DZ', 'AGL': 'DZ', 'BAD': 'BB', 'DAY': 'BJ', 'DAH': 'BJ', 'BSH': 'BA', 'HBR': 'BZ', 'VOL': 'BF', 'AFC': 'CF', 'CAB': 'KH', 'KHM': 'KH', 'CHD': 'TD', 'CIL': 'CL', 'PRC': 'CN', 'IVC': 'CI', 'CML': 'CI', 'COK': 'CD', 'ZAI': 'CD', 'COS': 'CR', 'TCH': 'CZ', 'DAN': 'DK', 'DIN': 'DK', 'RAU': 'EG', # Used 1960, 1968 (also used by Syria in 1960) 'UAR': 'EG', 'SAL': 'SV', 'SPA': 'ES', 'ETI': 'ET', 'FIG': 'FJ', 'GRB': 'GB', 'GBI': 'GB', 'ALL': 'DE', 'ALE': 'DE', 'GUT': 'GT', 'GUA': 'GY', 'GUI': 'GY', 'HOK': 'HK', 'UNG': 'HU', 'INS': 'ID', 'IRN': 'IR', 'IRA': 'IR', 'IRK': 'IQ', 'ICE': 'IS', 'ISL': 'IL', 'GIA': 'JP', 'JAP': 'JP', 'COR': 'KR', 'ARS': 'SA', 'SAU': 'SA', 'LYA': 'LY', 'LBY': 'LY', 'LEB': 'LB', # Used from 1960-1964 'LIB': 'LB', # Used from 1964-2016 'LIC': 'LI', 'LIT': 'LT', 'MAG': 'MG', 'MRC': 'MA', 'MAL': 'MY', 'MLD': 'MD', 'MOD': 'MN', 'MAT': 'MT', 'BIR': 'MM', 'BUR': 'MM', 'NGC': 'NI', 'NIC': 'NI', 'OLA': 'NL', 'NET': 'NL', 'NLD': 'NL', 'HOL': 'NL', 'NIG': 'NG', 'NGA': 'NG', 'NGR': 'NE', 'NZE': 'NZ', 'FIL': 'PH', 'NGY': 'PG', 'NGU': 'PG', 'NKO': 'KP', 'CDN': 'KP', 'PRI': 'PR', 'PRO': 'PR', 'ROM': 'RO', 'RUM': 'RO', 'SAF': 'ZA', 'SGL': 'SN', 'SIN': 'SG', # Used from 1959-2016 'SLA': 'SL', 'SMA': 'SM', 'CEY': 'LK', 'CEI': 'LK', 'SVI': 'CH', 'SVE': 'SE', 'SUE': 'SE', 'SIR': 'SY', 'TON': 'TO', 'IOA': 'TL', 'RCF': 'TW', 'TWN': 'TW', 'ROC': 'TW', 'TRT': 'TT', 'URG': 'UY', 'SUA': 'US', 'EUA': 'US', 'VET': 'VN', 'VNM': 'VN', 'NRH': 'ZM', 'RHO': 'ZW', } ISO_TO_IOC = dict((iso, ioc) for ioc, iso in IOC_TO_ISO.items()) def check_ioc_countries(verbosity=1): """ Check if all IOC codes map to ISO codes correctly """ from django_countries.data import COUNTRIES if verbosity: # pragma: no cover print("Checking if all IOC codes map correctly") for key in ISO_TO_IOC: assert COUNTRIES.get(key), 'No ISO code for %s' % key if verbosity: # pragma: no cover print("Finished checking IOC codes") django-countries-5.2/django_countries/templatetags/0000755000175000017500000000000013250336536023132 5ustar chrischris00000000000000django-countries-5.2/django_countries/templatetags/countries.py0000644000175000017500000000070313250336536025517 0ustar chrischris00000000000000import django from django import template from django_countries.fields import Country, countries register = template.Library() if django.VERSION < (1, 9): # Support older versions without implicit assignment support in simple_tag. simple_tag = register.assignment_tag else: simple_tag = register.simple_tag @simple_tag def get_country(code): return Country(code=code) @simple_tag def get_countries(): return list(countries) django-countries-5.2/django_countries/templatetags/__init__.py0000644000175000017500000000000013250336536025231 0ustar chrischris00000000000000django-countries-5.2/django_countries/conf.py0000644000175000017500000000532413250336536021743 0ustar chrischris00000000000000import django.conf class AppSettings(object): """ A holder for app-specific default settings that allows overriding via the project's settings. """ def __getattribute__(self, attr): if attr == attr.upper(): try: return getattr(django.conf.settings, attr) except AttributeError: pass return super(AppSettings, self).__getattribute__(attr) class Settings(AppSettings): COUNTRIES_FLAG_URL = 'flags/{code}.gif' """ The URL for a flag. It can either be relative to the static url, or an absolute url. The location is parsed using Python's string formatting and is passed the following arguments: * code * code_upper For example: ``COUNTRIES_FLAG_URL = 'flags/16x10/{code_upper}.png'`` """ COUNTRIES_COMMON_NAMES = True """ Whether to use the common names for some countries, as opposed to the official ISO name. Some examples: "Bolivia" instead of "Bolivia, Plurinational State of" "South Korea" instead of "Korea (the Republic of)" "Taiwan" instead of "Taiwan (Province of China)" """ COUNTRIES_OVERRIDE = {} """ A dictionary of names to override the defaults. Note that you will need to handle translation of customised country names. Setting a country's name to ``None`` will exclude it from the country list. For example:: COUNTRIES_OVERRIDE = { 'NZ': _('Middle Earth'), 'AU': None } """ COUNTRIES_ONLY = {} """ Similar to COUNTRIES_OVERRIDE A dictionary of names to include in selection. Note that you will need to handle translation of customised country names. For example:: COUNTRIES_ONLY = { 'NZ': _('Middle Earth'), 'AU': _('Desert'), } """ COUNTRIES_FIRST = [] """ Countries matching the country codes provided in this list will be shown first in the countries list (in the order specified) before all the alphanumerically sorted countries. """ COUNTRIES_FIRST_REPEAT = False """ Countries listed in :attr:`COUNTRIES_FIRST` will be repeated again in the alphanumerically sorted list if set to ``True``. """ COUNTRIES_FIRST_BREAK = None """ Countries listed in :attr:`COUNTRIES_FIRST` will be followed by a null choice with this title (if set) before all the alphanumerically sorted countries. """ COUNTRIES_FIRST_SORT = False """ Countries listed in :attr:`COUNTRIES_FIRST` will be alphanumerically sorted based on their translated name instead of relying on their order in :attr:`COUNTRIES_FIRST`. """ settings = Settings() django-countries-5.2/django_countries/tests/0000755000175000017500000000000013250336536021602 5ustar chrischris00000000000000django-countries-5.2/django_countries/tests/settings.py0000644000175000017500000000206313250336536024015 0ustar chrischris00000000000000SECRET_KEY = 'test' INSTALLED_APPS = ( 'django.contrib.contenttypes', 'django.contrib.auth', 'django_countries', 'django_countries.tests', ) DATABASES = { 'default': {'ENGINE': 'django.db.backends.sqlite3'} } STATIC_URL = '/static-assets/' MIDDLEWARE_CLASSES = ( 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.locale.LocaleMiddleware' ) TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.contrib.auth.context_processors.auth', 'django.template.context_processors.debug', 'django.template.context_processors.i18n', 'django.template.context_processors.media', 'django.template.context_processors.static', 'django.template.context_processors.tz', 'django.contrib.messages.context_processors.messages', ], }, }, ] django-countries-5.2/django_countries/tests/test_tags.py0000644000175000017500000000311613250336536024152 0ustar chrischris00000000000000from django.template import Template, Context from django.test import TestCase from django.utils import translation from django_countries import countries class TestCountriesTags(TestCase): TEMPLATE_COUNTRY = Template( "{% load countries %}{% get_country code as country %}{{ country }}") TEMPLATE_NAME = Template( "{% load countries %}{% get_country code as country %}" "{{ country.name }}") TEMPLATE_COUNTRIES = Template( "{% load countries %}{% get_countries as countries_list %}" "{{ countries_list }}") def test_country(self): rendered = self.TEMPLATE_COUNTRY.render(Context({'code': 'BR'})) self.assertEqual(rendered, 'BR') def test_country_name(self): rendered = self.TEMPLATE_NAME.render(Context({'code': 'BR'})) self.assertEqual(rendered, 'Brazil') def test_country_name_translated(self): with translation.override('pt-BR'): rendered = self.TEMPLATE_NAME.render(Context({'code': 'BR'})) self.assertEqual(rendered, 'Brasil') def test_wrong_code(self): rendered = self.TEMPLATE_COUNTRY.render(Context({'code': 'XX'})) self.assertEqual(rendered, 'XX') rendered = self.TEMPLATE_NAME.render(Context({'code': 'XX'})) self.assertEqual(rendered, '') def test_countries_displayed_all(self): rendered = self.TEMPLATE_COUNTRIES.render(Context()) self.assertEqual( rendered, Template("{{ expected }}").render(Context( {'expected': [(code, name) for code, name in countries]})) ) django-countries-5.2/django_countries/tests/test_fields.py0000644000175000017500000004514613250336536024473 0ustar chrischris00000000000000# -*- coding: utf-8 -*- from __future__ import unicode_literals import pickle from django.db import models from django.core import validators, checks from django.forms import Select from django.forms.models import modelform_factory from django.test import TestCase, override_settings from django.utils import translation from django.utils.encoding import force_text from django_countries import fields, countries, data from django_countries.fields import CountryField from django_countries.tests import forms, custom_countries from django_countries.tests.models import ( Person, AllowNull, MultiCountry, WithProp) class TestCountryField(TestCase): def test_logic(self): person = Person(name='Chris Beaven', country='NZ') self.assertEqual(person.country, 'NZ') self.assertNotEqual(person.country, 'ZZ') self.assertTrue(person.country) person.country = '' self.assertFalse(person.country) def test_get_property_from_class(self): self.assertIsInstance(Person.country, fields.CountryDescriptor) def test_deconstruct(self): field = Person._meta.get_field('country') self.assertEqual( field.deconstruct(), ('country', 'django_countries.fields.CountryField', [], {'max_length': 2})) def test_text(self): person = Person(name='Chris Beaven', country='NZ') self.assertEqual(force_text(person.country), 'NZ') def test_name(self): person = Person(name='Chris Beaven', country='NZ') self.assertEqual(person.country.name, 'New Zealand') def test_flag(self): person = Person(name='Chris Beaven', country='NZ') with self.settings(STATIC_URL='/static-assets/'): self.assertEqual( person.country.flag, '/static-assets/flags/nz.gif') def test_custom_field_flag_url(self): person = Person(name='Chris Beaven', country='NZ', other_country='US') self.assertEqual( person.other_country.flag, '//flags.example.com/us.gif') def test_unicode_flags(self): person = Person( name='Matthew Schinckel', country='AU', other_country='DE') self.assertEqual(person.country.unicode_flag, '🇦🇺') self.assertEqual(person.other_country.unicode_flag, '🇩🇪') def test_unicode_flag_blank(self): person = Person(name='Matthew Schinckel') self.assertEqual(person.country.unicode_flag, '') def test_COUNTRIES_FLAG_URL_setting(self): # Custom relative url person = Person(name='Chris Beaven', country='NZ') with self.settings(COUNTRIES_FLAG_URL='img/flag-{code_upper}.png', STATIC_URL='/static-assets/'): self.assertEqual( person.country.flag, '/static-assets/img/flag-NZ.png') # Custom absolute url with self.settings(COUNTRIES_FLAG_URL='https://flags.example.com/' '{code_upper}.PNG'): self.assertEqual( person.country.flag, 'https://flags.example.com/NZ.PNG') def test_flag_css(self): person = Person(name='Chris Beaven', country='NZ') self.assertEqual(person.country.flag_css, 'flag-sprite flag-n flag-_z') def test_flag_css_blank(self): person = Person(name='Chris Beaven') self.assertEqual(person.country.flag_css, '') def test_blank(self): person = Person.objects.create(name='The Outsider') self.assertEqual(person.country.code, '') person = Person.objects.get(pk=person.pk) self.assertEqual(person.country.code, '') def test_null(self): person = AllowNull.objects.create(country=None) self.assertIsNone(person.country.code) person = AllowNull.objects.get(pk=person.pk) self.assertIsNone(person.country.code) @override_settings(SILENCED_SYSTEM_CHECKS=['django_countries.E100']) def test_multi_null_country(self): class MultiNullCountry(models.Model): countries = fields.CountryField( multiple=True, null=True, blank=True) class MultiNullCountryNoBlank(models.Model): countries = fields.CountryField( multiple=True, null=True) errors = checks.run_checks() self.assertEqual([e.id for e in errors], ['django_countries.E100'] * 2) errors_dict = dict((e.obj, e) for e in errors) self.assertFalse( 'blank=True' in errors_dict[ MultiNullCountry._meta.get_field('countries') ].hint) self.assertTrue( 'blank=True' in errors_dict[ MultiNullCountryNoBlank._meta.get_field('countries') ].hint) def test_deferred(self): Person.objects.create(name='Person', country='NZ') person = Person.objects.defer('country').get(name='Person') self.assertEqual(person.country.code, 'NZ') def test_only(self): Person.objects.create(name='Person', country='NZ') person = Person.objects.only('name').get() self.assertEqual(person.country.code, 'NZ') def test_nullable_deferred(self): AllowNull.objects.create(country=None) person = AllowNull.objects.defer('country').get() self.assertIsNone(person.country.code) def test_len(self): person = Person(name='Chris Beaven', country='NZ') self.assertEqual(len(person.country), 2) person = Person(name='The Outsider', country=None) self.assertEqual(len(person.country), 0) def test_lookup_text(self): Person.objects.create(name='Chris Beaven', country='NZ') Person.objects.create(name='Pavlova', country='NZ') Person.objects.create(name='Killer everything', country='AU') lookup = Person.objects.filter(country='NZ') names = lookup.order_by('name').values_list('name', flat=True) self.assertEqual(list(names), ['Chris Beaven', 'Pavlova']) def test_lookup_country(self): Person.objects.create(name='Chris Beaven', country='NZ') Person.objects.create(name='Pavlova', country='NZ') Person.objects.create(name='Killer everything', country='AU') oz = fields.Country(code='AU', flag_url='') lookup = Person.objects.filter(country=oz) names = lookup.values_list('name', flat=True) self.assertEqual(list(names), ['Killer everything']) def test_save_empty_country(self): Person.objects.create(name='The Outsider') person = Person.objects.get() self.assertEqual(person.country.code, '') def test_create_modelform(self): Form = modelform_factory(Person, fields=['country']) form_field = Form().fields['country'] self.assertTrue(isinstance(form_field.widget, Select)) def test_render_form(self): Form = modelform_factory(Person, fields=['country']) Form().as_p() def test_model_with_prop(self): with_prop = WithProp(country='FR', public_field='test') self.assertEqual(with_prop.country.code, 'FR') self.assertEqual(with_prop.public_field, 'test') def test_in(self): Person.objects.create(name='A', country='NZ') Person.objects.create(name='B', country='AU') Person.objects.create(name='C', country='FR') Person.objects.create(name='D', country='NZ') self.assertEqual( list( Person.objects.filter(country__in=['AU', 'NZ']) .values_list('name', flat=True)), ['A', 'B', 'D'] ) class TestValidation(TestCase): def test_validate(self): person = Person(name='Chris', country='NZ') person.full_clean() def test_validate_alpha3(self): person = Person(name='Chris', country='NZL') person.full_clean() def test_validate_empty(self): person = Person(name='Chris') self.assertRaises(validators.ValidationError, person.full_clean) def test_validate_invalid(self): person = Person(name='Chris', country=':(') self.assertRaises(validators.ValidationError, person.full_clean) def test_validate_multiple(self): person = MultiCountry(countries=['NZ', 'AU']) person.full_clean() def test_validate_multiple_empty(self): person = MultiCountry() self.assertRaises(validators.ValidationError, person.full_clean) def test_validate_multiple_invalid(self): person = MultiCountry(countries=[':(', 'AU']) self.assertRaises(validators.ValidationError, person.full_clean) def test_validate_multiple_uneditable(self): person = MultiCountry(countries='NZ', uneditable_countries='xx') person.full_clean() def test_get_prep_value_empty_string(self): country_field_instance = CountryField(multiple=True, blank=True) prep_value = country_field_instance.get_prep_value('') self.assertEqual(prep_value, '') def test_get_prep_value_none(self): """ Note: django migrations will call get_prep_value() with None see: https://github.com/SmileyChris/django-countries/issues/215 """ country_field_instance = CountryField(multiple=True, blank=True) prep_value = country_field_instance.get_prep_value(None) self.assertEqual(prep_value, '') class TestCountryCustom(TestCase): def test_name(self): person = Person(name='Chris Beaven', fantasy_country='NV') self.assertEqual(person.fantasy_country.name, 'Neverland') def test_field(self): self.assertEqual( list(Person._meta.get_field('fantasy_country').choices), [('NV', 'Neverland'), ('NZ', 'New Zealand')]) def test_deconstruct(self): field = Person._meta.get_field('fantasy_country') self.assertEqual( field.deconstruct(), ( 'fantasy_country', 'django_countries.fields.CountryField', [], { 'countries': custom_countries.FantasyCountries, 'blank': True, 'max_length': 2 } )) class TestCountryMultiple(TestCase): def test_empty(self): obj = MultiCountry() self.assertEqual(obj.countries, []) def test_empty_save(self): MultiCountry.objects.create() def test_single(self): obj = MultiCountry(countries='NZ') self.assertEqual(len(obj.countries), 1) self.assertTrue(isinstance(obj.countries[0], fields.Country)) self.assertEqual(obj.countries[0], 'NZ') def test_multiple(self): obj = MultiCountry(countries='AU,NZ') self.assertEqual(len(obj.countries), 2) for country in obj.countries: self.assertTrue(isinstance(country, fields.Country)) self.assertEqual(obj.countries[0], 'AU') self.assertEqual(obj.countries[1], 'NZ') def test_set_text(self): obj = MultiCountry() obj.countries = 'NZ,AU' self.assertEqual(obj.countries, ['NZ', 'AU']) def test_set_list(self): obj = MultiCountry() obj.countries = ['NZ', 'AU'] self.assertEqual(obj.countries, ['NZ', 'AU']) def test_set_country(self): obj = MultiCountry() obj.countries = fields.Country('NZ') self.assertEqual(obj.countries, ['NZ']) def test_set_countries(self): obj = MultiCountry() obj.countries = [fields.Country('NZ'), fields.Country('AU')] self.assertEqual(obj.countries, ['NZ', 'AU']) def test_all_countries(self): all_codes = list(c[0] for c in countries) MultiCountry.objects.create(countries=all_codes) obj = MultiCountry.objects.get() self.assertEqual(obj.countries, all_codes) def test_deconstruct(self): field = MultiCountry._meta.get_field('countries') expected_max_length = len(data.COUNTRIES) * 3 - 1 self.assertEqual( field.deconstruct(), ( 'countries', 'django_countries.fields.CountryField', [], {'max_length': expected_max_length, 'multiple': True} )) class TestCountryObject(TestCase): def test_hash(self): country = fields.Country(code='XX', flag_url='') self.assertEqual(hash(country), hash('XX')) def test_repr(self): country1 = fields.Country(code='XX') country2 = fields.Country(code='XX', flag_url='') country3 = fields.Country(code='XX', str_attr='name') self.assertEqual( repr(country1), 'Country(code={0})'.format(repr('XX'))) self.assertEqual( repr(country2), 'Country(code={0}, flag_url={1})'.format(repr('XX'), repr(''))) self.assertEqual( repr(country3), 'Country(code={0}, str_attr={1})'.format(repr('XX'), repr('name'))) def test_str(self): country = fields.Country(code='NZ') self.assertEqual('%s' % country, 'NZ') def test_str_attr(self): country = fields.Country(code='NZ', str_attr='name') self.assertEqual('%s' % country, 'New Zealand') def test_flag_on_empty_code(self): country = fields.Country(code='', flag_url='') self.assertEqual(country.flag, '') def test_ioc_code(self): country = fields.Country(code='NL', flag_url='') self.assertEqual(country.ioc_code, 'NED') def test_country_from_ioc_code(self): country = fields.Country.country_from_ioc('NED') self.assertEqual(country, fields.Country('NL', flag_url='')) def test_country_from_blank_ioc_code(self): country = fields.Country.country_from_ioc('') self.assertIsNone(country) def test_country_from_nonexistence_ioc_code(self): country = fields.Country.country_from_ioc('XXX') self.assertIsNone(country) def test_alpha3(self): country = fields.Country(code='BN') self.assertEqual(country.alpha3, 'BRN') def test_alpha3_invalid(self): country = fields.Country(code='XX') self.assertEqual(country.alpha3, '') def test_numeric(self): country = fields.Country(code='BN') self.assertEqual(country.numeric, 96) def test_numeric_padded(self): country = fields.Country(code='AL') self.assertEqual(country.numeric_padded, '008') country = fields.Country(code='BN') self.assertEqual(country.numeric_padded, '096') country = fields.Country(code='NZ') self.assertEqual(country.numeric_padded, '554') def test_numeric_invalid(self): country = fields.Country(code='XX') self.assertEqual(country.numeric, None) def test_numeric_padded_invalid(self): country = fields.Country(code='XX') self.assertEqual(country.numeric_padded, None) def test_empty_flag_url(self): country = fields.Country(code='XX', flag_url='') self.assertEqual(country.flag, '') def test_alpha2_code(self): country = fields.Country(code='NZL') self.assertEqual(country.code, 'NZ') def test_alpha2_code_invalid(self): country = fields.Country(code='NZX') self.assertEqual(country.code, 'NZX') def test_numeric_code(self): country = fields.Country(code=554) self.assertEqual(country.code, 'NZ') def test_numeric_code_invalid(self): country = fields.Country(code=999) self.assertEqual(country.code, 999) class TestModelForm(TestCase): def test_translated_choices(self): lang = translation.get_language() translation.activate('eo') form = forms.PersonForm() try: # This is just to prove that the language changed. self.assertEqual(list(countries)[0][1], 'Afganio') # If the choices aren't lazy, this wouldn't be translated. It's the # second choice because the first one is the initial blank option. self.assertEqual( form.fields['country'].choices[1][1], 'Afganio') self.assertEqual( form.fields['country'].widget.choices[1][1], 'Afganio') finally: translation.activate(lang) def test_blank_choice(self): blank = ('', '---------') form = forms.PersonForm() self.assertEqual(form.fields['country'].choices[0], blank) multi_form = forms.MultiCountryForm() self.assertNotEqual( multi_form.fields['countries'].choices[0], blank) def test_no_blank_choice(self): form = forms.PersonForm() self.assertEqual( form.fields['favourite_country'].choices[0], ('AF', 'Afghanistan')) def test_blank_choice_label(self): form = forms.AllowNullForm() self.assertEqual( form.fields['country'].choices[0], ('', '(select country)')) def test_validation(self): form = forms.MultiCountryForm(data={'countries': ['NZ', 'AU']}) self.assertEqual(form.errors, {}) class TestPickling(TestCase): def test_standard_country_pickling(self): chris = Person(name='Chris Beaven', country='NZ') # django uses pickle.HIGHEST_PROTOCOL which is somewhere between 2 and # 4, depending on python version. Let's use 2 for testing. newly_pickled_zealand = pickle.dumps(chris.country, protocol=2) # Different python versions end up with slightly different sizes. Let's # just check the size is smaller than if it contained the entire # standard countries list in the pickle. self.assertLess(len(newly_pickled_zealand), 200) unpickled = pickle.loads(newly_pickled_zealand) self.assertEqual(unpickled.code, 'NZ') self.assertEqual(unpickled.name, 'New Zealand') self.assertEqual(unpickled.flag_url, None) self.assertIs(unpickled.countries, countries) self.assertIsNone(unpickled.custom_countries) def test_custom_country_pickling(self): chris = Person(name='Chris Beaven', fantasy_country='NV') # django uses pickle.HIGHEST_PROTOCOL which is somewhere between 2 and # 4, depending on python version. Let's use 2 for testing. pickled_neverland = pickle.dumps(chris.fantasy_country, protocol=2) # Different python versions end up with slightly different sizes. Let's # just check the size is smaller than if it also contained the fantasy # countries list in the pickle. self.assertLess(len(pickled_neverland), 300) neverland = pickle.loads(pickled_neverland) self.assertEqual(neverland.code, 'NV') self.assertEqual(neverland.name, 'Neverland') self.assertEqual(neverland.flag_url, None) self.assertIsInstance( neverland.countries, custom_countries.FantasyCountries) django-countries-5.2/django_countries/tests/test_widgets.py0000644000175000017500000000501413250336536024661 0ustar chrischris00000000000000from __future__ import unicode_literals from unittest import skipIf try: from urllib import parse as urlparse except ImportError: import urlparse # Python 2 from distutils.version import StrictVersion import django from django.forms.models import modelform_factory from django.test import TestCase from django.utils import safestring from django.utils.html import escape from django_countries import widgets, countries, fields from django_countries.conf import settings from django_countries.tests.models import Person class TestCountrySelectWidget(TestCase): def setUp(self): del countries.countries self.Form = modelform_factory( Person, fields=['country'], widgets={'country': widgets.CountrySelectWidget}) def tearDown(self): del countries.countries def test_not_default_widget(self): Form = modelform_factory(Person, fields=['country']) widget = Form().fields['country'].widget self.assertFalse(isinstance(widget, widgets.CountrySelectWidget)) def test_render_contains_flag_url(self): with self.settings(COUNTRIES_ONLY={'AU': 'Desert'}): html = self.Form().as_p() self.assertIn(escape(urlparse.urljoin( settings.STATIC_URL, settings.COUNTRIES_FLAG_URL)), html) def test_render(self): with self.settings(COUNTRIES_ONLY={'AU': 'Desert'}): html = self.Form().as_p() self.assertIn(fields.Country('__').flag, html) self.assertNotIn(fields.Country('AU').flag, html) def test_render_initial(self): with self.settings(COUNTRIES_ONLY={'AU': 'Desert'}): html = self.Form(initial={'country': 'AU'}).as_p() self.assertIn(fields.Country('AU').flag, html) self.assertNotIn(fields.Country('__').flag, html) def test_render_escaping(self): output = widgets.CountrySelectWidget().render('test', '