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

Issues with overriding/re-implementing BaseModelAdmin.formfield_for_manytomany #761

Closed
blueyed opened this issue Nov 29, 2021 · 3 comments
Closed
Labels
bug Something isn't working

Comments

@blueyed
Copy link
Contributor

blueyed commented Nov 29, 2021

I am overriding BaseModelAdmin.formfield_for_manytomany (code) and noticed two issues:

  1. assert not db_field.remote_field.through._meta.auto_created fails with: "Field[Any, Any]" has no attribute "through" [attr-defined] (code ref)
  2. formfield is typed as Any, which can be fixed with an assert/type-override (
    # TODO: plugin support
    def formfield(self, **kwargs) -> Any: ...
    )
@admin.register(MyModel)
class MyModelAdmin(BaseAdminMixin):
    …

    def formfield_for_manytomany(
        self, db_field: "ManyToManyField", request: "Optional[HttpRequest]", **kwargs
    ) -> "ModelMultipleChoiceField":
        """Manually use filter_horizontal for input_recipes.

        This is required due to Django not using a non-auto through model.
        Ref: https://code.djangoproject.com/ticket/12203#comment:22
        """
        if db_field.name == "m2m_with_through":
            assert not db_field.remote_field.through._meta.auto_created

            db = kwargs.get("using")
            kwargs["widget"] = widgets.FilteredSelectMultiple(
                db_field.verbose_name,
                False,  # filter_horizontal
            )
            queryset = self.get_field_queryset(db, db_field, request)
            if queryset is not None:
                kwargs["queryset"] = queryset

            form_field = db_field.formfield(**kwargs)
            if TYPE_CHECKING:
                # assert type as it is not provided via django-stubs yet.
                assert isinstance(form_field, ModelMultipleChoiceField)
            msg = _(
                "Hold down “Control”, or “Command” on a Mac, to select more than one."
            )
            help_text = form_field.help_text
            form_field.help_text = (
                format_lazy("{} {}", help_text, msg) if help_text else msg
            )
            return form_field
        return super().formfield_for_manytomany(db_field, request, **kwargs)

System information

  • OS: Arch Linux
  • python version: 3.9.9
  • django version: 3.2.9
  • mypy version: 0.910
  • django-stubs version: 1.9.0 / master (593d04d)
  • django-stubs-ext version: -
@blueyed blueyed added the bug Something isn't working label Nov 29, 2021
@quevon24
Copy link

The problem still exists, if you try to declare a proxy model using the through model, it throws the warning: Name "Audio.panel.through" is not defined

e.g.

class AudioPanel(Audio.panel.through):
    class Meta:
        proxy = True

@tony
Copy link
Contributor

tony commented Jul 5, 2023

Happens for me as of:

  • python: 3.10.x
  • django: 3.2.x
  • mypy: 1.4.x
  • django-stubs: 1.13.x

@flaeppe
Copy link
Member

flaeppe commented Dec 9, 2023

I'm going to close this issue as the attribute error for through should be fixed via #1805 while the formfield hints were improved in #1724 and #1739.

Feel free to open a new issue if you find anything else missing or needing improvements.

@flaeppe flaeppe closed this as completed Dec 9, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Development

No branches or pull requests

4 participants