Django'da Bire Çok ilişki nasıl ifade edilir


167

Django modellerimi şu anda tanımlıyorum OneToManyFieldve model alan türlerinde bir tane olmadığını fark ettim . Eminim bunu yapmanın bir yolu vardır, bu yüzden neyi özlediğimden emin değilim. Aslında böyle bir şey var:

class Dude(models.Model):
    numbers = models.OneToManyField('PhoneNumber')

class PhoneNumber(models.Model):
    number = models.CharField()

Bu durumda, her Dudeçoklu olabilir PhoneNumbers, ama ben biliyorum gerek yok ki ilişki, tek yönlü olmalıdır PhoneNumberhangi DudeBirçok farklı nesneler olabilir gibi kendiliğinden, onu sahip olduğu kendi PhoneNumbergibi a örneklerini, Businessiçin misal:

class Business(models.Model):
    numbers = models.OneToManyField('PhoneNumber')

OneToManyFieldBu tür bir ilişkiyi temsil etmek için modelde neyi (var olmayan) neyle değiştirirdim ? Hibernate / JPA'dan geliyorum, burada bire çok ilişki bildirmek kadar kolaydı:

@OneToMany
private List<PhoneNumber> phoneNumbers;

Bunu Django'da nasıl ifade edebilirim?

Yanıtlar:


135

Django'da Bire Çok ilişkilerini işlemek için kullanmanız gerekir ForeignKey.

ForeignKey ile ilgili belgeler çok kapsamlıdır ve sahip olduğunuz tüm soruları yanıtlamalıdır:

https://docs.djangoproject.com/en/dev/ref/models/fields/#foreignkey

Örneğinizdeki mevcut yapı, her bir Ahbabın bir sayıya sahip olmasına ve her sayının birden çok Ahbap'a (İş ile aynı) ait olmasına izin verir.

Ters ilişki istiyorsanız, PhoneNumber modelinize biri Dude'a diğeri de Business'a iki ForeignKey alanı eklemeniz gerekir. Bu, her sayının bir Dude veya bir Business'a ait olmasına ve Dudes ve Business'ların birden fazla Numaraya sahip olmasına izin verecektir. Bence peşinde olduğun şey bu olabilir.

class Business(models.Model):
    ...
class Dude(models.Model):
    ...
class PhoneNumber(models.Model):
    dude = models.ForeignKey(Dude)
    business = models.ForeignKey(Business)

3
Yukarıdaki sorun göz önüne alındığında bana bir örnek verebilir misiniz? Muhtemelen tamamen özlüyorum, ama bir süredir Django belgelerini okuyorum ve hala bu tür bir ilişkiyi nasıl oluşturacağım konusunda net değilim.
Naftuli Kay

4
YabancıKeylerin her ikisini de zorunlu kılmak istemeyebilir (blank = True, null = True) veya en az bir tane veya diğeri olduğundan emin olmak için bir tür özel doğrulama eklemek isteyebilirsiniz. jenerik numaraya sahip bir işletme durumunda ne olur? ya da işsiz bir ahbap mı?
j_syk

1
@j_syk özel doğrulama hakkında iyi bir nokta. ancak hem bir yabancı anahtarı hem de bir yabancı anahtarı işletmeye dahil etmek ve daha sonra özel (model tanımının dışında) doğrulama yapmak biraz kaba görünüyor. daha temiz bir yol olmalı gibi görünüyor, ama ben de çözemiyorum.
andy

Bu durumda , farklı nesnelerle genel ilişkilere izin veren ContentTypes Çerçevesini kullanmak uygundur . Bununla birlikte, içerik türlerini kullanmak çok hızlı bir şekilde çok karmaşık hale gelebilir ve eğer tek ihtiyacınız varsa, bu daha basit (hacky ise) yaklaşım istenebilir.
kball

57
İlgili bir şey, ForeignKey için "related_name" argümanıdır. Böylece, sahip olduğunuz PhoneNumber sınıfında ilgili tüm sayıları almak için dude = models.ForeignKey(Dude, related_name='numbers')kullanabilirsiniz some_dude_object.numbers.all()("related_name" belirtmezseniz varsayılan olarak "number_set" olur).
markshep

40

Django'da bire çok ilişkiye ForeignKey denir. Bununla birlikte, sadece bir yönde çalışır, bu nedenle ihtiyacınız olan bir numbersınıf niteliğine sahip olmak yerineDude

class Dude(models.Model):
    ...

class PhoneNumber(models.Model):
    dude = models.ForeignKey(Dude)

Birçok modeller olabilir ForeignKeyo bir ikinci özelliğinin olması geçerli olacak, böylece bir başka modele PhoneNumberböyle

class Business(models.Model):
    ...
class Dude(models.Model):
    ...
class PhoneNumber(models.Model):
    dude = models.ForeignKey(Dude)
    business = models.ForeignKey(Business)

Sen erişebilir PhoneNumberbir için s Dudenesne dile d.phonenumber_set.objects.all()ve daha sonra bir için benzer yapmak Businessnesne.


1
ForeignKey"Bire bir" anlamına gelen varsayımdaydım . Yukarıdaki örneğinizi kullanarak Dude, birçok PhoneNumbershakkı olan bir tane olmalı ?
Naftuli Kay

6
Cevabımı bunu yansıtacak şekilde düzenledim. Evet. ForeignKeybelirtirseniz yalnızca bire birdir ForeignKey(Dude, unique=True), bu nedenle yukarıdaki kodla Dudebirden fazla PhoneNumbers ile bir alacaksınız .
stillLearning

1
@rolling stone- teşekkür ederim, siz yorum yaparken hatamı fark ettikten sonra ekliyordum. Unique = True tam olarak OneToOneField gibi çalışmaz, ForeignKey'in Unique = True belirtirseniz yalnızca bire bir ilişki kullandığını açıklamak istedim.
stillLearning

8
İçin yaptığınız +1 PhoneNumber. Şimdi mantıklı olmaya başlıyor. ForeignKeyaslında bire bir, yani bire çok almak için geriye doğru yapmanız gerekir :)
Naftuli Kay

2
Birisi alan adının önemini açıklayabilir phonenumber_setmi? Hiçbir yerde tanımlandığını görmüyorum. Her şeyden önce "_set" ile eklenen modelin adı mı?
James Wierzba


15

OneToManyİlişkinin birçok tarafında (yani ManyToOneilişki) yabancı anahtarı veya ManyToManybenzersiz kısıtlamayla (herhangi bir tarafta) kullanabilirsiniz .


8

djangoyeterince akıllı. Aslında oneToManyalanı tanımlamamız gerekmiyor . djangoSizin için otomatik olarak üretilecek :-). Sadece foreignKeyilgili tabloda tanımlamamız gerekir . Başka bir deyişle, ManyToOneilişkiyi sadece kullanarak tanımlamamız gerekir foreignKey.

class Car(models.Model):
    // wheels = models.oneToMany() to get wheels of this car [**it is not required to define**].


class Wheel(models.Model):
    car = models.ForeignKey(Car, on_delete=models.CASCADE)  

Belirli bir arabanın tekerlek listesini almak istiyorsak. python'sotomatik olarak oluşturulan nesneyi kullanacağız wheel_set. Araba ciçin kullanacaksınızc.wheel_set.all()


5

İken yuvarlanan taş 'ın cevabı basit ve işlevsel iyi olduğunu, bunu çözmez iki şey vardır düşünüyorum.

  1. OP bir telefon numarasını zorunlu kılmak isterse, hem bir Dostum hem de Bir İşletmeye ait olamaz
  2. Dude / Business modellerinde değil, PhoneNumber modelinde ilişkiyi tanımlamanın bir sonucu olarak kaçınılmaz üzüntü hissi. Dünyaya ekstra karasallar geldiğinde ve bir Uzaylı modeli eklemek istediğimizde, Uzaylı modeline bir "phone_numbers" alanı eklemek yerine PhoneNumber'ı (ET'lerin telefon numaraları olduğunu varsayarak) değiştirmemiz gerekir.

PhoneNumber modelinde "genel yabancı anahtar" oluşturmamıza izin veren bazı nesneleri ortaya koyan içerik türleri çerçevesini tanıtın . Sonra, Dostum ve İş dünyasındaki ters ilişkiyi tanımlayabiliriz

from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
from django.contrib.contenttypes.models import ContentType
from django.db import models

class PhoneNumber(models.Model):
    number = models.CharField()

    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    owner = GenericForeignKey()

class Dude(models.Model):
    numbers = GenericRelation(PhoneNumber)

class Business(models.Model):
    numbers = GenericRelation(PhoneNumber)

Bkz dokümanlar Ayrıntılar için ve belki de kontrol bu makaleyi hızlı bir öğretici için.

Ayrıca, burada bir makale savunuyor karşı Jenerik FKS kullanımı.


0

"Birçok" model kendiliğinden bir model oluşturmayı haklı çıkarmıyorsa (burada durum böyle değildir, ancak diğer insanlara fayda sağlayabilir), başka bir alternatif Django Katkı paketi aracılığıyla belirli PostgreSQL veri türlerine güvenmek olacaktır.

Postgres başa çıkabilirim Array veya JSON veri türleri ve bu zaman güzel bir geçici çözüm Bir-çok işlemek için olabilir birçok-ler sadece tek bir varlığa bağlı olabilir biri .

Postgres, dizinin tek öğelerine erişmenizi sağlar; bu, sorguların gerçekten hızlı olabileceği ve uygulama düzeyinde ek yüklerden kaçınabileceği anlamına gelir. Ve elbette, Django bu özellikten yararlanmak için harika bir API uygular .

Açıkçası başkaları veritabanı arka uca taşınabilir olmanın dezavantajı vardır, ama yine de kayda değer değer düşündüm.

Umarım fikir arayan bazı insanlara yardımcı olabilir.


0

Her şeyden önce bir tura çıkıyoruz:

01) bir-çok ilişkisi:

ASSUME:

class Business(models.Model):
    name = models.CharField(max_length=200)
    .........
    .........
    phone_number = models.OneToMany(PhoneNumber) (NB: Django do not support OneToMany relationship)

class Dude(models.Model):
    name = models.CharField(max_length=200)
    .........
    .........
    phone_number = models.OneToMany(PhoneNumber) (NB: Django do not support OneToMany relationship)

class PhoneNumber(models.Model):
    number = models.CharField(max_length=20)
    ........
    ........

Not: Django herhangi bir OneToMany ilişkisi sağlamaz. Django'da üst yöntemi kullanamayız. Fakat ilişkisel modele dönüşmemiz gerekiyor. Öyleyse ne yapabiliriz? Bu durumda ilişkisel modeli ters ilişkisel modele dönüştürmeliyiz.

Buraya:

ilişkisel model = OneToMany

Yani, ters ilişkisel model = ManyToOne

Not: Django ManyToOne ilişkisini destekler ve Django'da ManyToOne, ForeignKey tarafından temsil edilir.

02) çoktan bire ilişki:

SOLVE:

class Business(models.Model):
    .........
    .........

class Dude(models.Model):
    .........
    .........

class PhoneNumber(models.Model):
    ........
    ........
    business = models.ForeignKey(Business)
    dude = models.ForeignKey(Dude)

Not: SADECE DÜŞÜNÜN !!

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.