Django: Country drop down list?
Asked Answered
N

16

24

I have a form for address information. One of the fields is for the address country. Currently this is just a textbox. I would like a drop down list (of ISO 3166 countries) for this. I'm a django newbie so I haven't even used a Django Select widget yet. What is a good way to do this?

Hard-code the choices in a file somewhere? Put them in the database? In the template?

Nigel answered 3/6, 2010 at 7:10 Comment(0)
M
25

Django Countries

from django_countries.fields import CountryField

class Foo(models.Model):
    country = CountryField()
Movement answered 13/9, 2010 at 12:18 Comment(3)
@monokrome So what you're saying is that I'm right, and you need to do extra work to represent the country name in any other format.Proviso
For some reason, that import didn't work form me. I use from django_countries.fields import CountryField.Galibi
@JohnLehmann maybe it's changed, this is 5 years old. Updated.Movement
G
35

Check out "choices" parameter of a CharField.

You might also want to take a look at django-countries.

Glyptics answered 3/6, 2010 at 7:37 Comment(4)
Note that there are two django-countries projects. The one linked has much more comprehensive data, but appears not to be actively maintained, so watch out for out-of-date data.Proviso
Seems to be living on github now: github.com/SmileyChris/django-countriesOglesby
@Oglesby Thanks! Updated accordingly.Hautbois
Instead of the additional django-countries dependency, you could use pytz, which is already included with Django. See example below.Evieevil
M
25

Django Countries

from django_countries.fields import CountryField

class Foo(models.Model):
    country = CountryField()
Movement answered 13/9, 2010 at 12:18 Comment(3)
@monokrome So what you're saying is that I'm right, and you need to do extra work to represent the country name in any other format.Proviso
For some reason, that import didn't work form me. I use from django_countries.fields import CountryField.Galibi
@JohnLehmann maybe it's changed, this is 5 years old. Updated.Movement
N
11

Ended up using the below snippet which basically defines a tuple of tuples of two character country codes. Additionally it defines a custom field type called CountryField and defaults the choices parameter to the above defined tuple. This automatically gets rendered as a drop down list.

http://djangosnippets.org/snippets/494/

Nigel answered 4/6, 2010 at 5:27 Comment(2)
django-countries provides exactly the same. Its a reusable component.Photoactive
Someone in the comment at djangosnippets recommends using this snippet instead: djangosnippets.org/snippets/1476 It is more up to date and fixes the maxlength bug.Patrick
P
8

Django Countries

from django_countries.countries import COUNTRIES

class CountryForm(forms.Form):
      country= forms.ChoiceField(COUNTRIES)
Perquisite answered 28/8, 2010 at 21:54 Comment(4)
django-countries has a CountryField class now.Movement
hi..there is one problem, when this form is rendered, by defaul it shows 'Afghanistan', which is the first country in the choice set of course..but what if the country field is not required? meaning, by default shows ---- or similarBecht
The import location seems to have changed it's now from django_countries import countriesKnockknee
Official documentation for using django_countries in a forms.Form: github.com/SmileyChris/django-countries#custom-formsCulosio
C
5

Two low mantained projects:

http://code.google.com/p/django-countries/

https://github.com/strange/django-country-utils

Two snippets:

http://djangosnippets.org/snippets/494/

http://djangosnippets.org/snippets/1476/

For now, I am going for a snippet.

Chigoe answered 24/11, 2011 at 15:47 Comment(0)
C
5

As previous answers have stated, there is a CountryField in django-countries. This is a model field.

If a form field is needed in a plain form (not model form), in django-countries v3.x (definitely tested in 3.3) the following can be used:

from django_countries.data import COUNTRIES

class MyForm(forms.Form):
    country = forms.ChoiceField(sorted(COUNTRIES.items()))
Cerium answered 17/5, 2015 at 22:22 Comment(1)
This is helpful while creating a form with django-countries. Thanks !Whoremaster
E
4

UPDATE (Django >=4.0)

Using pytz.country_names was convenient in older Django versions, as described below, but Django >=4.0 uses zoneinfo instead of pytz. Details in the release notes and here.

Unfortunately, zoneinfo does not appear to offer an equivalent of pytz.country_names (as far as I know).

There is, however, an up-to-date list of ISO 3166 country names in Python's (first-party) tzdata package: iso3166.tab

Note that tzdata is already installed if you're using Django 4+ on Windows.

For illustrative purposes only, here's a quick & dirty way to parse the iso3166.tab file into a dict similar to pytz.country_names (Python 3.9+):

from importlib import resources

with resources.files('tzdata.zoneinfo').joinpath('iso3166.tab').open('r') as f:
    country_names = dict(
        line.rstrip('\n').split('\t', 1)
        for line in f
        if not line.startswith('#')
    )

Note, for Django's field choices, it would be easier to create a list directly, instead of a dict.

