Repository: adfinis/timed-backend

Issue:
Replace uses of str.format with fstrings
Currently we still have `str.format`, this can be replaced with the more readable f-strings
 
## `str.format`
```py
class Attendance(models.Model):
    """Attendance model.

    An attendance is a timespan in which a user was present at work.
    Timespan should not be time zone aware hence splitting into date and
    from resp. to time fields.
    """

    date = models.DateField()
    from_time = models.TimeField()
    to_time = models.TimeField()
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="attendances"
    )

    def __str__(self) -> str:
        """Represent the model as a string."""
        return "{}: {} {} - {}".format(
            self.user,
            self.date.strftime("%Y-%m-%d"),
            self.from_time.strftime("%H:%M"),
            self.to_time.strftime("%H:%M"),
        )
```

## f-string
```py
class Attendance(models.Model):
    """Attendance model.

    An attendance is a timespan in which a user was present at work.
    Timespan should not be time zone aware hence splitting into date and
    from resp. to time fields.
    """

    date = models.DateField()
    from_time = models.TimeField()
    to_time = models.TimeField()
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="attendances"
    )

    def __str__(self) -> str:
        """Represent the model as a string."""
        return f"{self.user}: {self.date.strftime('%Y-%m-%d')} {self.from_time.strftime('%H:%M')} - {self.to_time.strftime('%H:%M')}"
```

## f-string and without strftime

```py
class Attendance(models.Model):
    """Attendance model.

    An attendance is a timespan in which a user was present at work.
    Timespan should not be time zone aware hence splitting into date and
    from resp. to time fields.
    """

    date = models.DateField()
    from_time = models.TimeField()
    to_time = models.TimeField()
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="attendances"
    )

    def __str__(self) -> str:
        """Represent the model as a string."""
        return f"{self.user}: {self.date:%Y-%m-%d} {self.from_time:%H:%M} - {self.to_time:%H:%M}"
```


Discussion:
related to this ruff is also catching more `"%s" % var` here: https://github.com/adfinis/timed-backend/pull/1072

Resolving patch:
diff --git a/timed/employment/models.py b/timed/employment/models.py
--- a/timed/employment/models.py
+++ b/timed/employment/models.py
@@ -62,7 +62,7 @@ class Meta:
 
     def __str__(self) -> str:
         """Represent the model as a string."""
-        return "{} {}".format(self.name, self.date.strftime("%Y"))
+        return f"{self.name} {self.date:%Y}"
 
 
 class AbsenceType(models.Model):
@@ -228,11 +228,7 @@ class Meta:
 
     def __str__(self) -> str:
         """Represent the model as a string."""
-        return "{} ({} - {})".format(
-            self.user.username,
-            self.start_date.strftime("%d.%m.%Y"),
-            self.end_date.strftime("%d.%m.%Y") if self.end_date else "today",
-        )
+        return f"{self.user.username} ({self.start_date:%d.%m.%Y} - {(self.end_date or date.today()):%d.%m.%Y})"
 
     def calculate_worktime(
         self, start: date, end: date
diff --git a/timed/reports/views.py b/timed/reports/views.py
--- a/timed/reports/views.py
+++ b/timed/reports/views.py
@@ -299,12 +299,7 @@ def _generate_workreport_name(self, from_date: date, project: Project) -> str:
         whereas YYMM is year and month of from_date and YYYYMMDD
         is date when work reports gets created.
         """
-        return "{}-{}-{}-{}.ods".format(
-            from_date.strftime("%y%m"),
-            date.today().strftime("%Y%m%d"),
-            self._clean_filename(project.customer.name),
-            self._clean_filename(project.name),
-        )
+        return f"{from_date:%y%m}-{date.today():%Y%m%d}-{self._clean_filename(project.customer.name)}-{self._clean_filename(project.name)}.ods"
 
     def _create_workreport(  # noqa: PLR0913
         self,
diff --git a/timed/tracking/models.py b/timed/tracking/models.py
--- a/timed/tracking/models.py
+++ b/timed/tracking/models.py
@@ -65,12 +65,7 @@ class Attendance(models.Model):
 
     def __str__(self) -> str:
         """Represent the model as a string."""
-        return "{}: {} {} - {}".format(
-            self.user,
-            self.date.strftime("%Y-%m-%d"),
-            self.from_time.strftime("%H:%M"),
-            self.to_time.strftime("%H:%M"),
-        )
+        return f"{self.user}: {self.date:%Y-%m-%d} {self.from_time:%H:%M} - {self.to_time:%H:%M}"
 
 
 class Report(models.Model):
@@ -149,11 +144,7 @@ class Meta:
 
     def __str__(self) -> str:
         """Represent the model as a string."""
-        return "{}: {} {}".format(
-            self.user,
-            self.date.strftime("%Y-%m-%d"),
-            self.comment,
-        )
+        return f"{self.user}: {self.date:%Y-%m-%d} {self.comment}"
 
     def calculate_duration(self, employment: Employment) -> timedelta:
         """Calculate duration of absence with given employment.


Test patch:
diff --git a/timed/employment/tests/test_worktime_balance.py b/timed/employment/tests/test_worktime_balance.py
--- a/timed/employment/tests/test_worktime_balance.py
+++ b/timed/employment/tests/test_worktime_balance.py
@@ -86,7 +86,7 @@ def test_worktime_balance_with_employments(auth_client, django_assert_num_querie
 
     url = reverse(
         "worktime-balance-detail",
-        args=["{}_{}".format(auth_client.user.id, end_date.strftime("%Y-%m-%d"))],
+        args=[f"{auth_client.user.id}_{end_date:%Y-%m-%d}"],
     )
 
     with django_assert_num_queries(11):