保存时跳过一个字段(Django 模型、插入和更新)
Skipping a field on save (Django models, Insert and Update)
给定 PostgreSQL 9.2.10,Django 1.8,python2.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 仅 return 这 4 个字段,其中模型中有第 5 个字段 (soap_ip
)。我知道这可能不是 最好的 方法,但我有一个单独的代码块查询数据库 soap_ip
[=84] 中的 None
值=] 是它们的子进程主机,并将其与 ip 地址一起保存(行数 returned/updated 每次通过时应该变小,而不是将进行主机查找的逻辑放入 request/this celery 任务本身会 运行 每个 API 请求。我已经尝试过这个,它需要永远 return 完成的数据。)。我查询的 soap API 没有提供 IP,否则我显然会那样获取它。这所有 运行s 作为后台任务使用 celery 使其 invisible/seamless 给网络用户。
我 运行 遇到的问题是,每次 saveSoapProd()
运行 都会用 '0.0.0.0'
覆盖之前的 soap_ip
字段,从而否定工作我的其他功能。另一个问题是我不能 force_insert
或 force_update
因为我需要这两个功能。我的问题是:有没有办法同时选择性地 update/insert 并完全排除每次 saveSoapProd()
运行 对 soap_ip
做任何事情?非常感谢任何帮助。提前谢谢你。
** 编辑 1 **
我可能在 update_or_create or 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() ,它可能需要插入新记录或更新更改的记录 WITHOUT 接触 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'])
尝试从 update_fields
中删除 soap_id
。
通过对我的模型进行以下更改,在不修改保存方法的情况下解决了我自己的问题:
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é 的帮助。
给定 PostgreSQL 9.2.10,Django 1.8,python2.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 仅 return 这 4 个字段,其中模型中有第 5 个字段 (soap_ip
)。我知道这可能不是 最好的 方法,但我有一个单独的代码块查询数据库 soap_ip
[=84] 中的 None
值=] 是它们的子进程主机,并将其与 ip 地址一起保存(行数 returned/updated 每次通过时应该变小,而不是将进行主机查找的逻辑放入 request/this celery 任务本身会 运行 每个 API 请求。我已经尝试过这个,它需要永远 return 完成的数据。)。我查询的 soap API 没有提供 IP,否则我显然会那样获取它。这所有 运行s 作为后台任务使用 celery 使其 invisible/seamless 给网络用户。
我 运行 遇到的问题是,每次 saveSoapProd()
运行 都会用 '0.0.0.0'
覆盖之前的 soap_ip
字段,从而否定工作我的其他功能。另一个问题是我不能 force_insert
或 force_update
因为我需要这两个功能。我的问题是:有没有办法同时选择性地 update/insert 并完全排除每次 saveSoapProd()
运行 对 soap_ip
做任何事情?非常感谢任何帮助。提前谢谢你。
** 编辑 1 **
我可能在 update_or_create or 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() ,它可能需要插入新记录或更新更改的记录 WITHOUT 接触 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'])
尝试从 update_fields
中删除 soap_id
。
通过对我的模型进行以下更改,在不修改保存方法的情况下解决了我自己的问题:
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é 的帮助。