微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Django:错误实现 ComputedTextField无法在没有主键的情况下强制更新 save()

如何解决Django:错误实现 ComputedTextField无法在没有主键的情况下强制更新 save()

想法

为了使代码更易于理解,我将首先解释我的代码(问题可能来自哪里)首先应该做什么:我将报告保存在我的模型中。我为这些报告指定了自己的 ID 或编号,因为这是绝对必要的。此 ID 的结构如下:

<year><ascending number with leading zeros>

示例:2021001、2021002、...、2022001

代码

我为此开发了以下模型。由于要自动计算该值,因此我使用了 @property 装饰器。为了以后能够更轻松地将 ID(名称:einsatznummer)用作字段并且仅用于我的 REST Api,我使用了 computed_property 包。

class EinsatzPublic(models.Model):

    STATUS = (
        (0,"Entwurf"),(1,"Öffentlich"),(2,"Archiv"),(3,"Papierkorb"),)

    author = models.ForeignKey(User,on_delete=models.SET_NULL,null=True,verbose_name="Autor")
    created = models.DateTimeField(default=timezone.Now,editable=False,verbose_name="Erstellt")
    updated = models.DateTimeField(auto_Now= True,verbose_name="Aktualisiert")
    status = models.IntegerField(choices=STATUS,default=0,verbose_name="Status")

    #(some more fields...)

    einsatznummer = ComputedTextField(blank=True,compute_from="einsatznummer_calc")
    alarmzeit = ComputedTextField(blank=True,compute_from="alarmzeit_calc")
    alarmdatum = ComputedTextField(blank=True,compute_from="alarmdatum_calc")


    @property
    def alarmdatum_calc(self):
        date =  self.einsatz_start.date()
        return date.strftime("%d.%m.%y")

    @property
    def alarmzeit_calc(self):
        date =  self.einsatz_start.date()
        return date.strftime("%H:%M")

    @property
    def einsatznummer_calc(self):
        year_einsatz = self.einsatz_start.strftime('%Y')
        last_number = EinsatzPublic.objects.filter(einsatznummer__isnull=False,einsatz_start__year=year_einsatz).values_list('einsatznummer',flat=True)
        
        if last_number:
            if  last_number[:-1] != year_einsatz:
                last_number = '0'
                einsatznummer_gen = year_einsatz + str(int(last_number)+ 1)
                return einsatznummer_gen

            elif last_number[:-1] == year_einsatz:
                einsatznummer_gen = year_einsatz + str(int(last_number)+ 1)
                return einsatznummer_gen

        else:
            einsatznummer_gen = str(year_einsatz + '1')
            return einsatznummer_gen

    
    class Meta:
        ordering = ['-created']
        verbose_name = "Einsatz"
        verbose_name_plural = "Einsätze"

    def save(self,*args,**kwargs):
        for instance in EinsatzPublic.objects.all().iterator():
            instance.save()
        super().save(*args,**kwargs)

    def __str__(self):
        return self.meldebild

当我尝试添加新记录时,出现以下错误

Internal Server Error: /super/einsatzverwaltung/einsatzpublic/add/
Traceback (most recent call last):
  File "C:\Users\marce\.virtualenvs\backend-ZTyOc35O\lib\site-packages\django\core\handlers\exception.py",line 47,in inner
    response = get_response(request)
  File "C:\Users\marce\.virtualenvs\backend-ZTyOc35O\lib\site-packages\django\core\handlers\base.py",line 181,in _get_response        
    response = wrapped_callback(request,*callback_args,**callback_kwargs)
  File "C:\Users\marce\.virtualenvs\backend-ZTyOc35O\lib\site-packages\django\contrib\admin\options.py",line 616,in wrapper
    return self.admin_site.admin_view(view)(*args,**kwargs)        
  File "C:\Users\marce\.virtualenvs\backend-ZTyOc35O\lib\site-packages\django\utils\decorators.py",line 130,in _wrapped_view
    response = view_func(request,**kwargs)
  File "C:\Users\marce\.virtualenvs\backend-ZTyOc35O\lib\site-packages\django\views\decorators\cache.py",line 44,in _wrapped_view_func    response = view_func(request,**kwargs)
  File "C:\Users\marce\.virtualenvs\backend-ZTyOc35O\lib\site-packages\django\contrib\admin\sites.py",line 232,in inner
    return view(request,**kwargs)
  File "C:\Users\marce\.virtualenvs\backend-ZTyOc35O\lib\site-packages\django\contrib\admin\options.py",line 1657,in add_view
    return self.changeform_view(request,None,form_url,extra_context)
  File "C:\Users\marce\.virtualenvs\backend-ZTyOc35O\lib\site-packages\django\utils\decorators.py",line 43,in _wrapper
    return bound_method(*args,**kwargs)
  File "C:\Users\marce\.virtualenvs\backend-ZTyOc35O\lib\site-packages\django\utils\decorators.py",line 1540,in changeform_view  
    return self._changeform_view(request,object_id,extra_context)
  File "C:\Users\marce\.virtualenvs\backend-ZTyOc35O\lib\site-packages\django\contrib\admin\options.py",line 1586,in _changeform_view 
    self.save_model(request,new_object,form,not add)
  File "C:\Users\marce\.virtualenvs\backend-ZTyOc35O\lib\site-packages\django\contrib\admin\options.py",line 1099,in save_model       
    obj.save()
  File "D:\04-Dev\Projekt\feuerwehr-ensdorf-webapp-cms\backend\einsatzverwaltung\models.py",line 164,in save
    super().save(*args,**kwargs)
  File "C:\Users\marce\.virtualenvs\backend-ZTyOc35O\lib\site-packages\django\db\models\base.py",line 726,in save
    self.save_base(using=using,force_insert=force_insert,File "C:\Users\marce\.virtualenvs\backend-ZTyOc35O\lib\site-packages\django\db\models\base.py",line 763,in save_base
    updated = self._save_table(
  File "C:\Users\marce\.virtualenvs\backend-ZTyOc35O\lib\site-packages\django\db\models\base.py",line 828,in _save_table
    raise ValueError("Cannot force an update in save() with no primary key.")
ValueError: Cannot force an update in save() with no primary key.   
[11/Jun/2021 10:40:10] "POST /super/einsatzverwaltung/einsatzpublic/add/ HTTP/1.1" 500 137809

我认为错误是因为我错误地实现了 ComputedTextField。文档说明如下:

注意

需要注意的是,您的计算域数据不会 立即写入数据库。您必须(重新)保存所有 将计算字段填充在数据的实例中 数据库。在您这样做之前,您将能够访问这些字段 当您加载模型的实例时,但您不会从中受益 他们的可查询性。

你可以这样做的一种方法是在数据迁移中,使用一些东西 喜欢:

例如在 MyModel.objects.all().iterator() 中: 实例.save()

我根据文档进行设置的尝试是首先创建一个空迁移,然后在实例中通过 migrations.RunPython(save_func), 保存它。由于这只会导致错误,我尝试将其包含在模型的 save() 函数中。然而,这显然是错误的。有谁知道如何正确保存实例?

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。