Django OneToOneField ve ForeignKey arasındaki fark nedir?


Yanıtlar:


507

OneToOneField(SomeModel)Ve arasında bazı farklar olduğunu fark etmeye dikkat edin ForeignKey(SomeModel, unique=True). Django'nun Kesin Kılavuzunda belirtildiği gibi :

OneToOneField

Bire bir ilişki. Kavramsal olarak, bu bir ForeignKeyile benzerdir unique=True, ancak ilişkinin "ters" tarafı doğrudan tek bir nesneyi döndürür.

OneToOneField"Ters" ilişkinin aksine, "ters" ilişki a ForeignKeydöndürür QuerySet.

Misal

Örneğin, aşağıdaki iki modelimiz varsa (aşağıdaki tam model kodu):

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

İçinden python manage.py shellaşağıdakileri yürütün:

OneToOneField Misal

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

ForeignKeyile unique=True, Örnek

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

Model kodu

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

5
@MarkPNeyer: anladığım kadarıyla, bir OneToOne alanı sadece: bire bir. Üzerine olmak zorunda değil. Bu örneğe bakın : bir yerin restoran olması gerekmez.
osa

21
Bu cevapta "bazı farklılıklar var" yazıyor ve sonra bir fark var. Başkaları var mı?
Chris Martin

6
Chris ile aynı şeyi merak ediyorum. Basitçe sözdizimsel şeker mi, verilere nasıl erişildiği konusunda performans farklılıklarına yol açan temel bir fark var mı?
Carlos

4
Django'nun yabancı anahtar benzersiz ve boş değilse, o zaman e.carda işe yarayacak bir kurala sahip olamamasının temel bir nedeni var mı?
Ciro Santilli 法轮功 冠状 病 六四 事件 法轮功

4
Peki ... ne biri bile bir kullanmak isteyeyim ForeignKeyile unique=Trueyerine OneToOneField? Diğer sorularda, Django'nun OneToOneFieldgenellikle en iyi hizmetin çıkarlarının olduğunu uyardığını görüyorum . Tersi QuerySetasla birden fazla öğeye sahip olmayacak, değil mi?
Andy

121

Bir ForeignKey bire çok içindir, bu nedenle bir Car nesnesinin birçok Tekerlekleri olabilir, her bir Tekerlek ait olduğu Arabaya bir YabancıKey'e sahiptir. Bir OneToOneField, bir Car nesnesinin yalnızca bir tanesine sahip olabileceği bir Motor gibi olacaktır.


4
teşekkür ederim, Dose OneToOneField (someModel), ForeignKey (SomeModel, unique = True) anlamına mı geliyor?
Redice

9
Evet: 'Bir OneToOneField aslında bir ForeignKey ile aynıdır, ancak her zaman onunla "benzersiz" bir kısıtlama taşır ve ters ilişki her zaman işaret edilen nesneyi döndürür (yalnızca bir tane olacağından) liste.'
Dan Breen

1
Aynı motora sahip birkaç arabaya ne dersiniz?
Oleg Belousov

3
@OlegTikhonov Aynı motor tasarımının bir kopyasına sahip olabilirler , ancak birkaç otomobilin aynı fiziksel motoru paylaştığı bir örneği görmek istiyorum.
Dan Breen

3
Bu cevaptaki terimler hakkında biraz karışıklık var. ForeignKey bire-bir çok değil ama resmi django belgelerine göre bir çok-one ilişkidir: docs.djangoproject.com/en/2.0/ref/models/fields/...
Kutay Demireren

45

Yeni şeyler öğrenmenin en iyi ve en etkili yolu, gerçek dünyadaki pratik örnekleri görmek ve çalışmaktır. Django'da gazetecilerin haber makaleleri yazabileceği ve yayınlayabileceği bir blog oluşturmak istediğinizi varsayalım. Çevrimiçi gazetenin sahibi, gazetecilerinin her birinin istedikleri kadar makale yayınlamasına izin vermek istiyor, ancak farklı gazetecilerin aynı makale üzerinde çalışmasını istemiyor. Bu, okuyucular bir makaleye gidip okuduklarında makalede yalnızca bir yazar görecekleri anlamına gelir.

Örneğin: John'dan makale, Harry'den makale, Rick'den makale. Harry ve Rick'in makalesi olamaz, çünkü patron iki veya daha fazla yazarın aynı makale üzerinde çalışmasını istemiyor.

Bu 'problemi' django yardımıyla nasıl çözebiliriz? Bu sorunun çözümünün anahtarı django'dur ForeignKey.

Patronumuzun fikrini uygulamak için kullanılabilecek tam kod aşağıdadır.

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

