Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update deps #769

Merged
merged 4 commits into from
Dec 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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