2013-08-17 70 views
14

Sự khác biệt giữa các triển khai này là gì? Django khác gì (bên cạnh kế thừa Meta ordering và thuộc tính get_latest_by)?Sự khác biệt giữa mô hình kế thừa nhiều bảng và mối quan hệ một-một giữa hai mô hình giống nhau là gì?

1.

# models.py 
from django.db import models 

class Place(models.Model): 
    name = models.CharField(max_length=50) 

class Restaurant(models.Model): 
    place = models.OneToOneField(Place) 
    serves_pizza = models.BooleanField() 

2.

class Place(models.Model): 
    name = models.CharField(max_length=50) 

class Restaurant(Place): 
    serves_pizza = models.BooleanField() 

3.

class Place(models.Model): 
    name = models.CharField(max_length=50) 

class Restaurant(Place): 
    place = models.OneToOneField(Place, parent_link=True) 
    serves_pizza = models.BooleanField() 
+0

Tôi muốn mở rộng các trang web được xây dựng trong khuôn khổ Mô hình trang web với các trường bổ sung và cố gắng quyết định phương pháp nào là tốt nhất. – kissgyorgy

Trả lời

17

1. Bạn không thực sự nhận được bất kỳ thừa kế python, có nghĩa là bạn không thể kế thừa/phương pháp ghi đè hoặc các thuộc tính từ lớp mô hình Place trong lớp học của bạn Restaurant:

Ví dụ:

class Place(models.Model): 
    name = models.CharField(max_length=50) 

    def get_x(self): 
     return 'x' 

class Restaurant(models.Model): 
    place = models.OneToOneField(Place) 
    serves_pizza = models.BooleanField() 

a_restaurant = Restaurant() 
a_restaurant.get_x() # -> wouldn't work 

Điều này có nghĩa rằng để có được những name của một nhà hàng, bạn không thể làm a_restaurant.name, bạn sẽ cần phải làm theo các liên kết: a_restaurant.place.name

Cũng lưu ý rằng khi truy vấn một đối tượng Place với liên quan Restaurant.

a_restaurant.save() 
Place.objects.get(pk=a_restaurant.pk) # won't work 

Bạn sẽ phải viết:

a_restaurant.save() 
Place.objects.get(restaurant__pk=a_restaurant.pk) 

2 và 3. gần như giống nhau. Bạn nhận được sự thừa kế python thực với những điều này.

a_restaurant = Restaurant() 
a_restaurant.get_x() # would actually work and print 'x' 

lớp Mô hình của bạn Restaurant thừa hưởng tất cả mọi thứ từ Place: lĩnh vực người mẫu, các thuộc tính dụ/lớp bình thường, các nhà quản lý, phương pháp ... và bạn cũng có thể ghi đè lên hầu hết mọi thứ trong số này: Bạn không có thể ghi đè các thuộc tính lĩnh vực , điều đó không được hỗ trợ.

Vì vậy, bây giờ bạn có thể lấy giá trị của các trường từ mô hình gốc trực tiếp: a_restaurant.name vì chúng được kế thừa.

Kể từ với những thực hiện một Restaurant một cũng Place bạn có thể truy vấn cho một đối tượng Place với Restaurant dữ liệu:

a_restaurant.save() 
the_place = Place.objects.get(pk=a_restaurant.pk) 
#^this works now and returns the equivalent `Place` instance. 
the_same_restaurant = the_place.restaurant 

Các chênh lệch giữa 2 và 3 là dễ dàng hơn để xem bạn đặt tên khác cho trường:

class Place(models.Model): 
    name = models.CharField(max_length=50) 

class Restaurant(Place): 
    where = models.OneToOneField(Place, parent_link=True) 
    serves_pizza = models.BooleanField() 

trình giống hệt nhau nhưng để có được những vị trí phụ huynh của Restaurant tên thuộc tính là where:

the_place = a_restaurant.where 

với sẽ là:

the_place = a_restaurant.place_ptr 

Những phương tiện đó place = models.OneToOneField(Place, parent_link=True) sẽ chỉ thay đổi tên của liên kết đến cá thể mô hình gốc. Tên mặc định là '{lowercase_model_name}_ptr'.


dụ cuối:

Với :

place1 = Place.objects.create(name='place_1') 
place2 = Place.objects.create(name='place_2') 
restaurant1 = Restaurant.objects.create(place=place1, serves_pizza=True) 

print Place.objects.all() # prints [place1, place2] 
print Restaurant.objects.all() # prints [restaurant1] 

Với 2-3:

place1 = Place.objects.create(name='place_1') 
place2 = Place.objects.create(name='place_2') 
restaurant1 = Restaurant.objects.create(name='place_3', serves_pizza=True) 

print Place.objects.all() # prints [place1, place2, place3] 
print Restaurant.objects.all() # prints [restaurant1] 

Hy vọng những điều này sẽ giúp ích cho bạn. Nó phát triển một chút quá dài:/

+0

Ý kiến ​​cá nhân của tôi: tùy chọn 2º có vẻ là triển khai tốt nhất cho ví dụ này bởi vì 'Nhà hàng' thực sự là' Địa điểm'. –

+0

lời giải thích rất hay, tôi đã không mong đợi điều này :) cảm ơn bạn! – kissgyorgy

+1

Một thông báo: Tên mặc định cho OneToOneField từ mô hình con là 'objectname.parentobject_ptr' (không phải objectname.parentobject) trong Django 1.5. Vì vậy, bạn có thể truy vấn Địa điểm bằng 'a_restaurant.place_ptr' trong # 2. Nhưng cách khác xung quanh (query từ nơi này) đó là: 'a_place.restaurant' – kissgyorgy

3

1 - để tạo ra nhà hàng, bạn cần phải tạo ra, sau khi tạo ra nhà hàng, sau khi liên kết chúng, 2 - sau đó tạo nhà hàng, địa điểm mới được tạo và tự động liên kết, 3 - yo u đã đổi tên thành liên kết gốc thành địa điểm.

Sử dụng mẫu Thừa hưởng với các loại nội dung bạn có thể liệt kê tất cả các quán ăn, nhà hàng, quán bar, vv iterating trên Place.objects.all()