Skip to content

Commit

Permalink
chore: Update deps (#769)
Browse files Browse the repository at this point in the history
* chore: Update deps
* refactor: Use version-specific refresh_from_db patch
* chore: Fix admin types
* fix: Fix django version checks
  • Loading branch information
last-partizan authored Dec 1, 2024
1 parent 294302c commit 1b0bf21
Show file tree
Hide file tree
Showing 4 changed files with 282 additions and 218 deletions.
46 changes: 44 additions & 2 deletions modeltranslation/_compat.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
from __future__ import annotations

from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Any, Callable

import django
from typing import Iterable
from typing import Optional

if TYPE_CHECKING:
from django.db.models import QuerySet
from django.db.models.fields.reverse_related import ForeignObjectRel

_django_version = django.VERSION[:2]


def is_hidden(field: ForeignObjectRel) -> bool:
return field.hidden
Expand All @@ -25,7 +30,44 @@ def clear_ForeignObjectRel_caches(field: ForeignObjectRel):
field.__dict__.pop(name, None)


if django.VERSION <= (5, 1):
def build_refresh_from_db(
old_refresh_from_db: Callable[
[Any, Optional[str], Optional[Iterable[str]], QuerySet[Any] | None], None
],
):
from modeltranslation.manager import append_translated

def refresh_from_db(
self: Any,
using: str | None = None,
fields: Iterable[str] | None = None,
from_queryset: QuerySet[Any] | None = None,
) -> None:
if fields is not None:
fields = append_translated(self.__class__, fields)
return old_refresh_from_db(self, using, fields, from_queryset)

return refresh_from_db


if _django_version <= (5, 0):

def is_hidden(field: ForeignObjectRel) -> bool:
return field.is_hidden()

# Django versions below 5.1 do not have `from_queryset` argument.
def build_refresh_from_db( # type: ignore[misc]
old_refresh_from_db: Callable[[Any, Optional[str], Optional[Iterable[str]]], None],
):
from modeltranslation.manager import append_translated

def refresh_from_db(
self: Any,
using: str | None = None,
fields: Iterable[str] | None = None,
) -> None:
if fields is not None:
fields = append_translated(self.__class__, fields)
return old_refresh_from_db(self, using, fields)

return refresh_from_db
41 changes: 21 additions & 20 deletions modeltranslation/admin.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations

from copy import deepcopy
from typing import Any, TypeVar
from typing import Any, TypeVar, TYPE_CHECKING
from collections.abc import Iterable, Sequence

from django import forms
Expand All @@ -26,6 +26,11 @@
from modeltranslation.widgets import ClearableWidgetWrapper
from modeltranslation._typing import _ListOrTuple

if TYPE_CHECKING:
# We depend here or `django-stubs` internal `_FieldsetSpec`,
# in case it changes, change import or define this internally.
from django.contrib.admin.options import _FieldsetSpec

_ModelT = TypeVar("_ModelT", bound=Model)


Expand All @@ -40,7 +45,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None:

def _get_declared_fieldsets(
self, request: HttpRequest, obj: _ModelT | None = None
) -> _ListOrTuple[tuple[str | None, dict[str, Any]]] | None:
) -> _FieldsetSpec | None:
# Take custom modelform fields option into account
if not self.fields and hasattr(self.form, "_meta") and self.form._meta.fields:
self.fields = self.form._meta.fields # type: ignore[assignment]
Expand All @@ -56,11 +61,18 @@ def _get_declared_fieldsets(
return [(None, {"fields": self.replace_orig_field(self.get_fields(request, obj))})]
return None

def _patch_fieldsets(self, fieldsets: _FieldsetSpec) -> _FieldsetSpec:
fieldsets_new = list(fieldsets)
for name, dct in fieldsets:
if "fields" in dct:
dct["fields"] = self.replace_orig_field(dct["fields"])
return fieldsets_new

def formfield_for_dbfield(
self, db_field: Field, request: HttpRequest, **kwargs: Any
) -> forms.Field:
field = super().formfield_for_dbfield(db_field, request, **kwargs)
self.patch_translation_field(db_field, field, request, **kwargs)
) -> forms.Field | None:
if field := super().formfield_for_dbfield(db_field, request, **kwargs):
self.patch_translation_field(db_field, field, request, **kwargs)
return field

