【问题标题】:Does the django_address module provide a way to seed the initial country data?django_address 模块是否提供了一种播种初始国家数据的方法?
【发布时间】:2020-01-27 20:42:52
【问题描述】:

我正在使用 Django 2.0、Python 3.7 和 MySql 5。我最近安装了 django_address 模块。我注意到当我基于我的 models.py 文件运行我的初始迁移时......

from django.db import models

from address.models import AddressField
from phonenumber_field.modelfields import PhoneNumberField


class CoopType(models.Model):
    name = models.CharField(max_length=200, null=False)

    class Meta:
        unique_together = ("name",)


class Coop(models.Model):
    type = models.ForeignKey(CoopType, on_delete=None)
    address = AddressField(on_delete=models.CASCADE)
    enabled = models.BooleanField(default=True, null=False)
    phone = PhoneNumberField(null=True)
    email = models.EmailField(null=True)
    web_site = models.TextField()

它创建了一些地址表,包括...

mysql> show create table address_country;
+-----------------+---------------------------------------------------+
| Table           | Create Table                                      |
+-----------------+---------------------------------------------------+
| address_country | CREATE TABLE `address_country` (                  |
|                 |   `id` int(11) NOT NULL AUTO_INCREMENT,           |
|                 |   `name` varchar(40) COLLATE utf8_bin NOT NULL,   |
|                 |   `code` varchar(2) COLLATE utf8_bin NOT NULL,    |
|                 |   PRIMARY KEY (`id`),                             |
|                 |   UNIQUE KEY `name` (`name`)                      |
|                 | ) ENGINE=InnoDB                                   |
|                 | DEFAULT CHARSET=utf8 COLLATE=utf8_bin             |
+-----------------+---------------------------------------------------+

但是,此表中没有数据。有没有办法获取模块生成的表的种子数据还是需要我自己去挖掘?

【问题讨论】:

  • 如果this one,你使用的是哪个django_address?
  • 是的,就是这个!当然,如果有更好的模块可以创建 AddressField 模型类型并提供一些默认种子信息,我愿意切换。
  • 您使用 django_address 的意图是什么?你想知道合作社的完整地址还是他们的国家?你能详细解释一下你期望达到的目标吗?

标签: python django python-3.x seeding


【解决方案1】:

您可以使用pycountry package 轻松自己生成国家/地区。

由于创建的Country 模型上的code 字段的最大长度为两个字符,因此您需要使用alpha_2 代码。

我通常使用custom management command 来处理这类事情。也许添加一个检查以查看是否已经创建了任何对象,然后根据需要进行处理。

从shell使用python manage.py create_countries

from address.models import Country
from pycountry import countries
from django.core.management.base import BaseCommand

class Command(BaseCommand):
    help = 'Initialize Country model'

    def handle(self, *args, **kwargs):
        create_countries = [
            Country(name=country.name[:40], code=country.alpha_2)
            for country in countries
        ]
        Country.objects.bulk_create(create_countries)
        self.stdout.write(f'Created {len(countries)} countries.\n')

如果生产服务器没有运行 Python/Django,那么您可以使用 pycountry 创建包含相关数据的 CSV 文件。假设您使用的是 PostgreSQL,那么您可以使用 COPY FROM command 来填充数据库。

import csv
from pycountry import countries

with open('countries.csv', mode='w') as countries_file:
    # specify delimiter because some countries have a comma
    writer = csv.writer(countries_file, delimiter='\t')
    writer.writerow(['id', 'name', 'code'])
    writer.writerows([
        [index + 1, country.name, country.alpha_2]
        for index, country in enumerate(countries)
    ])

【讨论】:

  • 谢谢,我想这让我更接近了。我想要数据库中的数据,因为我将导出到另一个可能使用或不使用 Python 的系统。那么您的建议是使用上述脚本生成迁移以填充数据库?
  • 以上脚本将在数据库中生成 249 条记录 - 每个国家/地区一条。
  • K,所以我安装了 pycountry (pycountry-19.8.18.tar.gz),当我运行上面的脚本时,你让它因错误而死,“django.db.utils.DataError: ( 1406, "对于第 196 行的列 'name' 而言,数据太长")"。
  • @Dave 好吧,刚刚查看了您的 OP,似乎 name 字段的最大字符数为 40,我添加了一个编辑,将字符串分割为 40 个字符
  • @Dave 有趣的选择得到了赏金的答案......哈哈
【解决方案2】:

