Skip to content

"RelatedModel" has no attribute "RelatedObjectDoesNotExist" [attr-defined] #1390

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

Closed
eternal-sorrow opened this issue Mar 8, 2023 · 6 comments · Fixed by #1733
Closed

"RelatedModel" has no attribute "RelatedObjectDoesNotExist" [attr-defined] #1390

eternal-sorrow opened this issue Mar 8, 2023 · 6 comments · Fixed by #1733
Labels
bug Something isn't working stubs Issues in stubs files (.pyi)

Comments

@eternal-sorrow
Copy link

eternal-sorrow commented Mar 8, 2023

Bug report

What's wrong

Mypy prints Module "django.db.models" has no attribute "ObjectDoesNotExist" [attr-defined] on the from django.db.models import ObjectDoesNotExist line, which is obviously wrong.

Also, if I alternatively use MyModel.field.RelatedObjectDoesNotExist, I get the "RelatedModel" has no attribute "RelatedObjectDoesNotExist" [attr-defined] message.

field here is a reverse relation from RelatedModel to MyModel one-to-one field.

How is that should be

No error messages.

System information

  • OS:
  • python version: 3.10.6
  • django version: 3.2.18
  • mypy version: 1.0.1
  • django-stubs version: 1.15.0
  • django-stubs-ext version: 0.7.0
@eternal-sorrow eternal-sorrow added the bug Something isn't working label Mar 8, 2023
@intgr
Copy link
Collaborator

intgr commented Mar 8, 2023

Hi. This was caused by #1309, which removes re-exports that are not part of Django's intentional public API.

According to Django documentation https://docs.djangoproject.com/en/4.1/ref/exceptions/ the exception ObjectDoesNotExist should be imported from django.core.exceptions, not from django.db.models.

@eternal-sorrow
Copy link
Author

Alright, that's valid. The second prat of the bug report still applies.

@eternal-sorrow eternal-sorrow changed the title Module "django.db.models" has no attribute "ObjectDoesNotExist" [attr-defined] "RelatedModel" has no attribute "RelatedObjectDoesNotExist" [attr-defined] Mar 8, 2023
@intgr intgr added the stubs Issues in stubs files (.pyi) label Mar 8, 2023
@intgr
Copy link
Collaborator

intgr commented Mar 8, 2023

Ah sorry I missed the second part. You're right, that's a bug. Looks like it could be complicated.

@RyanWalker277
Copy link
Contributor

Hey! @eternal-sorrow can you share the code snippet in which you encountered the bug? On a quick lookup in related_descriptors.pyi

class ForwardManyToOneDescriptor:
field: ForeignKey
def __init__(self, field_with_rel: ForeignKey) -> None: ...
@property
def RelatedObjectDoesNotExist(self) -> type[ObjectDoesNotExist]: ...
def is_cached(self, instance: Model) -> bool: ...
def get_queryset(self, **hints: Any) -> QuerySet: ...
def get_prefetch_queryset(
self, instances: list[Model], queryset: QuerySet | None = ...
) -> tuple[QuerySet, Callable, Callable, bool, str, bool]: ...
def get_object(self, instance: Model) -> Model: ...
def __get__(
self, instance: Model | None, cls: type[Model] | None = ...
) -> Model | ForwardManyToOneDescriptor | None: ...
def __set__(self, instance: Model, value: Model | None) -> None: ...
def __reduce__(self) -> tuple[Callable, tuple[type[Model], str]]: ...

class ReverseOneToOneDescriptor:
related: OneToOneRel
def __init__(self, related: OneToOneRel) -> None: ...
@property
def RelatedObjectDoesNotExist(self) -> type[ObjectDoesNotExist]: ...
def is_cached(self, instance: Model) -> bool: ...
def get_queryset(self, **hints: Any) -> QuerySet: ...
def get_prefetch_queryset(
self, instances: list[Model], queryset: QuerySet | None = ...
) -> tuple[QuerySet, Callable, Callable, bool, str, bool]: ...
def __get__(self, instance: Model | None, cls: type[Model] | None = ...) -> Model | ReverseOneToOneDescriptor: ...
def __set__(self, instance: Model, value: Model | None) -> None: ...
def __reduce__(self) -> tuple[Callable, tuple[type[Model], str]]: ...

One thing that I think that might be causing the issue can be the fact that the RelatedObjectDoesNotExist attribute is defined as a property in the ForwardManyToOneDescriptor and ReverseOneToOneDescriptor classes, but it is not defined in the ManyToManyDescriptor class. This could result in the error when using MyModel.field.RelatedObjectDoesNotExist if field is a ManyToManyField. I may be wrong and something else might be causing the issue, just wanted to have a discussion on the potential causes before working on this one.

@eternal-sorrow
Copy link
Author

eternal-sorrow commented Mar 15, 2023

field here is a reverse relation for a one-to-one field. I looks something like this:

class A(models.Model):
    ...

class B(models.Model):
    a = models.OneToOneField(A, related_name='b')

a = A.objects.first()
try:
    b = a.b
except A.b.RelatedObjectDoesNotExist:  # mypy complains here '"B" has no attribute "RelatedObjectDoesNotExist"'
    pass

@flaeppe
Copy link
Member

flaeppe commented Nov 1, 2023

Closed via #1733

@flaeppe flaeppe closed this as completed Nov 1, 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 stubs Issues in stubs files (.pyi)
Development

Successfully merging a pull request may close this issue.

4 participants