这个想法
为了使代码更易于理解,我将首先解释我的代码(问题可能来自于此)应该做什么:我将报告保存在我的模型中。我给这些报告自己的 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
我认为错误是因为我错误地实现了ComputedTextField
s 。该文档说明了以下内容:
笔记
请务必注意,您的计算域数据不会立即写入数据库。您必须(重新)保存数据的所有实例,才能在数据库中填充计算字段。在您这样做之前,您将能够在加载模型实例时访问这些字段,但您不会从它们的可查询性中受益。
您可以做到这一点的一种方法是在数据迁移中,使用类似的东西:
例如在 MyModel.objects.all().iterator(): instance.save()
我根据文档进行设置的尝试是首先创建一个空迁移,然后在实例中通过
migrations.RunPython(save_func),
保存它。由于这只会导致错误,因此我尝试将其包含在模型的 save() 函数中。然而,这显然是错误的。有谁知道如何正确保存实例?