python - 保存时跳过字段(Django 模型、插入和更新)

标签 python sql django django-models orm

给定 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'])

我的soapProdQ​​uery 仅返回这4 个字段,其中模型中有第5 个字段(soap_ip)。我知道这可能不是最好的方法,但我有一个单独的代码块来查询数据库中的 soap_ipNone在它们上运行一个子进程主机,并用 ip 地址将其保存回来(每次通过时返回/更新的行数应该变小,而不是将用于执行主机查找的逻辑放入请求/此 celery 任务本身,这会运行每个API请求。我已经尝试过这个,它需要永远返回完整的数据。)。我查询的soap API不提供IP,否则我显然会以这种方式获取它。这一切都使用 celery 作为后台任务运行,以使其对网络用户不可见/无缝。

我遇到的问题是,每次 saveSoapProd() 运行时,它都会用 '0.0.0.0' 覆盖之前的 soap_ip 字段从而否定了我其他职能的工作。另一个问题是我不能 force_insertforce_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_onlyupdate_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:以下字段在此模型中不存在或者是 m2m 字段:soap_id

因为您尝试更新 soap_id,所以该字段被定义为模型的主键,因此更新时它是不可变的。这就是为什么当你这样做时它会崩溃:

commit.save(update_fields=['soap_id', 'soap_host', 'soap_asset', 'soap_state'])

尝试从 update_fields 中删除 soap_id

关于python - 保存时跳过字段(Django 模型、插入和更新),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29758695/

相关文章:

django - 避免 makemigrations 重新创建日期字段

python - 值相等时的 numpy argmax

python - 如何让 python 加载混合模式 .dll 引用的 .NET .dll?

python - Django-taggit 向对象添加新标签?

python - 调用 Python C 扩展会阻止所有 Django 进程/用户

sql - 在 t-sql 中验证日期?

python - 使用 raw_input 让用户输入变量名并使用它的值

python - Pandas - 第一次找到条件为真的索引

sql - 如何在 SQL Server 中批量插入印地语文本

sql - SQL 中的撇号选择整个表