def patch_translation_field(
Expand All @@ -80,6 +92,8 @@ def patch_translation_field(
pass
else:
orig_formfield = self.formfield_for_dbfield(orig_field, request, **kwargs)
if orig_formfield is None:
return
field.widget = deepcopy(orig_formfield.widget)
attrs = field.widget.attrs
# if any widget attrs are defined on the form they should be copied
Expand Down Expand Up @@ -185,17 +199,6 @@ def replace_orig_field(self, option: Iterable[str | Sequence[str]]) -> _ListOrTu
option = option_new
return option # type: ignore[return-value]

def _patch_fieldsets(
self, fieldsets: _ListOrTuple[tuple[str | None, dict[str, Any]]]
) -> _ListOrTuple[tuple[str | None, dict[str, Any]]]:
if fieldsets:
fieldsets_new = list(fieldsets)
for name, dct in fieldsets:
if "fields" in dct:
dct["fields"] = self.replace_orig_field(dct["fields"])
fieldsets = fieldsets_new
return fieldsets

def _patch_prepopulated_fields(self) -> None:
def localize(sources: Sequence[str], lang: str) -> tuple[str, ...]:
"Append lang suffix (if applicable) to field list"
Expand Down Expand Up @@ -244,7 +247,7 @@ def _get_form_or_formset(

def _get_fieldsets_pre_form_or_formset(
self, request: HttpRequest, obj: _ModelT | None = None
) -> _ListOrTuple[tuple[str | None, dict[str, Any]]] | None:
) -> _FieldsetSpec | None:
"""
Generic get_fieldsets code, shared by
TranslationAdmin and TranslationInlineModelAdmin.
Expand Down Expand Up @@ -382,9 +385,7 @@ def get_form(
kwargs = self._get_form_or_formset(request, obj, **kwargs)
return super().get_form(request, obj, **kwargs)

def get_fieldsets(
self, request: HttpRequest, obj: _ModelT | None = None
) -> _ListOrTuple[tuple[str | None, dict[str, Any]]]:
def get_fieldsets(self, request: HttpRequest, obj: _ModelT | None = None) -> _FieldsetSpec:
return self._get_fieldsets_pre_form_or_formset(request, obj) or self._group_fieldsets(
self._get_fieldsets_post_form_or_formset(
request, self.get_form(request, obj, fields=None), obj
Expand Down
13 changes: 2 additions & 11 deletions modeltranslation/translator.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
from modeltranslation.manager import (
MultilingualManager,
MultilingualQuerysetManager,
append_translated,
rewrite_lookup_key,
)
from modeltranslation.thread_context import auto_populate_mode
Expand All @@ -43,7 +42,7 @@
# Re-export the decorator for convenience
from modeltranslation.decorators import register

from ._compat import is_hidden
from ._compat import is_hidden, build_refresh_from_db
from ._typing import _ListOrTuple

__all__ = [
Expand Down Expand Up @@ -374,16 +373,8 @@ def patch_refresh_from_db(model: type[Model]) -> None:
"""
if not hasattr(model, "refresh_from_db"):
return
old_refresh_from_db = model.refresh_from_db

def new_refresh_from_db(
self, using: str | None = None, fields: Iterable[str] | None = None
) -> None:
if fields is not None:
fields = append_translated(self.__class__, fields)
return old_refresh_from_db(self, using, fields)

model.refresh_from_db = new_refresh_from_db
model.refresh_from_db = build_refresh_from_db(model.refresh_from_db)


def delete_cache_fields(model: type[Model]) -> None:
Expand Down
Loading

0 comments on commit 1b0bf21

Please sign in to comment.