Skip to content

Commit

Permalink
fix: handle generated-values when calculating _initial model version
Browse files Browse the repository at this point in the history
  • Loading branch information
joaodaher committed Jul 8, 2024
1 parent b7a332c commit c457833
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 5 deletions.
16 changes: 14 additions & 2 deletions drf_kit/models/diff_models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import contextlib
import logging

from django.db.models import GeneratedField

from drf_kit.serializers import as_dict

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -40,8 +42,18 @@ def _dict(self):

# If there's any deferred field (i.e. lazy loading),
# refresh the whole object at once, instead of letting `value_from_object` refresh one by one
# TODO: Lazily compute the diff only for the deferred fields
if self.get_deferred_fields():
# TODO: Lazily compute the diff only for the deferred fields, otherwise .only() will be useless
lazy_fields = []
deferred_fields = self.get_deferred_fields()
for field in self._meta.get_fields():
if isinstance(field, GeneratedField):
continue
if field.name in deferred_fields:
lazy_fields.append(field)

if lazy_fields:
# refresh_from_db() will populate the deferred fields, this is causing max-recursing error,
# so we refresh all of them at once
self.refresh_from_db(fields=[field.attname for field in self._meta.concrete_fields])

for field in self._meta.fields:
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "drf-kit"
version = "1.42.2"
version = "1.42.3"
description = "DRF Toolkit"
authors = ["Nilo Saude <[email protected]>"]
packages = [
Expand Down
19 changes: 19 additions & 0 deletions test_app/migrations/0013_wizard_minimum_age.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 5.0.6 on 2024-07-08 20:29

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("test_app", "0012_beast_is_active"),
]

operations = [
migrations.AddField(
model_name="wizard",
name="minimum_age",
field=models.GeneratedField(
db_persist=True, expression=models.Value(11), output_field=models.IntegerField()
),
),
]
6 changes: 6 additions & 0 deletions test_app/models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.contrib.postgres.constraints import ExclusionConstraint
from django.contrib.postgres.fields import DateTimeRangeField, RangeOperators
from django.db import models
from django.db.models import Value

from drf_kit.fields import SlugifyField
from drf_kit.models import (
Expand All @@ -24,6 +25,11 @@ class Wizard(BaseModel):
null=True,
blank=True,
)
minimum_age = models.GeneratedField(
expression=Value(11),
output_field=models.IntegerField(),
db_persist=True,
)
is_half_blood = models.BooleanField(default=True)
picture = models.FileField(
**StoragePath.media_thumb(),
Expand Down
6 changes: 4 additions & 2 deletions test_app/tests/tests_models/tests_diff_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ def test_updated_special_fields(self):
self.assertEqual(new_url.removeprefix("/"), wizard._diff["picture"][1])

def test_no_deferred_fields(self):
WizardFactory(name="Harry Potter", age=12)
with self.assertNumQueries(2):
WizardFactory(name="Harry Potter", age=12)

with self.assertNumQueries(1):
# 1 SELECT with only
Expand All @@ -92,7 +93,8 @@ def test_no_deferred_fields(self):
self.assertFalse(wizard._has_changed)

def test_deferred_fields(self):
WizardFactory(name="Harry Potter", age=12)
with self.assertNumQueries(2):
WizardFactory(name="Harry Potter", age=12)

with self.assertNumQueries(2):
# 1 SELECT with only
Expand Down

0 comments on commit c457833

Please sign in to comment.