#python #django
#python #django
Вопрос:
Я устанавливаю две модели: расписание и расписание. TimesheetEntry будет встроенным и устанавливается в admin.py файл, и оттуда вы можете указать текущие часы для каждого проекта. Мой вопрос в том, как создать функцию и вычислить total_hours, чтобы я мог визуализировать ее в своей пользовательской таблице в шаблоне Django?
class TimesheetEntry(TimeStampedModel):
hours = models.DecimalField(max_digits=4, decimal_places=2, default=0, verbose_name=_("Hours"))
timesheet = models.ForeignKey('timesheet.TimeSheet', verbose_name=_("Timesheet"),
related_name='timesheet_entries', on_delete=models.CASCADE)
project = models.ForeignKey('project.Project', verbose_name=_("Project"),
related_name='timesheet_entries', on_delete=models.PROTECT, null=True)
project_role = models.ForeignKey('project.ProjectRole', verbose_name=_("Project role"),
related_name='timesheet_entries', on_delete=models.PROTECT, null=True)
def __str__(self):
return f"{self.timesheet} - {self.project} - {self.project_role}"
def save(self, **kwargs):
self.timesheet.save()
super().save(**kwargs)
class Meta:
verbose_name = _("Timesheet entry")
verbose_name_plural = _("Timesheet entries")
class Timesheet(TimeStampedModel):
date = models.DateField(verbose_name=_("Date"), default=datetime.date.today, editable=True)
total_hours = models.DecimalField(max_digits=4, decimal_places=2, verbose_name=_("Total hours"), editable=False)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='timesheet')
def __str__(self):
return f"{self.user} - {date_format(self.date, 'DATE_FORMAT')}"
def recalculate(self):
self.total_hours = self.timesheet_entries.all().aggregate(total_hours=Sum('hours'))['total_hours'] or 0
def save(self, **kwargs):
self.recalculate()
super().save(**kwargs)
def projects(self):
from hr.project.models import Project
return Project.objects.filter(
pk__in=self.timesheet_entries.all().values_list('project_id', flat=True).distinct()
)
class Meta:
verbose_name = _("Timesheet")
verbose_name_plural = _("Timesheets")
```
Комментарии:
1.вы пытались добавить свойство в свою модель?
@property
docs.djangoproject.com/en/2.2/topics/db/models/#model-methods2. Я никогда не использовал это, потому что я немного новичок.
3. Добро пожаловать в Stack Overflow… где вы сможете попробовать что-то новое… определенно рекомендую прочитать соответствующие документы.
Ответ №1:
Агрегирование — это не то, что вы хотите использовать здесь, поскольку вы суммируете его в экземпляре. итак, это должно сделать это:
self.total_hours = sum(self.timesheet_entries.all().values_list("hours",flat=True)
Затем вы либо делаете это свойством (как указано Icognos), либо переопределяете функцию сохранения и вызываете пересчет в функции сохранения.
Ответ №2:
Ответ прост и сложен одновременно. Вы можете использовать @cached_property
декоратор для метода модели (например recalculate
, — который вы могли бы переименовать total_hours
и удалить из своего save
метода), а затем кэшировать результат cached_property
— только для того, чтобы аннулировать его каждый раз, когда появляется новая или отредактированная запись времени — путем удаления cached_property
. Кэшированное свойство
class Timesheet(TimeStampedModel):
date = models.DateField(verbose_name=_("Date"), default=datetime.date.today, editable=True)
total_hours = models.DecimalField(max_digits=4, decimal_places=2, verbose_name=_("Total hours"), editable=False)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='timesheet')
def __str__(self):
return f"{self.user} - {date_format(self.date, 'DATE_FORMAT')}"
@cached_property
def total_hours(self):
return self.timesheet_entries.all().aggregate(total_hours=Sum('hours'))['total_hours'] or 0
def save(self, **kwargs):
super().save(**kwargs)
Ответ №3:
Ну, это def recalculate
в модели расписания работает, когда производится редактирование. Реальная проблема заключалась в том, что мне нужно выполнить обратный вызов в сериализаторе расписания, и там я должен вызвать функцию timesheet.recalculate
и save
ее. В обоих случаях это работает из ответов службы поддержки. Спасибо!
class TimesheetSerializer(ModelSerializer):
timesheet_entries = TimesheetEntrySerializer(many=True)
class Meta:
model = Timesheet
fields = ['date', 'user', 'total_hours', 'timesheet_entries']
def to_representation(self, instance):
result = super().to_representation(instance)
result['user'] = UserDetailsSerializer(instance=instance.user).data
return result
def create(self, validated_data):
entries = validated_data.pop('timesheet_entries')
timesheet = Timesheet.objects.create(**validated_data)
for entry in entries:
TimesheetEntry.objects.create(timesheet=timesheet, **entry)
timesheet.recalculate()
timesheet.save()
return timesheet
```