2012-03-21 28 views
10

Giả sử rằng chúng ta có các mô hình sau đây.Django OneToOneField - tôi nên đặt mô hình nào?

class A(Model): pass 
class B(Model): pass 

Sau đó, không có sự khác biệt giữa:

Trong mô hình A: b = OneToOneField(B, related_name=A.__name__)

trong mô hình B: a = OneToOneField(A, related_name=B.__name__)

Vậy câu hỏi tôi nên tự hỏi bản thân mình để quyết định cho dù đặt OTO trong một mô hình này hay mô hình khác. Tôi có nghĩa là có-a, là-a và vân vân.

Trả lời

1

Tôi nghĩ trường hợp của trường OneToOne, câu trả lời đúng là nó không quan trọng, nó chỉ phụ thuộc vào mô hình nào có ý nghĩa hơn khi liên quan đến mô hình kia.

+0

Vâng, đó là câu hỏi.Làm cách nào để tìm hiểu điều gì có ý nghĩa hơn? Đôi khi hoàn toàn không có sự khác biệt và cả hai cách đều có thể. – aemdy

+0

Trong trường hợp như thế này, nó hoàn toàn tùy thuộc vào bạn. Tôi không nghĩ rằng có một câu trả lời dứt khoát. – Brandon

7

OneToOneField s thực sự chỉ dành cho hai mục đích: 1) thừa kế (Django sử dụng những thực hiện của MTI) hoặc 2) mở rộng của một mô hình không thể chỉnh sửa (như tạo một UserProfile cho User).

Trong hai trường hợp này, hiển nhiên mô hình mà OneToOneField tiếp tục. Trong trường hợp thừa kế, nó đi vào đứa trẻ. Trong trường hợp mở rộng nó đi trên mô hình duy nhất bạn có quyền truy cập.

Với rất một số ngoại lệ, bất kỳ việc sử dụng một sự kiện nào khác thực sự chỉ cần được hợp nhất thành một mô hình duy nhất.

+0

Câu trả lời tuyệt vời Chris. – Brandon

+0

Còn khóa bàn thì sao? Nếu chúng ta chia tách dữ liệu cụ thể (chẳng hạn như bảng lương từ bảng Employee), chúng ta có thể sử dụng 'select_for_update' trên bảng Employee mà không khóa thông tin tiền lương. Chính xác? – grokpot

23

Có sự khác biệt ở nơi bạn đặt trường một-một, vì việc xóa sẽ hoạt động khác nhau. Khi bạn xóa một đối tượng, bất kỳ đối tượng nào khác có mối quan hệ một-một tham chiếu đối tượng đó sẽ bị xóa. Nếu thay vào đó bạn xóa một đối tượng có chứa trường một-một (nghĩa là nó tham chiếu đến các đối tượng khác, nhưng các đối tượng khác không tham chiếu lại nó), không có đối tượng nào khác bị xóa.

Ví dụ:

class A(models.Model): 
    pass 

class B(models.Model): 
    a = models.OneToOneField(A) 

Nếu bạn xóa A, B theo mặc định sẽ bị xóa theo (mặc dù bạn có thể ghi đè này bằng cách sửa đổi đối số on_delete trên OneToOneField giống như với ForeignKey). Xóa B sẽ không xóa A (mặc dù bạn có thể thay đổi hành vi này bằng cách ghi đè phương thức delete() trên B).

Quay lại câu hỏi ban đầu của bạn có-a so với-a, nếu A có B, B phải có trường một-một (B chỉ nên tồn tại nếu A tồn tại, nhưng A có thể tồn tại mà không có B).

0

Bằng cách này, tôi cần thiết để ngăn chặn OneToOneField tròn phụ thuộc (sử dụng thừa kế):

Model A: 
    ... 
    current_choice = models.ForeignKey(B) 

Model B: 
    ... 
    parent = models.ForeignKey(A) 

Điều đó có nghĩa, A có nhu cầu B được xác định. Không phải là một quy ước cơ sở dữ liệu tốt để khởi động. Thay vào đó tôi đã làm:

Model A: 
    ... 

Model B: 
    ... 
    parent = models.ForeignKey(A) 

Model C: 
    parent = models.OneToOneField(A) 
    current_choice = models.ForeignKey(B) 

đối với ví dụ từ documentation Với, bạn cũng có thể truy vấn sạch như: p1.restaurant.place.restaurant.place ... Đây là điên rồ.

+0

Tại sao bạn không nhận ra hành vi này bằng cách sử dụng * related_name * trên khóa ngoại? Vì vậy, trên Model A bạn có thể làm 'current_choice = models.ForeignKey (B, related_name = 'parent')' và sau đó trên mọi instance của B ('b = B.objects.first()') bạn có thể làm 'b.parent 'để tìm đối tượng A liên quan. – Kim

+0

Vâng, 'related_name' không nhất thiết là một-nhưng-một, nhưng được sử dụng như một truy vấn thiết lập hầu hết thời gian, vì vậy bạn cần kiểm tra số vv Ví dụ ở trên là một truy vấn ngay lập tức vì nó đã buộc phải có một kết quả duy nhất chỉ có. – hurturk

Các vấn đề liên quan