我建议您编写一个简单的管理命令,将来自pycountry 的数据导入您的地址模型(从here 借用的方法)。 pycountry 是 ISO 标准国家/地区列表的包装器 - 即,它与您将获得的国家/地区列表一样规范。

将所有国家/地区填充到您的 Country 模型中的 management command 看起来像这样:

import pycountry
from django.core.management.base import BaseCommand, CommandError

from address.models import Country

class Command(BaseCommand):
    help = "Populates address.Country with data from pycountry."

    def handle(self, *args, **options):
        countries = [
            Country(
                code=country.alpha_2,
                name=country.name[:40],  # NOTE - concat to 40 chars because of limit on the model field
            )
            for country in pycountry.countries
        ]

        Country.objects.bulk_create(countries)
        self.stdout.write("Successfully added %s countries." % len(countries))

这将使用 ISO 国家/地区列表填充您的模型。

这里需要注意的是address.Country.name 字段限制为 40 个字符(这对我来说似乎是一个有问题的设计决定,以及不使国家/地区代码唯一的决定 - ISO 2 字母代码绝对是唯一的),所以上面的脚本会截断名称以适应。如果这对您来说是个问题,我建议您建立自己的地址模型,借鉴django-address 并提高字符数限制。

【讨论】:

  • (发帖后我注意到bdoubleu已经提供了一个非常相似的解决方案。这个答案将解决name字段有字符限制的问题)。
【解决方案3】:

如上所述,您需要自己添加实际数据。您需要准备它并进行一次性上传。如果您只查找国家/地区数据,this is a good source。还有一个名为 django-countries 的 django 应用程序,它可以让您拥有更多数据和控件,包括标志、ISO 代码等。另一个具有 3 个字母代码的数据库是 IBAN list。希望对您有所帮助。

【讨论】:

  • 我正在查看您链接到的 django-countries 存储库,但我没有在其中看到任何种子数据或迁移。我期待找到一个带有python数据的fixtures文件夹或其他东西。我错过了什么吗?
  • 我建议您使用其他两个来源作为种子数据。 Django-countries 是供您用作国家数据的经过良好测试的下拉菜单。另请查看此部分 github.com/SmileyChris/django-countries/blob/master/… 。 ioc 代码在同一个文件夹中。
【解决方案4】:

您可以使用 django-countries 并在模型中包含 CountryField。这包括对模型的支持和表单的选择字段。

由于这是内置的,因此您可以将其包含在您的模型中,而不必担心为表格播种。

【讨论】:

  • 这并不能以任何方式回答 OP 问题,下面也已经推荐了这个包。
  • @CalMac,所以我理解你的建议,我上面列出的 django-address 模块是否与你列出的 django-countries 模型有任何兼容性?获取国家列表很棒,但是对于您的模块,它如何与 django-address 相关联?
【解决方案5】:

简单更好。通过 django 文档,您可以创建数据迁移:https://docs.djangoproject.com/en/3.0/topics/migrations/#data-migrations

假设您的models.py 的应用名称是coops,请执行以下操作:

第一:

第二:

  • django_countries 添加到INSTALLED_APPS

第三:

  • 制作一个空的迁移文件:python manage.py makemigrations --empty coops

第四:

  • 编辑迁移文件,例如:vi coops/migrations/0002_auto_20200205_0421.py
  • 文件内容:
# Generated by Django 2.2 on 2020-02-05 04:21

from django.db import migrations


def init_countries(apps, schema_editor):
    from django_countries import countries
    from address.models import Country
    countries = [
        Country(code=code, name=name) for code, name in countries
    ]
    Country.objects.bulk_create(countries)



class Migration(migrations.Migration):

    dependencies = [
        ('coops', '0001_initial'),
    ]

    operations = [
        migrations.RunPython(init_countries),
    ]

第五:

  • 运行python manage.py migrate

迁移后的address_country表应该有如下数据:

In [1]: from address.models import *

In [2]: Country.objects.all()
Out[2]: <QuerySet [<Country: Afghanistan>, <Country: Albania>, <Country: Algeria>, <Country: American Samoa>, <Country: Andorra>, <Country: Angola>, <Country: Anguilla>, <Country: Antarctica>, <Country: Antigua and Barbuda>, <Country: Argentina>, <Country: Armenia>, <Country: Aruba>, <Country: Australia>, <Country: Austria>, <Country: Azerbaijan>, <Country: Bahamas>, <Country: Bahrain>, <Country: Bangladesh>, <Country: Barbados>, <Country: Belarus>, '...(remaining elements truncated)...']>

In [3]: Country.objects.all().count()
Out[3]: 249

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-24
    • 2010-12-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多