django-countries-5.2/ 0000755 0001750 0001750 00000000000 13250336536 015103 5 ustar chris chris 0000000 0000000 django-countries-5.2/setup.cfg 0000644 0001750 0001750 00000003052 13250336536 016724 0 ustar chris chris 0000000 0000000 [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/ 0000755 0001750 0001750 00000000000 13250336536 022132 5 ustar chris chris 0000000 0000000 django-countries-5.2/django_countries.egg-info/dependency_links.txt 0000644 0001750 0001750 00000000001 13250336536 026200 0 ustar chris chris 0000000 0000000
django-countries-5.2/django_countries.egg-info/not-zip-safe 0000644 0001750 0001750 00000000001 13250336536 024360 0 ustar chris chris 0000000 0000000
django-countries-5.2/django_countries.egg-info/PKG-INFO 0000644 0001750 0001750 00000063040 13250336536 023232 0 ustar chris chris 0000000 0000000 Metadata-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.txt 0000644 0001750 0001750 00000000021 13250336536 024655 0 ustar chris chris 0000000 0000000 django_countries
django-countries-5.2/django_countries.egg-info/requires.txt 0000644 0001750 0001750 00000000220 13250336536 024524 0 ustar chris chris 0000000 0000000
[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.txt 0000644 0001750 0001750 00000033356 13250336536 024030 0 ustar chris chris 0000000 0000000 CHANGES.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.py django-countries-5.2/setup.py 0000755 0001750 0001750 00000000074 13250336536 016621 0 ustar chris chris 0000000 0000000 #!/usr/bin/env python
from setuptools import setup
setup()
django-countries-5.2/README.rst 0000644 0001750 0001750 00000027750 13250336536 016605 0 ustar chris chris 0000000 0000000 ================
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/LICENSE 0000644 0001750 0001750 00000002060 13250336536 016106 0 ustar chris chris 0000000 0000000 Copyright (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.rst 0000644 0001750 0001750 00000015677 13250336536 016725 0 ustar chris chris 0000000 0000000 ==========
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/ 0000755 0001750 0001750 00000000000 13250336536 020440 5 ustar chris chris 0000000 0000000 django-countries-5.2/django_countries/ioc_data.py 0000644 0001750 0001750 00000013423 13250336536 022560 0 ustar chris chris 0000000 0000000 IOC_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/ 0000755 0001750 0001750 00000000000 13250336536 023132 5 ustar chris chris 0000000 0000000 django-countries-5.2/django_countries/templatetags/countries.py 0000644 0001750 0001750 00000000703 13250336536 025517 0 ustar chris chris 0000000 0000000 import 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__.py 0000644 0001750 0001750 00000000000 13250336536 025231 0 ustar chris chris 0000000 0000000 django-countries-5.2/django_countries/conf.py 0000644 0001750 0001750 00000005324 13250336536 021743 0 ustar chris chris 0000000 0000000 import 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/ 0000755 0001750 0001750 00000000000 13250336536 021602 5 ustar chris chris 0000000 0000000 django-countries-5.2/django_countries/tests/settings.py 0000644 0001750 0001750 00000002063 13250336536 024015 0 ustar chris chris 0000000 0000000 SECRET_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.py 0000644 0001750 0001750 00000003116 13250336536 024152 0 ustar chris chris 0000000 0000000 from 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.py 0000644 0001750 0001750 00000045146 13250336536 024473 0 ustar chris chris 0000000 0000000 # -*- 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.py 0000644 0001750 0001750 00000005014 13250336536 024661 0 ustar chris chris 0000000 0000000 from __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', '