Связь OneToOne с моделью User (django.contrib.auth) без каскадного удаления - PullRequest
6 голосов
/ 06 августа 2011

Я немного озадачен тем, как OneToOneField работает, когда удаление вступает в игру.Единственная квазиавторизованная информация, которую я могу найти, это эта тема на django-developers :

Я не знаю, обнаружили ли вы это еще, но удаление работает вв одном направлении, но не в том направлении, в котором вы ожидаете.Например, используя модели, которые вы разместили в другом сообщении:

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

Если вы создаете место и связанный с ним ресторан, удаление ресторана не приведет к удалению этого места (это проблема, которую высообщайте здесь), но удаление Места приведет к удалению ресторана.

У меня есть следующая модель:

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

Она настроена таким образом, что я могу легко получить доступ person из User экземпляра, использующего user.person.

Однако, когда я пытаюсь удалить запись User в admin, естественно, это каскадно возвращается к моей Person модели, как обсуждалось в потоке,показывая что-то вроде:

Вы уверены, что хотите удалить пользователя "JordanReiter2"?Все следующие связанные элементы будут удалены:

  • Пользователь: JordanReiter
    • Персона: JordanReiter
      • Представление: Title1
      • Представление: Title2

Нет необходимости говорить, что я не хочу удалить запись Person или любого из ее потомков!

Полагаю, я понимаю логику: поскольку в поле OneToOne в записи Person есть значение, удаление записи User приведет к неправильной ссылке в столбце user_id в базе данных.

Обычно решением было бы переключиться в том месте, где находится поле OneToOne.Конечно, это нереально возможно, поскольку объект User в значительной степени установлен на django.contrib.auth.

Есть ли какой-нибудь способ предотвратить каскад удаления, при этом оставаясь простым способом доступа к человеку из user?Есть ли only способ сделать это, создав User модель, которая расширяет django.contrib версию?

Update

Я изменил названия моделей так, надеюсь, теперь этонемного понятнее.В основном там тысячи записей о людях.Не у каждого есть логин, но если он есть, у него один и только один логин.

Ответы [ 2 ]

23 голосов
/ 06 августа 2011

Оказывается, что и ForeignKey, и OneToOneField имеют атрибут on_delete, который можно установить на models.SET_NULL, например:

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)

Это приводит к желаемому поведению: модель User удаляется, не касаясь записи Person. Я упустил из виду это, потому что это явно не перечислено под OneToOneField, это просто говорит

Кроме того, OneToOneField принимает все дополнительные аргументы, принятые ForeignKey ...

Легко пропустить.

0 голосов
/ 06 августа 2011

Для этого варианта использования вы должны использовать простой ForeignKey. OneToOne означает, что он есть, и может быть только один, и он может быть связан только с этим другим конкретным объектом. Удаление происходит потому, что не имеет смысла иметь нулевое одноэлементное поле, оно НЕ МОЖЕТ быть связано ни с чем другим.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...