简体   繁体   English

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

[英]Skipping a field on save (Django models, Insert and Update)

Given PostgreSQL 9.2.10, Django 1.8, python 2.7.5, the following model: 给定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)

And the following code: 和以下代码:

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()

To answer Josué Padilla's question: 要回答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'])

My soapProdQuery only returns these 4 fields where there is a 5th field in the model ( soap_ip ). 我的soapProdQ​​uery仅返回模型中第5个字段( soap_ip )的这4个字段。 I know it is probably not the best way to do it but I have a separate block of code that queries the db for None values in soap_ip runs a subprocess host on them and saves it back with the ip address (The number of rows returned/updated should get smaller each pass through, as opposed to putting the logic for doing a host lookup into the request/this celery task itself which would run every API request. I have tried this already, it takes FOREVER to return the completed data.). 我知道这可能不是最好的方法,但是我有一个单独的代码块,可在db中查询soap_ip None值, soap_ip在它们上运行一个子soap_ip主机,并将其保存回ip地址(返回的行数/与每次执行API请求的主机查询逻辑相比,经过更新的每次通过操作都应该变小,因为它将运行每个API请求。我已经尝试过,永远需要返回完整的数据。) 。 The soap API I query does not provide the IP or I would grab it that way obviously. 我查询的soap API不提供IP,或者显然我会以这种方式获取它。 This all runs as background tasks using celery to make it invisible/seamless to the web user. 所有这些操作都使用celery作为后台任务运行,以使其对Web用户不可见/无缝。

The issue I run into is that every time the saveSoapProd() runs it overwrites the previous soap_ip field with '0.0.0.0' thus negating the work of my other function. 我遇到的问题是,每次运行saveSoapProd() ,它soap_ip'0.0.0.0'覆盖以前的soap_ip字段,从而使我的其他函数soap_ip工作。 The other issue is that I cannot force_insert or force_update as I need both functionalities with this. 另一个问题是我无法force_insertforce_update因为我需要这两个功能。 My question is this: is there a way to selectively update/insert at the same time and completely exclude doing anything to the soap_ip each time saveSoapProd() runs? 我的问题是这样的:有没有一种方法可以同时有选择地更新/插入并在每次saveSoapProd()运行时完全排除对soap_ip做任何事情? Any and all help is greatly appreciated. 任何帮助都将不胜感激。 Thank you in advance. 先感谢您。

** EDIT 1 ** ** 编辑1 **

I may or may not have found a solution in update_or_create or get_or_create , however I am unsure on the exact usage. 我可能会或可能不会在update_or_createget_or_create中找到解决方案,但是我不确定确切的用法。 The docs have me slightly confused. 文档让我有些困惑。

** EDIT 2 ** ** 编辑2 **

I guess get_or_create is a bust. 我猜get_or_create是一个破产。 Works first pass through but every save after that fails with this: 可以先通过工程,但是此后的每次保存都会失败:

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

Here is the code: 这是代码:

@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'])

I will be honest, I am not entirely sure what is causing this error. 老实说,我不太确定是什么导致了此错误。


** EDIT 3/CURRENT SOLUTION ** ** 编辑3 /当前解决方案 **

I was able to resolve my own issue by modifying my model and my task function. 通过修改模型和任务功能,我能够解决自己的问题。 The solution uses get_or_create, but you could easily extrapolate how to use update_or_create from the solution provided. 该解决方案使用get_or_create,但是您可以轻松地从提供的解决方案中推断出如何使用update_or_create。 See the selected answer below for a coded example. 有关编码示例,请参见下面的选定答案。


** TLDR ** ** TLDR **

I want to do a .save() where it may need to do a insert for new records or update for changed records WITHOUT touching the soap_ip field (no insert_only or update_only ). 我想做一个.save(),其中可能需要插入新记录或更新已更改的记录,而无需触摸soap_ip字段(没有insert_onlyupdate_only )。

I don't know if you already knew this, but you can override the save() function of your model. 我不知道您是否已经知道这一点,但是您可以覆盖模型的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

EDIT 编辑

You are getting 你越来越

ValueError: The following fields do not exist in this model or are m2m fields: soap_id

Because you are trying to update soap_id , that field is defined as your model's primary key, so it is immutable when updating. 因为您正在尝试更新soap_id ,所以该字段被定义为模型的主键,因此在更新时它是不变的。 That's why it crashes when you do: 这就是为什么当您这样做时它会崩溃:

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

Try removing soap_id from update_fields . 尝试删除soap_idupdate_fields

Solved my own issue without modifying the save method by making the following changes to my model: 通过对模型进行以下更改来解决我自己的问题,而无需修改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)

and my task: 和我的任务:

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()

EDIT 编辑

Just noticed Josué Padilla's response, which was in fact part of my problem that I solved with this answer. 刚注意到JosuéPadilla的回答,这实际上是我通过此答案解决的问题的一部分。 Thank you to Josué for all of your help. 感谢Josué的所有帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM