OneToOne relation to User model (django.contrib.auth) without cascading deletion

I'm a little confused about how OneToOneField works when deletion comes into play. The only quasi-authoritative information I can find is this thread on django-developers :

I do not know if you found this, but the removal works in one direction, but not in the direction in which you expect it. For an instance using the models you sent in another message:

class Place(models.Model): name = models.CharField(max_length = 100) class Restaurant(models.Model): place = models.OneToOneField(Place, primary_key=True) 

If you create a place and a restaurant that is associated with it, deleting the Restaurant will not delete the place (this is the problem you encountered here), but deleting Place will delete the restaurant.

I have the following model:

 class Person(models.Model): name = models.CharField(max_length=50) # ... etc ... user = models.OneToOneField(User, related_name="person", null=True, blank=True) 

It is configured so that I can easily access person from the User instance using user.person .

However, when I try to delete the User entry in admin, naturally, it cascades back to my person model, just like the thread in question, showing something line by line:

Are you sure you want to delete the user "JordanReiter2"? All of the following related items will be deleted:

  • User: JordanReiter
    • Face: JordanReiter
      • Presentation: Title1
      • View: Title2

Needless to say, I do not want to delete the person record or any of her descendants!

I understand that I understand the logic: because there is a value in the OneToOne field in the Person record, deleting the user record will create a bad link in the user_id column in the database.

Typically, the solution should switch where the OneToOne field OneToOne . Of course, this is unrealistic impossible, since the User object is largely set by django.contrib.auth .

Is there a way to prevent the cascade of deletion while still having an easy way to access the person from User ? A way to just do this by creating a User model that extends the version of django.contrib ?

Update

I changed the model names, so hopefully this is a little clearer now. In fact, there are thousands of records of Man. Not every person has a login, but if they do, they have one and only one login.

+6
source share
2 answers

It turns out that ForeignKey and OneToOneField have an on_delete attribute that can be set to models.SET_NULL , for example:

 class Person(models.Model): name = models.CharField(max_length=50) # ... etc ... user = models.OneToOneField(User, on_delete=models.SET_NULL, related_name="person", null=True, blank=True) 

This leads to the behavior I wanted: the User model is deleted without touching the Person entry. I overlooked this because it is not explicitly listed in OneToOneField , it just says

In addition, OneToOneField accepts all the additional arguments accepted by ForeignKey ...

Easy to miss.

+23
source

In this case, you should use a simple ForeignKey. OneToOne means that it is one, and can be only one, and it can only be associated with this specific other object. Deletion occurs because it does not make sense to have the onetoone field null, it CANNOT be associated with anything else.

0
source

Source: https://habr.com/ru/post/894420/


All Articles