Добрый день. Необходимо сделать вычисляемое поле в модели Django. Пытаюсь переопределить метод save для этого.
from django.db import models
import tlsh
from django.contrib import admin
# Create your models here.
class Font(models.Model):
name = models.CharField(max_length=500, unique=True)
def __str__(self):
return self.name
class Meta:
ordering = ["name"]
class Language(models.Model):
name = models.CharField(max_length=50, unique=True)
def __str__(self):
return self.name
class Meta:
ordering = ["name"]
class FingerPrint(models.Model):
def result_string(self):
return self.user_agent + str(self.time_zone) + str(self.screen_h) + str(self.screen_w) + \
str(self.hardware_concurrency) + ''.join(lng.name for lng in self.browser_languages.all()) + \
self.canvas_fingerprint + '1'.join(font.name for font in self.installed_fonts.all()) + \
'0'.join(font.name for font in self.not_installed_fonts.all())
def calculate_tlsh(self):
return tlsh.forcehash(self.result_string().encode())
user_agent = models.CharField(max_length=1000,blank=True)
time_zone = models.IntegerField(blank=True)
screen_w = models.IntegerField(blank=True)
screen_h = models.IntegerField(blank=True)
hardware_concurrency = models.IntegerField(blank=True)
browser_languages = models.ManyToManyField('Language', related_name='browser_languages')
canvas_fingerprint = models.CharField(max_length=256, blank=True)
installed_fonts = models.ManyToManyField(Font, related_name='installed_fonts')
not_installed_fonts = models.ManyToManyField('Font', related_name='not_installed_fonts')
tlsh = models.CharField(max_length=400, blank=True)
def save(self, *args, **kwargs):
#super(FingerPrint, self).save(*args, **kwargs) костыль который чинит ошибку
self.tlsh = self.calculate_tlsh()
print(':', self.tlsh)
super(FingerPrint, self).save(*args, **kwargs)
Получаю ошибку
File "/home/maxim/PycharmProjects/fingerprint/core/fingerprinter/models.py", line 52, in save
self.tlsh = self.calculate_tlsh()
File "/home/maxim/PycharmProjects/fingerprint/core/fingerprinter/models.py", line 37, in calculate_tlsh
return tlsh.forcehash(self.result_string().encode())
File "/home/maxim/PycharmProjects/fingerprint/core/fingerprinter/models.py", line 33, in result_string
self.canvas_fingerprint + '1'.join(font.name for font in self.installed_fonts.all()) + \
File "/home/maxim/PycharmProjects/fingerprint/venv/lib/python3.6/site-packages/django/db/models/fields/related_descriptors.py", line 535, in __get__
return self.related_manager_cls(instance)
File "/home/maxim/PycharmProjects/fingerprint/venv/lib/python3.6/site-packages/django/db/models/fields/related_descriptors.py", line 848, in __init__
(instance, self.pk_field_names[self.source_field_name]))
ValueError: "<FingerPrint: FingerPrint object (None)>" needs to have a value for field "id" before this many-to-many relationship can be used.
я так понял что это происходит из за того что сначало нужно сохранить объект а потом только обращаться к ManyToManyFields. и если в методе save сначало сохранить, потом вычислить поле, потом опять сохранить то все работает. Как грамотно сделать данную задачу?