Opt*_*mus 17 python django json django-models relational-database
我在Django中有一个典型的关系数据库模型,其中典型的模型包含扩展Django的一些ForeignKeys,一些ManyToManyFields和一些字段DateTimeField.
我想保存我从外部api以JSON格式(不是平面)接收的数据.我不是这样,数据被保存到各自的表(而不是整个json字符串到一个字段).这样做最干净,最简单的方法是什么?是否有可用于使此任务更简单的库?
这是一个澄清我的问题的例子,
楷模-
class NinjaData(models.Model):
id = models.IntegerField(primary_key=True, unique=True)
name = models.CharField(max_length=60)
birthdatetime = MyDateTimeField(null=True)
deathdatetime = MyDatetimeField(null=True)
skills = models.ManyToManyField(Skills, null=True)
weapons = models.ManyToManyField(Weapons, null=True)
master = models.ForeignKey(Master, null=True)
class Skills(models.Model):
id = models.IntegerField(primary_key=True, unique=True)
name = models.CharField(max_length=60)
difficulty = models.IntegerField(null=True)
class Weapons(models.Model):
id = models.IntegerField(primary_key=True, unique=True)
name = models.CharField(max_length=60)
weight = models.FloatField(null=True)
class Master(models.Model):
id = models.IntegerField(primary_key=True, unique=True)
name = models.CharField(max_length=60)
is_awesome = models.NullBooleanField()
Run Code Online (Sandbox Code Playgroud)
现在,我通常要将从外部api(秘密忍者api)获得的json字符串数据保存到此模型中,json看起来像这样
JSON-
{
"id":"1234",
"name":"Hitori",
"birthdatetime":"11/05/1999 20:30:00",
"skills":[
{
"id":"3456",
"name":"stealth",
"difficulty":"2"
},
{
"id":"678",
"name":"karate",
"difficulty":"1"
}
],
"weapons":[
{
"id":"878",
"name":"shuriken",
"weight":"0.2"
},
{
"id":"574",
"name":"katana",
"weight":"0.5"
}
],
"master":{
"id":"4",
"name":"Schi fu",
"is_awesome":"true"
}
}
Run Code Online (Sandbox Code Playgroud)
现在用于处理典型ManyToManyField的逻辑非常简单,
逻辑代码 -
data = json.loads(ninja_json)
ninja = NinjaData.objects.create(id=data['id'], name=data['name'])
if 'weapons' in data:
weapons = data['weapons']
for weapon in weapons:
w = Weapons.objects.get_or_create(**weapon) # create a new weapon in Weapon table
ninja.weapons.add(w)
if 'skills' in data:
...
(skipping rest of the code for brevity)
Run Code Online (Sandbox Code Playgroud)
我可以使用很多方法,
view执行将json转换为模型实例的所有工作__init__方法save()方法create,get_or_create,filter等.ManyToManyField并把它放在那里,我想知道是否有一种最明显的方法可以将这种json形式的数据保存到数据库而无需多次编写上述逻辑,那么您建议的最优雅的方法是什么?
感谢大家阅读长篇文章,
Ane*_*pic 10
在我看来,您需要的代码最干净的地方是作为NinjaData模型的自定义管理器上的新Manager方法(例如from_json_string).
我不认为你应该覆盖标准的create,get_or_create等方法,因为你做的事情与他们通常做的有点不同,保持它们正常工作是件好事.
更新: 我意识到我可能在某些时候想要这个,所以我已编码并轻微测试了一个通用函数.由于它递归地通过并影响其他模型,我不再确定它属于一个Manager方法,应该是一个独立的辅助函数.
def create_or_update_and_get(model_class, data):
get_or_create_kwargs = {
model_class._meta.pk.name: data.pop(model_class._meta.pk.name)
}
try:
# get
instance = model_class.objects.get(**get_or_create_kwargs)
except model_class.DoesNotExist:
# create
instance = model_class(**get_or_create_kwargs)
# update (or finish creating)
for key,value in data.items():
field = model_class._meta.get_field(key)
if not field:
continue
if isinstance(field, models.ManyToManyField):
# can't add m2m until parent is saved
continue
elif isinstance(field, models.ForeignKey) and hasattr(value, 'items'):
rel_instance = create_or_update_and_get(field.rel.to, value)
setattr(instance, key, rel_instance)
else:
setattr(instance, key, value)
instance.save()
# now add the m2m relations
for field in model_class._meta.many_to_many:
if field.name in data and hasattr(data[field.name], 'append'):
for obj in data[field.name]:
rel_instance = create_or_update_and_get(field.rel.to, obj)
getattr(instance, field.name).add(rel_instance)
return instance
# for example:
from django.utils.simplejson import simplejson as json
data = json.loads(ninja_json)
ninja = create_or_update_and_get(NinjaData, data)
Run Code Online (Sandbox Code Playgroud)