在保存时跳过字段(Django模型,插入和更新)

时间:2015-04-20 21:25:22

标签: 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仅返回模型中有第5个字段(soap_ip)的这4个字段。我知道这可能不是最好的方法,但我有一个单独的代码块,在None中查询db soap_ip值,在它们上面运行一个子进程主机并使用ip地址将其保存(返回/更新的行数应该在每次传递时变小,而不是将主机查找的逻辑放入请求/此celery任务本身,这将运行每个API请求。我已经尝试过这个,它需要FOREVER返回完成的数据。) soap API我查询不提供IP或我会明显地抓住它。这一切都作为后台任务运行,使用芹菜使其对Web用户不可见/无缝。

我遇到的问题是,每次saveSoapProd()运行时,它都会用soap_ip覆盖以前的'0.0.0.0'字段,从而否定了我的其他功能的工作。另一个问题是我不能force_insertforce_update因为我需要这两个功能。我的问题是:有没有办法有选择地同时更新/插入并完全排除每次soap_ip saveSoapProd()运行时的任何内容?非常感谢任何和所有的帮助。提前谢谢。

** 编辑1 **

我可能会或可能没有在update_or_createget_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字段(无{{1} }或insert_only)。

2 个答案:

答案 0 :(得分:1)

我不知道您是否已经知道这一点,但您可以覆盖模型的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

答案 1 :(得分:0)

通过对我的模型进行以下更改来解决我自己的问题而不修改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é的所有帮助。