2015-12-23 3 views
1

Я знаю, что ForeignKeys и OneToOneFields, а также ManyToManyField, как они работают, и когда их использовать. Тем не менее, я работаю с проектом, у которого Многие отношения не могут быть изменены. Итак, предположим, I want to let a user have many phone numbers, я обычно это сделать:OneToMany отношения в Django с одной моделью заблокированы

# my_app/models.py 
from django.db import models 
class User(Model): 
    ... 

class PhoneNumber(models.Model): 
    user = models.ForeignKey(User) 

У меня есть проблема в том, что моя PhoneNumber модель эквивалент из пакета третьей стороной, уже заполнены записями, а не подклассы в моем приложении. То есть

# third_party_django_package/models.py 
from django.db import models 
class PhoneNumber(models.Model): 
    # This cannot change 

# my_app/models.py 
from django.db import models 
from third_party_django_package.models import PhoneNumber 
class User(Model): 
    # These do not work -- a user can have more than one phone number 
    phone_number = models.ForeignKey(PhoneNumber) 
    phone_number = models.OneToOneField(PhoneNumber) 

    # This is close, but I want a phone number to belong to only one User 
    phone_numbers = models.ManyToManyField(PhoneNumber, related_name=...) 

    def clean(self): 
     # Validating the M2M relation costs extra queries, is slow, and 
     # is prone to race conditions 

Это все псевдокод.

Без использования yet another third-party package, который обращается к внутренним членам Django, что делает проект еще менее совместимым с переходом, какие параметры у меня остались, чтобы получить правильный OneToManyField с правильными ограничениями на уровне схемы?

ответ

7

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

class UserPhoneNumber(models.Model): 
    phone_number = models.OneToOneField(PhoneNumber) 
    user = models.ForeignKey(User) 

Это немного громоздко, но, по крайней мере, оно достигает того, что вам нужно.

Edit:

Как @Daniel сказал, что это можно сделать, используя отношения M2M с through модели с unique_together на полях:

class User(Model): 
    phone_numbers = models.ManyToManyField(PhoneNumber, through=UserPhoneNumber) 

class UserPhoneNumber(Model): 
    phone_number = models.ForeignKey(PhoneNumber) 
    user = models.ForeignKey(User) 

    class Meta: 
     unique_together = ('phone_number', 'user') 

Это сделает вашу жизнь проще, если вам хотите найти номера телефонов пользователя, выполнив numbers = user.phone_numbers.all().

+0

Я не думаю, что вы можете сделать это лучше или эквивалентную настройку наследования модели. –

+0

Ага, это сработало у меня в голове! Согласились обо всем, что вы сказали, включая громоздкую часть. – Brian

+0

Возможно, вы сможете определить это как сквозную таблицу M2M от User to PhoneNumber, и в этом случае она становится значительно менее громоздкой. –

Смежные вопросы