簡體   English   中英

通過模型形式將非規范化數據導入Django模型

[英]Importing Denormalized data into django models via modelforms

場景:

我有一些看起來像這樣的數據:

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

假設它是一個平面文件,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是錯誤的事情嗎?

嘗試以下代碼:

insert_data = []

with open('data.txt') as f:
    state = 'HEADER'
    headers = []
    for line in f.readlines():
        if state == 'HEADER':
            headers = [header.lower().strip().replace(' ', '_') for header in line.split('|')]
            state = 'IGNORE'
        elif state == 'IGNORE':
            state = 'DATA'
        elif state == 'DATA':
            data_values = map(str.strip, line.split('|'))
            insert_entry = {}
            for key, data in zip(headers, data_values):
                insert_entry[key] = data
            insert_data.append(insert_entry)

for row in insert_data:
    form = PersonForm(row)

    if form.is_valid():
        form.save()
    else:
        print form.errors()

第一步是讀取文件(假設文件名為data.txt),我建議您使用json或其他一些結構化文本以避免輸入錯誤,因為您可以首先檢查文件是否已使用知名庫進行了正確格式化。

為了使此腳本正常工作,您還需要技巧來填寫表單中的字段,我認為將PERSON字段稱為NAME就足夠了。

在第二步中,我們為要插入的每個條目創建表單實例,驗證它們,如果一切正常,則將它們保存到數據庫中。

希望能幫助到你,

我提出了部分解決方案,至少是針對涉及選擇的問題。 我猜想也許它也可以適用於ForeignKey字段。

首先,我定義一個函數get_choice_by_name ,該函數經歷一個選擇元組並按值查找鍵。

然后,我將TypedChoiceField子類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__'

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM