Jaka jest różnica między django OneToOneField a ForeignKey?

Jaka jest różnica między Django OneToOneField a ForeignKey?

Author: phoenix, 2011-05-03

10 answers

Bądź ostrożny, aby zdać sobie sprawę, że istnieją pewne różnice między OneToOneField(SomeModel) i ForeignKey(SomeModel, unique=True). Jak stwierdzono w the Definitive Guide to Django:

OneToOneField

Związek jeden do jednego. Koncepcyjnie jest to podobne do ForeignKey z unique=True, ale "odwrotna" strona relacji zwróci bezpośrednio pojedynczy obiekt.

W przeciwieństwie do OneToOneField "odwrotna" relacja, a ForeignKey "odwrotna" relacja zwraca QuerySet.

Przykład

Na przykład, jeśli mamy następujące dwa modele (Pełny kod modelu poniżej):

  1. Car model wykorzystuje OneToOneField(Engine)
  2. Car2 model wykorzystuje ForeignKey(Engine2, unique=True)

From within python manage.py shell wykonaj następujące polecenie:

OneToOneField przykład

>>> from testapp.models import Car, Engine
>>> c = Car.objects.get(name='Audi')
>>> e = Engine.objects.get(name='Diesel')
>>> e.car
<Car: Audi>

ForeignKey z unique=True przykład

>>> from testapp.models import Car2, Engine2
>>> c2 = Car2.objects.get(name='Mazda')
>>> e2 = Engine2.objects.get(name='Wankel')
>>> e2.car2_set.all()
[<Car2: Mazda>]

Kod Modelu

from django.db import models

class Engine(models.Model):
    name = models.CharField(max_length=25)

    def __unicode__(self):
        return self.name

class Car(models.Model):
    name = models.CharField(max_length=25)
    engine = models.OneToOneField(Engine)

    def __unicode__(self):
        return self.name

class Engine2(models.Model):
    name = models.CharField(max_length=25)

    def __unicode__(self):
        return self.name

class Car2(models.Model):
    name = models.CharField(max_length=25)
    engine = models.ForeignKey(Engine2, unique=True, on_delete=models.CASCADE)

    def __unicode__(self):
        return self.name
 552
Author: Matthew Rankin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-11-26 09:57:54

Klucz obcy jest dla jednego do wielu, więc obiekt samochodowy może mieć wiele kół, każde koło ma klucz obcy do samochodu, do którego należy. OneToOneField byłby jak silnik, w którym obiekt samochodowy może mieć jeden i tylko jeden.

 135
Author: Dan Breen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-03 13:58:22

Najlepszym i najskuteczniejszym sposobem uczenia się nowych rzeczy jest oglądanie i studiowanie praktycznych przykładów z prawdziwego świata. Załóżmy przez chwilę, że chcesz zbudować blog w django, gdzie reporterzy mogą pisać i publikować wiadomości. Właściciel gazety online chce, aby każdy ze swoich reporterów mógł opublikować tyle artykułów, ile chcą, ale nie chce, aby różni reporterzy pracowali nad tym samym artykułem. Oznacza to, że gdy czytelnicy pójdą i przeczytają artykuł, zobaczą tylko jednego autora w artykuł.

Na przykład: artykuł Johna, artykuł Harry ' ego, artykuł Ricka. Nie możesz mieć artykułu Harry & Rick, ponieważ szef nie chce, aby dwóch lub więcej autorów pracowało nad tym samym artykułem.

Jak możemy rozwiązać ten 'problem' za pomocą django? Kluczem do rozwiązania tego problemu jest django ForeignKey.

Poniżej znajduje się Pełny kod, który można wykorzystać do realizacji idei naszego szefa.

from django.db import models

# Create your models here.

class Reporter(models.Model):
    first_name = models.CharField(max_length=30)

    def __unicode__(self):
        return self.first_name


class Article(models.Model):
    title = models.CharField(max_length=100)
    reporter = models.ForeignKey(Reporter)

    def __unicode__(self):
        return self.title

Uruchom python manage.py syncdb aby wykonać kod sql i tworzenie tabel dla aplikacji w bazie danych. Następnie użyj python manage.py shell, aby otworzyć powłokę Pythona.

Utwórz obiekt Reporter R1.

In [49]: from thepub.models import Reporter, Article

In [50]: R1 = Reporter(first_name='Rick')

In [51]: R1.save()

Utwórz obiekt artykułu A1.

In [5]: A1 = Article.objects.create(title='TDD In Django', reporter=R1)

In [6]: A1.save()

Następnie użyj poniższego kodu, aby uzyskać nazwisko reportera.

In [8]: A1.reporter.first_name
Out[8]: 'Rick'

Utwórz obiekt Reporter R2, uruchamiając następujący kod Pythona.

In [9]: R2 = Reporter.objects.create(first_name='Harry')

In [10]: R2.save()

Teraz spróbuj dodać R2 do artykułu obiekt A1.

In [13]: A1.reporter.add(R2)

