[英]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.