Run python manage.py syncdbsql kodu çalıştırmak ve veritabanınızda uygulamanız için tabloları oluşturma. Sonra python manage.py shellbir piton kabuğu açmak için kullanın .

Reporter nesnesi R1'i oluşturun.

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

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

In [51]: R1.save()

Makale nesnesi A1'i oluşturun.

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

In [6]: A1.save()

Sonra muhabirin adını almak için aşağıdaki kod parçasını kullanın.

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

Şimdi aşağıdaki python kodunu çalıştırarak Reporter nesnesi R2'yi oluşturun.

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

In [10]: R2.save()

Şimdi A1 nesne nesnesine R2 eklemeyi deneyin.

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

Çalışmıyor ve 'Reporter' nesnesinin 'add' özelliği yok diyen bir AttributeError alacaksınız.

Gördüğünüz gibi bir Makale nesnesi birden fazla Reporter nesnesiyle ilişkilendirilemez.

R1 ne olacak? Birden fazla Makale nesnesi ekleyebilir miyiz?

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>]

Bu pratik örnek bize django'nun ForeignKeybire bir ilişkileri tanımlamak için kullanıldığını göstermektedir.

OneToOneField bire bir ilişkiler oluşturmak için kullanılır.

reporter = models.OneToOneField(Reporter)Yukarıdaki models.py dosyasında kullanabiliriz , ancak bir yazarın birden fazla makale yayınlayamayacağı için örneğimizde yararlı olmayacaktır.

Her yeni makale göndermek istediğinizde yeni bir Reporter nesnesi oluşturmanız gerekir. Bu zaman alıcı, değil mi?

Örneği ile denemenizi OneToOneFieldve farkı fark etmenizi şiddetle tavsiye ederim . Bu örnekten sonra django OneToOneFieldve django arasındaki farkı tam olarak bileceğinizden eminim ForeignKey.


Bunu severim. OneToOne ve ForeignKey arasındaki temel fark, bire bir ve bire çok ilişkidir. Birebir yapmak için ForeignKey ve unique = True kullanabilirsiniz, ince fark Matthew'in cevabında belirtilir.
FrankZhu

13

OneToOneField (bire bir), nesne yöneliminde kompozisyon kavramını gerçekleştirirken, ForeignKey (bire-çok) anlaşma ile ilgilidir.


3
Güzel benzetme, ama her zaman böyle değil. Bu açıklamaya uymayan bazı uç durumlar vardır. Diyelim ki sınıflarımız var Patientve Organ. Patientbirçok Organs olabilir, ancak bir Organkutu sadece birine aittir Patient. Ne zaman Patientsilinir, bütün Organler de silinir. Onlar olmadan var olamazlar Patient.
cezar

4

Ayrıca OneToOneFieldtemel tekrarından kaçınmak için birincil anahtar olarak kullanılacak yararlıdır. Birinin üstü kapalı / açık otomatik alanı olmayabilir

models.AutoField(primary_key=True)

ancak OneToOneFieldbunun yerine birincil anahtar olarak kullanın ( UserProfileörneğin modeli hayal edin ):

user = models.OneToOneField(
    User, null=False, primary_key=True, verbose_name='Member profile')

3

Bir OneToOneField öğesine eriştiğinizde, sorguladığınız alanın değerini alırsınız. Bu örnekte bir kitap modelinin 'başlık' alanı bir OneToOneField'dir:

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

Bir ForeignKey'e eriştiğinizde, ilgili model nesnesini alırsınız; daha sonra başka sorguları önceden oluşturabilirsiniz. Bu örnekte aynı kitap modelinin 'yayıncı' alanı bir ForeignKey'dir (Yayıncı sınıfı model tanımıyla ilişkili):

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

ForeignKey alanları ile sorgular başka şekilde de çalışır, ancak ilişkinin simetrik olmayan yapısı nedeniyle biraz farklıdırlar.

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

Sahnelerin arkasında, book_set sadece bir QuerySet'tir ve diğer QuerySet gibi filtrelenebilir ve dilimlenebilir. Book_set öznitelik adı, _set öğesine küçük harfli model adı eklenerek oluşturulur.


1

OneToOneField: İkinci tablo aşağıdakilerle ilgiliyse

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

table2, table1'in pk değerine karşılık gelen sadece bir kayıt içerecektir, yani table2_col1, tablonun pk değerine eşit benzersiz bir değere sahip olacaktır

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

table2, table1'in pk değerine karşılık gelen birden fazla kayıt içerebilir.


1

ForeignKey, başka bir sınıfın tanımı olan alt sınıfları almanıza izin verir, ancak OneToOneFields bunu yapamaz ve birden çok değişkene bağlanamaz

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.