通过模型将非规范化数据导入django模型

时间:2015-09-22 14:31:28

标签: python django django-models import flat-file

场景:

我有一些看起来像这样的数据:

Person   | Favorite Color | Favorite Fruit
------------------------------------------
Bobby    | RED            | BANANA
Jared    | YELLOW         | RASPBERRY
Milly    | BLACK          | PEACH
Shawn    | ORANGE         | ORANGE

假设它处于flatfile,python dicts或其他非sql格式中。

编辑:假设为了论证,我已经在Python结构中得到了它,看起来像这样:

data = [
    {"name": "Bobby", "favorite_color": "RED", "favorite_fruit": "BANANA"},
    {"name": "Jared", "favorite_color": "YELLOW", "favorite_fruit": "RASPBERRY"},
    # etc....
 ]

我的django模型看起来像这样:

class Person(models.Model):
    COLORS = (
                 ('R', 'RED'),
                 ('O', 'ORANGE'),
                 ('Y', 'YELLOW'),
                 ('G', 'GREEN'),
                 ('B', 'BLUE'),
                 ('P', 'PURPLE'),
                 ('L', 'BLACK'),
                 ('W', 'WHITE')
              )
    name = CharField(max_length=256)
    favorite_color = CharField(max_length=1, choices=COLORS)
    favorite_fruit = ForeignKey(Fruit)

class Fruit(models.Model):
    name = CharField(max_length=256)
    fructose_content = PositiveIntegerField()

编辑:假设我的Fruit模型已填充了所有可能的成果。

任务:

我想使用ModelForm将我的数据从原始源导入到我的Django模型中,以利用正确的验证和数据库抽象。

class PersonForm(forms.ModelForm):
    class Meta:
        model = Person
        fields = '__all__'

ModelForm是否可以将非规范化数据转换为可以保存在模型中的数据? ModelForm在这里使用是错误的吗?

2 个答案:

答案 0 :(得分:0)

请尝试以下代码:

setnames(DT, "0b", "something_digestible")

第一步是读取文件(假设它名为data.txt),我建议您使用json或其他一些结构化文本来避免输入错误,因为您可以先检查文件是否使用众所周知的格式良好库。

要使这个脚本起作用,你还需要一个表单中字段的技巧,我认为将PERSON字段称为NAME就足够了。

在第二步,我们为每个要插入的条目创建表单实例,验证它们,如果一切正常,我们将它们保存到数据库中。

希望它有所帮助,

答案 1 :(得分:0)

我提出了部分解决方案,至少对于涉及选择的问题。我想通过一些修补,它也适用于ForeignKey字段。

首先,我定义一个函数get_choice_by_name,它通过一个选择元组并按值查找键。

然后我将TypedChoiceField子类化,并覆盖其clean()方法以转换数据。在任何验证之前,似乎都会调用此方法。

以下是代码:

def get_choice_by_name(name, choices, case_sensitive=False):
    try:
        if name is None:
            return ''
        elif name and not case_sensitive:
            return next(k for k, n in choices
                        if n.lower() == name.lower())
        else:
            return next(k for k, n in choices if n == name)
    except StopIteration:
        raise ValueError(
            "Invalid choice: {}, not found in {}".format(name, choices)
        )

class DenormalizedChoiceField(TypedChoiceField):

    def clean(self, value):
        if not value:
            return self.empty_value
        try:
            value = get_choice_by_name(value, self.choices)
        except ValueError as e:
            raise ValidationError(str(e))

        value = super(DenormalizedChoiceField, self).clean(value)
        return value

我的ModelForm现在只需要将相关字段重新定义为DenormalizedChoiceField。我需要明确指定选项,但由于某些原因,如果覆盖该字段,它不会从模型中选择它。

class PersonForm(forms.ModelForm):
    favorite_color = DenormalizedChoiceField(choices=Person.COLORS)
    class Meta:
        model = Person
        fields = '__all__'