在Django脚本中保存数据到一列而不删除其他列

0 投票
2 回答
633 浏览
提问于 2025-04-17 04:46

我有一个模型,结构是这样的:

class Data(models.Model):
    some_id = models.IntegerField(primary_key=True)
    data1 = models.IntegerField()
    data2 = models.IntegerField()
    data3 = models.CharField(max_length=150)

我从不同的文件中读取数据,并使用文件中的表头信息来确定这些数据应该保存到哪个列。数据库中的每个列名都是唯一的,所以我也用它们来指向相应的表。

有时候,数据库中的某一行已经有数据了,我需要往其他列添加数据。我是在Django的命令行中运行Python代码来完成这个操作。不过,如果我指定一个主键(pk)或者某个'id'来保存数据到某一列,其他列的数据就会被覆盖成None。举个例子,如果我的代码是这样的:

data_args = {}
data_args['some_id'] = 0
data_args['data2'] = 100

data_entry = Data(**data_args)

data_entry.save()

而且这个条目的data1和data3已经有数据了,执行save()后,它们会变成None。

因为我是在脚本中运行这个,而我的列名是从表头读取的字符串,所以我一直没法按照文档中的例子那样更新数据,比如:

data_entry = Data.objects.get(some_id=0)
data_entry.data2=100
data_entry.save()

虽然在命令行中这样做是有效的,但在Python代码中,当'data2'是从文件表头读取的字符串时,就不行了。

补充说明:抱歉之前没有说清楚。我想省略一些复杂的细节。当我说上面的(正确的)代码在我的脚本中不工作时,我是从一个看起来像这样的文件表头中获取列名'data2':

some_id|data1|data2|data3

我使用numpy.genfromtxt来解析文件中的数据,这样可以获取数据列的名称,格式是:

data_array.dtype.names = ('some_id', 'data1', 'data2', 'data3')

所以,假设Data中的第一个条目已经存在,如果我尝试保存到一个没有数据的列:

single_arg = data_array.dtype.names[2]
data_entry = Data.objects.get(some_id=0)
data_entry.single_arg = 100
data_entry.save()

值100并没有被保存到第一个条目的'data2'列中。我得到的值仍然是None。在我执行这个操作的循环中,在save()之前,我打印了single_arg(在这个例子中是data2),还有我尝试赋值给data_entry.single_arg的变量(在这个例子中是100),以及data_entry.single_arg本身(在这个例子中应该是100),它们看起来都是正确的。

但是,出于某种原因,这个值并没有被保存到数据库中。如果上面的代码是正确的,那我的问题可能出在其他地方。

进一步补充:

正如我所想的,问题似乎在于single_arg在data_entry.single_arg中没有被识别为'data2'。在save()之后,如果我重新查询数据库并尝试打印应该被保存的内容:

data_entry = Data.objects.get(some_id=0)
single_arg = data_array.dtype.names[2]
print data_entry.single_arg

我得到了这个错误:

AttributeError: 'Data' object has no attribute 'single_arg'

所以,可能在脚本中整个字符串"data_entry.single_arg"的值是100,但对象data_entry.data2实际上并没有被访问到。也许是这样。

所以我的问题是,如何在保存数据到一列(或多列)的同时,保留同一行中其他列的现有数据呢?

2 个回答

0

你问的问题的总体答案是,当你执行

data_entry = Data(**data_args)
data_entry.save()

这段代码时,你是在往数据库里保存一个新记录;如果你没有填写某些值,这些值就会使用默认值或者变成NULL,这取决于模型字段的定义。如果你想修改一个已经存在的记录,你需要先从数据库中把它取出来,就像你第二段代码那样:

data_entry = Data.objects.get(some_id=0) # populates data_entry object with values from db
data_entry.data2=100
data_entry.save()

如果在你的脚本中,这段代码看起来像是在覆盖你已有的值,那可能是其他地方出现了问题。我建议你在第一次从数据库中取出对象时,打印出它的值,这样可能会发现问题出在更早的地方。打印一个模型实例所有值的一个方便方法是:

print data_entry.__dict__
1

你把查找属性和 getattr 搞混了。你不能通过输入 data.single_arg 来把字符串变成属性——Python 怎么知道你是想用变量的值还是属性的名字呢?

single_arg = 'data2'
data.single_arg = 100

# you can NOT set an attribute by a string this way. 
# You're just setting an attribute called single_arg to 100 which isn't a model 
# field, so it's not going to be saved.

如果你想通过字符串来设置一个属性,你需要用 setattr

single_arg = 'data2'
data = Data.objects.get(id=1)
setattr(data, single_arg, 100)
data.save()

你最后的例子是正常的…… data_entry 没有 single_arg 这个属性。如果你想获取变量 single_arg 中提到的字符串属性,你需要调用 getattr(data_entry, single_arg)

撰写回答