0

这个想法

为了使代码更易于理解,我将首先解释我的代码(问题可能来自于此)应该做什么:我将报告保存在我的模型中。我给这些报告自己的 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, editable=False, 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, *args, **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, *args, **kwargs)
  File "C:\Users\marce\.virtualenvs\backend-ZTyOc35O\lib\site-packages\django\contrib\admin\sites.py", line 232, in inner
    return view(request, *args, **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 130, in _wrapped_view
    response = view_func(request, *args, **kwargs)
  File "C:\Users\marce\.virtualenvs\backend-ZTyOc35O\lib\site-packages\django\contrib\admin\options.py", line 1540, in changeform_view  
    return self._changeform_view(request, object_id, form_url, 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

我认为错误是因为我错误地实现了ComputedTextFields 。该文档说明了以下内容:

笔记

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

您可以做到这一点的一种方法是在数据迁移中,使用类似的东西:

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

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

4

0 回答 0