ORIGINAL (Django <4.0)

Django (<4.0) uses pytz (see e.g. django.utils.timezone), and pytz exposes a country_names dictionary, based on ISO 3166 (see pytz docs).

This pytz.country_names dictionary can be used to set your model field choices, or form field choices.

This might not cover all edge cases, but, at least, it does not add another obscure external dependency to your Django project.

Example for a model field (import pytz first):

country = models.CharField(max_length=2, choices=pytz.country_names.items())

Note that the dict keys (country codes) are all capitals.

One other thing to keep in mind, in case pytz is updated: as mentioned in the Django Model field reference

A new migration is created each time the order of choices changes.

Evieevil answered 19/6, 2020 at 13:58 Comment(0)
L
3

Here is a nice library with countries (and not only): pycountry

Its main advantage is that it is a wrapper around Debian package pkg-isocodes (thus can updates automatically with it) compared to hard-coded countries in other solutions. It also has translations.

So if new country appears or existing countries will be merged together you do not need to change your code.

I found it useful to use this library and create a simple Django app with model Country for example

Then you can populate and keep up-to-date your 'country' table by means of custom django-admin command as described here: Writing custom django-admin commands

Lampion answered 20/1, 2014 at 21:45 Comment(0)
Y
2

Link to package : django-countries
If looking for how to do it in forms :

$ pip install django-countries

>>> from django_countries.data import COUNTRIES

>>> Country = forms.ChoiceField(choices = sorted(COUNTRIES.items()))
Yuriyuria answered 24/1, 2019 at 1:52 Comment(1)
consider adding a link to the packageCustody
C
1

Put them in the database is a better way. Convenient to management.

Cullan answered 24/1, 2012 at 9:46 Comment(0)
V
1

I solved it by using multiple=True:

from django_countries.fields import CountryField    

class UserProfile(models.Model):
    countries = CountryField(multiple=True)

You can read more about it in the docs:

https://github.com/SmileyChris/django-countries

Viole answered 20/8, 2018 at 20:29 Comment(0)
P
1

If you just want to have a country ChoiceField without installing django-choices you can create an extra file which holds a tuple with all choices from the Wikipedia Iso Country Codes:

import csv


# Get the file from: "http://geohack.net/gis/wikipedia-iso-country-codes.csv"
with open("wikipedia-iso-country-codes.csv") as f:
    file = csv.DictReader(f, delimiter=',')
    country_names = [line['English short name lower case'] for line in file]

# Create a tuple with the country names
with open("country_names.py", 'w') as f:
    f.write('COUNTRY_CHOICES = (\n')
    for c in country_names:
        f.write(f'    ("{c}", "{c}"),\n')
    f.write(')')

The created country_names.py file looks something like this:

COUNTRY_CHOICES = (
    ("Afghanistan", "Afghanistan"),
    ("Åland Islands", "Åland Islands"),
    ("Albania", "Albania"),
    ("Algeria", "Algeria"),
    ("American Samoa", "American Samoa"),
    ...
)

You can then use COUNTRY_CHOICES in your form like this:

from django import forms
from country_names import COUNTRY_CHOICES


class CountryForm(forms.Form):
    country= forms.ChoiceField(choices=COUNTRY_CHOICES)
Phyllome answered 5/10, 2021 at 12:58 Comment(0)
I
0

Here is the solution:

from django_countries.fields import CountryField

class Foo(TimeStampedModel):

    country = CountryField()
Impellent answered 26/9, 2014 at 23:16 Comment(0)
H
0

SmileyChris seems to be pretty busy and unavailable, as the repository hasn't been updated since September. Thankfully, there is a repository that can be forked that is compatible with Django 3 and higher. This can be found here:

https://github.com/yunojuno/django-countries/tree/django-30

It passes all checks for a pull request, however SmileyChris has not responded to the merge request.

To install it just run pip install git+https://github.com/yunojuno/django-countries.git

Helium answered 6/1, 2020 at 6:13 Comment(0)
B
0

If you are extending forms.Form class then you have to specify .formfield right after your Countryfield and then specify your attributes in formfield() parameter.

from django_countries.fields import CountryField
class CheckOutForm(forms.Form):
    country = CountryField().formfield()

But if you are extending from models.Model class then defining Coutryfield is enough.

from django_countries.fields import CountryField
    class CheckOutForm(models.Model):
        country = CountryField()
Bohannon answered 8/3, 2020 at 6:21 Comment(0)
C
0

I guess, instead of trying with models fields such as ChoiceField or CharField and passing 'choices' as a parameter which contains list of countries as tuple values inside the list created outside in the models.py, Django has compact library to work with selecting country while filling the form.

from django-countries.fields import CountryField

class foo(models.Model):
   country = CountryField(blank_label='select country')
   ...
Cristicristian answered 19/8, 2021 at 8:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.