To nie działa i otrzymasz AttributeError obiekt "Reporter" nie posiada atrybutu "add".

Jak widać obiekt artykułu nie może być powiązany z więcej niż jednym obiektem reportera.

A co z R1? Czy możemy dołączyć do niego więcej niż jeden obiekt artykułu?

In [14]: A2 = Article.objects.create(title='Python News', reporter=R1)

In [15]: R1.article_set.all()
Out[15]: [<Article: Python News>, <Article: TDD In Django>]

Ten praktyczny przykład pokazuje nam, że django ForeignKey jest używane do definiowania relacji wielu do jednego.

OneToOneField służy do tworzenia relacji jeden-do-jednego.

Możemy użyć reporter = models.OneToOneField(Reporter) w powyższym models.py plik ale nie będzie przydatne w naszym przykładzie jako autor nie będzie w stanie opublikować więcej niż jednego artykułu.

Za każdym razem, gdy chcesz opublikować nowy artykuł, musisz utworzyć nowy obiekt Reporter. To czasochłonne, prawda?

Gorąco polecam wypróbować przykład z {[11] } i uświadomić sobie różnicę. Jestem całkiem pewien, że po tym przykładzie całkowicie poznasz różnicę między django OneToOneField i django ForeignKey.

 52
Author: orthodoxpirate,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-14 19:29:58

OneToOneField (one-to-one) realizuje w orientacji obiektowej pojęcie kompozycji, podczas gdy ForeignKey (one-to-many) odnosi się do agregacji.

 14
Author: andrers52,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-27 21:42:52

Gdy uzyskasz dostęp do OneToOneField, otrzymasz wartość pola, które zapytałeś. W tym przykładzie pole "Tytuł" modelu książki jest polem OneToOneField:

>>> from mysite.books.models import Book
>>> b = Book.objects.get(id=50)
>>> b.title
u'The Django Book'

Gdy uzyskasz dostęp do klucza zagranicznego, otrzymasz powiązany obiekt modelu, który możesz następnie preform dalszych zapytań. W tym przykładzie pole "wydawca" tego samego modelu książki jest kluczem obcym (korelującym z definicją modelu klasy wydawcy):

>>> b = Book.objects.get(id=50)
>>> b.publisher
<Publisher: Apress Publishing>
>>> b.publisher.website
u'http://www.apress.com/'

Z ForeignKey fields queries działają również w drugą stronę, ale są nieco inny ze względu na niesymetryczny charakter relacji.

>>> p = Publisher.objects.get(name='Apress Publishing')
>>> p.book_set.all()
[<Book: The Django Book>, <Book: Dive Into Python>, ...]

Za kulisami, book_set jest tylko zestawem zapytań i może być filtrowany i krojony jak każdy inny zestaw zapytań. Atrybut nazwa book_set jest generowany przez dodanie nazwy modelu z małymi literami do _set.

 4
Author: Yup.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-12 18:59:13

Również {[2] } jest przydatne do użycia jako klucz główny, aby uniknąć powielania kluczy. Można nie mieć autofield implicit / explicit

models.AutoField(primary_key=True)

Ale zamiast tego użyj OneToOneField jako klucza podstawowego (wyobraź sobie na przykład model UserProfile):

user = models.OneToOneField(
    User, null=False, primary_key=True, verbose_name='Member profile')
 4
Author: Dmitriy Sintsov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-26 16:58:44

OneToOneField: jeśli druga tabela jest powiązana z

table2_col1 = models.OneToOneField(table1,on_delete=models.CASCADE, related_name='table1_id')

Table2 będzie zawierał tylko jeden rekord odpowiadający wartości pk table1, tzn. table2_col1 będzie miał unikalną wartość równą pk tabeli

table2_col1 == models.ForeignKey(table1, on_delete=models.CASCADE, related_name='table1_id')

Table2 może zawierać więcej niż jeden rekord odpowiadający wartości pk table1.

 2
Author: aarif faridi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-03-28 11:27:33

Najprostszym sposobem na narysowanie relacji między przedmiotami jest zrozumienie ich w prostych językach. Przykład

Użytkownik może mieć wiele samochodów, ale wtedy samochód może mieć tylko jednego właściciela. Po ustaleniu tego, klucz obcy powinien być użyty na elemencie z relacją wielu. W tym przypadku samochód. Oznacza to, że użytkownik będzie oznaczony jako klucz obcy w samochodach

A relacja jeden na jednego jest dość prosta. Powiedz człowiek i serce. Człowiek ma tylko jedno serce i serce może należeć tylko do one man

 2
Author: T. Ems,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-14 22:08:25

ForeignKey pozwala na odbieranie podklas czy jest to definicja innej klasy, ale OneToOneFields nie może tego zrobić i nie jest dołączany do wielu zmiennych

 1
Author: Bitdom8,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-09-30 12:11:44

OneToOneField (przykład: jeden samochód ma jednego właściciela) ForeignKey (OneToMany) (przykład: jedna restauracja ma wiele pozycji)

 0
Author: Siva Sankar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-01-27 11:32:16