Django:国家下拉列表?

发布于 2024-09-03 14:58:05 字数 167 浏览 7 评论 0原文

我有一张地址信息表格。其中一个字段用于地址国家/地区。目前这只是一个文本框。我想要一个(ISO 3166 国家/地区)的下拉列表。我是 Django 新手,所以我什至还没有使用过 Django Select 小部件。有什么好的方法可以做到这一点?

将选项硬编码到文件中的某处?把它们存入数据库?在模板中?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(16

走野 2024-09-10 14:58:05

查看 CharField 的“choices”参数。

您可能还想查看 django-countries

Check out "choices" parameter of a CharField.

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

阳光的暖冬 2024-09-10 14:58:05

Django 国家

from django_countries.fields import CountryField

class Foo(models.Model):
    country = CountryField()

Django Countries

from django_countries.fields import CountryField

class Foo(models.Model):
    country = CountryField()
自我难过 2024-09-10 14:58:05

最终使用下面的代码片段,它基本上定义了两个字符国家/地区代码的元组的元组。此外,它定义了一个名为 CountryField 的自定义字段类型,并将选择参数默认为上面定义的元组。这会自动呈现为下拉列表。

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

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/

情绪操控生活 2024-09-10 14:58:05

姜戈国家

from django_countries.countries import COUNTRIES

class CountryForm(forms.Form):
      country= forms.ChoiceField(COUNTRIES)

Django Countries

from django_countries.countries import COUNTRIES

class CountryForm(forms.Form):
      country= forms.ChoiceField(COUNTRIES)
谎言月老 2024-09-10 14:58:05

正如之前的答案所述,django-countries 中有一个 CountryField。这是一个模型字段。

如果需要普通表单(不是模型表单)的表单字段,在 django-countries v3.x 中(在 3.3 中确实经过测试)可以使用以下内容:

from django_countries.data import COUNTRIES

class MyForm(forms.Form):
    country = forms.ChoiceField(sorted(COUNTRIES.items()))

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()))
小霸王臭丫头 2024-09-10 14:58:05

更新(Django >=4.0)

在较旧的 Django 版本中使用 pytz.country_names 很方便,如下所述,但 Django >=4.0 使用 zoneinfo 而不是 pytz。详细信息请参见发行说明和< a href="https://pytz-deprecation-shim.readthedocs.io/en/latest/index.html" rel="nofollow noreferrer">此处。

不幸的是,zoneinfo 似乎没有提供 pytz.country_names 的等效项(据我所知)。

然而,Python(第一方)中有一个最新的 ISO 3166 国家/地区名称列表 tzdata 包:iso3166.tab

请注意,tzdata已经安装

仅出于说明目的,这里有一个快速&将 iso3166.tab 文件解析为类似于 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('#')
    )

注意,对于 Django 的字段选择,直接创建 list 会比创建 dict 更容易。

原始版本 (Django <4.0)

Django (<4.0) 使用 pytz (参见例如 django.utils.timezone),并且 pytz 公开一个 country_names 字典,基于ISO 3166(请参阅 pytz 文档)。

这个 pytz.country_names 字典可用于设置您的 模型字段选择,或表单字段选择。

这可能无法涵盖所有​​边缘情况,但至少,它不会向您的 Django 项目添加另一个模糊的外部依赖项。

模型字段示例(首先 import pytz):

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

请注意,字典键(国家/地区代码)均为大写。

另一件要记住的事情是,如果 pytz 被更新:如 Django 模型字段参考

每次选择顺序发生变化时都会创建一个新的迁移。

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.

猫卆 2024-09-10 14:58:05

这是一个很好的库,其中包含国家/地区(不仅如此): pycountry

它的主要内容与其他解决方案中的硬编码国家/地区相比,它的优点是它是 Debian 软件包 pkg-isocodes 的包装器(因此可以使用它自动更新)。它还有翻译。

因此,如果出现新的国家/地区或现有国家/地区将合并在一起,您无需更改代码。

我发现使用这个库并使用模型 Country 创建一个简单的 Django 应用程序很有用,

然后您可以通过自定义 django-admin 命令填充并保持最新的“国家/地区”表,如下所述:编写自定义 django-admin 命令

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

宛菡 2024-09-10 14:58:05

链接到包:django-countries
如果寻找如何以表格形式进行操作:

$ pip install django-countries

>>> from django_countries.data import COUNTRIES

>>> Country = forms.ChoiceField(choices = sorted(COUNTRIES.items()))

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()))
说谎友 2024-09-10 14:58:05

将它们放入数据库是更好的方法。方便管理。

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

心房的律动 2024-09-10 14:58:05

我通过使用 multiple=True 解决了这个问题:

from django_countries.fields import CountryField    

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

您可以在文档中阅读更多相关信息:

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

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

爱人如己 2024-09-10 14:58:05

如果您只想拥有一个国家/地区 ChoiceField 而不安装 django-choices 您可以创建一个额外的文件,其中包含 Wikipedia Iso 国家/地区代码 中的所有选择的元组:

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(')')

创建的country_names.py文件看起来像这样:

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

然后您可以在表单中使用COUNTRY_CHOICES,如下所示:

from django import forms
from country_names import COUNTRY_CHOICES


class CountryForm(forms.Form):
    country= forms.ChoiceField(choices=COUNTRY_CHOICES)

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)
情深缘浅 2024-09-10 14:58:05

这是解决方案:

from django_countries.fields import CountryField

class Foo(TimeStampedModel):

    country = CountryField()

Here is the solution:

from django_countries.fields import CountryField

class Foo(TimeStampedModel):

    country = CountryField()
你好,陌生人 2024-09-10 14:58:05

SmileyChris 似乎很忙而且没空,因为存储库自 9 月份以来就没有更新过。值得庆幸的是,有一个可以分叉的存储库与 Django 3 及更高版本兼容。可以在这里找到:

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

它通过了拉取请求的所有检查,但是 SmileyChris 尚未响应合并请求。

要安装它,只需运行 pip install git+https://github.com/yunojuno/django-countries.git

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

池木 2024-09-10 14:58:05

如果您要扩展 forms.Form 类,那么您必须在 Countryfield 之后指定 .formfield ,然后在 formfield() 参数中指定您的属性。

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

但如果您从 models.Model 类扩展,那么定义 Coutryfield 就足够了。

from django_countries.fields import CountryField
    class CheckOutForm(models.Model):
        country = CountryField()

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()
怀中猫帐中妖 2024-09-10 14:58:05

我想,不要尝试使用诸如 ChoiceFieldCharField 之类的模型字段,并将“选择”作为参数传递,其中包含国家/地区列表作为在外部创建的列表中的元组值models.py,Django 有一个紧凑的库,可以在填写表单时选择国家/地区。

from django-countries.fields import CountryField

class foo(models.Model):
   country = CountryField(blank_label='select country')
   ...

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')
   ...
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文