[英]Skipping a field on save (Django models, Insert and Update)
给定PostgreSQL 9.2.10,Django 1.8,python 2.7.5,以下模型:
class soapProdAPI(models.Model):
soap_id = models.PositiveIntegerField(primary_key=True)
soap_host = models.CharField(max_length=20)
soap_ip = models.GenericIPAddressField(default='0.0.0.0')
soap_asset = models.CharField(max_length=20)
soap_state = models.CharField(max_length=20)
和以下代码:
tableProdSoap = soapProdQuery()
@periodic_task(run_every=timedelta(minutes=2))
def saveSoapProd():
tableProdSoap = soapProdQuery()
if tableProdSoap != None:
for item in tableProdSoap:
commit = soapProdAPI(soap_id=item[0], soap_host=item[1], soap_asset=item[2], soap_state=item[3])
commit.save()
saveSoapNullIP()
要回答JosuéPadilla的问题:
@task
def saveSoapNullIP():
missingIP = soapProdAPI.objects.filter(soap_ip='0.0.0.0')
if missingIP:
for record in missingIP:
if str(record.soap_host).lower().startswith('1a'):
fqdn = str(record.soap_host) + 'stringvaluehere'
elif str(record.soap_host).lower().startswith('1b'):
fqdn = str(record.soap_host) + 'stringvaluehere'
elif str(record.soap_host).lower().startswith('1c'):
fqdn = str(record.soap_host) + 'stringvaluehere'
else:
fqdn = str(record.soap_host) + 'stringvaluehere'
try:
hostIp = check_output('host %s' % fqdn, shell=True)
hostIp = hostIp.split()[-1]
except:
hostIp = '0.0.0.0'
record.soap_ip = hostIp
record.save(update_fields=['soap_ip'])
我的soapProdQuery仅返回模型中第5个字段( soap_ip
)的这4个字段。 我知道这可能不是最好的方法,但是我有一个单独的代码块,可在db中查询soap_ip
None
值, soap_ip
在它们上运行一个子soap_ip
主机,并将其保存回ip地址(返回的行数/与每次执行API请求的主机查询逻辑相比,经过更新的每次通过操作都应该变小,因为它将运行每个API请求。我已经尝试过,永远需要返回完整的数据。) 。 我查询的soap API不提供IP,或者显然我会以这种方式获取它。 所有这些操作都使用celery作为后台任务运行,以使其对Web用户不可见/无缝。
我遇到的问题是,每次运行saveSoapProd()
,它soap_ip
用'0.0.0.0'
覆盖以前的soap_ip
字段,从而使我的其他函数soap_ip
工作。 另一个问题是我无法force_insert
或force_update
因为我需要这两个功能。 我的问题是这样的:有没有一种方法可以同时有选择地更新/插入并在每次saveSoapProd()
运行时完全排除对soap_ip
做任何事情? 任何帮助都将不胜感激。 先感谢您。
** 编辑1 **
我可能会或可能不会在update_or_create或get_or_create中找到解决方案,但是我不确定确切的用法。 文档让我有些困惑。
** 编辑2 **
我猜get_or_create是一个破产。 可以先通过工程,但是此后的每次保存都会失败:
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "<console>", line 8, in saveSoapProd
File "/lib/python2.7/site-packages/django/db/models/base.py", line 690, in save
% ', '.join(non_model_fields))
ValueError: The following fields do not exist in this model or are m2m fields: soap_id
这是代码:
@periodic_task(run_every=timedelta(minutes=2))
def saveSoapProd():
tableProdSoap = soapProdQuery()
if tableProdSoap != None:
for item in tableProdSoap:
obj, created = soapProdAPI.objects.get_or_create(soap_id=item[0], defaults={'soap_host': item[1], 'soap_asset': item[2], 'soap_state': item[3]})
if created == False:
commit = soapProdAPI(soap_id=item[0], soap_host=item[1], soap_asset=item[2], soap_state=item[3])
commit.save(update_fields=['soap_id', 'soap_host', 'soap_asset', 'soap_state'])
老实说,我不太确定是什么导致了此错误。
** 编辑3 /当前解决方案 **
通过修改模型和任务功能,我能够解决自己的问题。 该解决方案使用get_or_create,但是您可以轻松地从提供的解决方案中推断出如何使用update_or_create。 有关编码示例,请参见下面的选定答案。
** TLDR **
我想做一个.save(),其中可能需要插入新记录或更新已更改的记录,而无需触摸soap_ip
字段(没有insert_only
或update_only
)。
我不知道您是否已经知道这一点,但是您可以覆盖模型的save()函数。
class soapProdAPI(models.Model):
soap_id = models.PositiveIntegerField(primary_key=True)
soap_host = models.CharField(max_length=20)
soap_ip = models.GenericIPAddressField(default='0.0.0.0')
soap_asset = models.CharField(max_length=20)
soap_state = models.CharField(max_length=20)
# Override save
def save(self, *args, **kwargs):
if self.soap_ip != '0.0.0.0':
self.soap_ip = your_ip # Here you can get your old IP an save that instead of 0.0.0.0
编辑
你越来越
ValueError: The following fields do not exist in this model or are m2m fields: soap_id
因为您正在尝试更新soap_id
,所以该字段被定义为模型的主键,因此在更新时它是不变的。 这就是为什么当您这样做时它会崩溃:
commit.save(update_fields=['soap_id', 'soap_host', 'soap_asset', 'soap_state'])
尝试删除soap_id
从update_fields
。
通过对模型进行以下更改来解决我自己的问题,而无需修改save方法:
class soapProdAPI(models.Model):
soap_id = models.PositiveIntegerField(unique=True, null=False)
soap_host = models.CharField(max_length=20)
soap_ip = models.GenericIPAddressField(default='0.0.0.0')
soap_asset = models.CharField(max_length=20)
soap_state = models.CharField(max_length=20)
和我的任务:
def saveSoapProd():
tableProdSoap = soapProdQuery()
if tableProdSoap != None:
for item in tableProdSoap:
try:
obj, created = soapProdAPI.objects.get_or_create(soap_id=item[0], defaults={'soap_host': item[1], 'soap_asset': item[2], 'soap_state': item[3]})
if created == False:
obj.soap_host = item[1]
obj.soap_asset = item[2]
obj.soap_state = item[3]
obj.save(update_fields=['soap_host', 'soap_asset', 'soap_state'])
except:
continue
saveSoapMissingIP()
编辑
刚注意到JosuéPadilla的回答,这实际上是我通过此答案解决的问题的一部分。 感谢Josué的所有帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.