django-types icon indicating copy to clipboard operation
django-types copied to clipboard

Inverse of OneToOneField

Open lpil opened this issue 4 years ago • 5 comments

Hello!

What should be used as the inverse of an OneToOneField?

I've been attempting something like the ForeignKey example but I've not been able to determine what exactly so far. https://github.com/sbdchd/django-types#foreignkey-ids-and-related-names-as-properties-in-orm-models

Thanks, Louis

lpil avatar Oct 28 '21 11:10 lpil

Yeah don't really have any docs on those, but I think it would be similar to the ForeignKey where we have to do some if TYPE_CHECKING stuff

Using the django docs https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.OneToOneField,

from django.conf import settings
from django.db import models

class MySpecialUser(models.Model):
    user = models.OneToOneField(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
    )
    supervisor = models.OneToOneField(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name='supervisor_of',
    )

And docs say:

>>> user = User.objects.get(pk=1)
>>> hasattr(user, 'myspecialuser')
True
>>> hasattr(user, 'supervisor_of')
True

So we'd need to update User to have the properties, something like:

class User(models.Model):
    # some fields
    if TYPE_CHECKING:
        myspecialuser: MySpecialUser
        user: MySpecialUser

I think the if TYPE_CHECKING might not be necessary, so maybe:

class User(models.Model):
    # some fields
    myspecialuser: MySpecialUser
    user: MySpecialUser

sbdchd avatar Oct 29 '21 00:10 sbdchd

Oh thank you! I thought that the model class would need to be wrapped in some other object. Clearly I've been overthinking this.

I'll try this out and if I can't find any problems perhaps I could add this to the README?

lpil avatar Oct 29 '21 09:10 lpil

The problem with reverse OneToOneField, is it does not exists and will raise RelatedObjectDoesNotExist when there is not corresponding model.

> user = User.objects.get(pk=1)
> hasattr(user, 'myspecialuser')
False
> MySpecialUser.objects.create(user=user)
> hasattr(user, 'myspecialuser')
True

Any ideas how to type this?

last-partizan avatar Jan 13 '22 07:01 last-partizan

Yikes, that's pretty dynamic. I'm not sure there is a good way. I think the best we can do is pretend the attr is always there.

sbdchd avatar Jan 13 '22 23:01 sbdchd

This could lead to some unexpected errors.

But that's not something type checking should solve. I think it's better to define something like get_mysecialuser which would handle those exceptions.

last-partizan avatar Jan 14 '22 10:01 last-partizan