2012-02-13 28 views
5

Tôi có hai mô hình trong Django liên kết với nhau bởi mối quan hệ ManyToMany như thế này:Bắt mục mục đầu tiên trong một mối quan hệ nhiều-nhiều trong Django

class Person(models.Model): 
    name = models.CharField(max_length=128) 

class Group(models.Model): 
    name = models.CharField(max_length=128) 
    members = models.ManyToManyField(Person) 

tôi cần để có được những nhân vật chính trong nhóm mà là người đầu tiên trong nhóm. Làm thế nào tôi có thể có được người đầu tiên?

Đây là cách tôi đang bổ sung thêm thành viên:

grp = Group.objects.create(name="Group 1") 
grp.save() 
prs = Person.objects.create(name="Tom") 
grp.members.add(prs) #This is the main person of the group. 
prs = Person.objects.create(name="Dick") 
grp.members.add(prs) 
prs = Person.objects.create(name="Harry") 
grp.members.add(prs) 

Tôi không nghĩ rằng tôi cần bất kỳ cột bổ sung như id của bảng group_members là một chuỗi hoạt động đúng.

Nếu tôi cố gắng tìm nạp thành viên chính của nhóm thông qua Group.objects.get(id=1).members[0] thì Django nói rằng người quản lý không thể lập chỉ mục được.

Nếu tôi thử điều này Group.objects.get(id=1).members.all().order_by('id')[0], tôi nhận được thành viên có id thấp nhất trong bảng Person.

Tôi làm cách nào để giải quyết vấn đề này?

Cảm ơn

+0

Bạn muốn xác định ai là người "đầu tiên" trong nhóm? ID? Theo thứ tự abc? – Brandon

+0

Giá trị có 'id' thấp nhất trong bảng' group_members'. Các đối tượng không bao giờ bị xóa khỏi bảng này vì vậy thành viên chính sẽ luôn giống nhau cho một nhóm. –

+0

Câu trả lời của Alex Gaynor là chính xác. Bạn sẽ cần phải thêm một trường bổ sung để sắp xếp theo nhóm, vì cột ID không được đảm bảo tuần tự cho nhóm. – Brandon

Trả lời

4

Django không chú ý đến thứ tự của các cuộc gọi đến add. Bảng ngầm Django có cho mối quan hệ là một cái gì đó như sau nếu nó là một mô hình Django:

class GroupMembers(models.Model): 
    group = models.ForeignKey(Group) 
    person = models.ForeignKey(Person) 

Rõ ràng, không có gì về một "thứ tự" hoặc bạn nên đến trước. Theo mặc định, nó có thể sẽ làm như bạn mô tả và trả lại pk thấp nhất, nhưng đó là chỉ vì nó không có gì khác để đi ra khỏi.

Nếu bạn muốn thực thi một đơn đặt hàng, bạn sẽ phải sử dụng một bảng. Về cơ bản, thay vì để Django tạo ra mô hình ngầm định, bạn tự tạo ra nó. Sau đó, bạn sẽ thêm một lĩnh vực như order ra lệnh thứ tự:

class GroupMembers(models.Model): 
    class Meta: 
     ordering = ['order'] 

    group = models.ForeignKey(Group) 
    person = models.ForeignKey(Person) 
    order = models.PositiveIntegerField(default=0) 

Sau đó, bạn cho Django để sử dụng mô hình này cho các mối quan hệ, thay vì:

class GroupMembers(models.Model): 
    group = models.ForeignKey(Group) 
    person = models.ForeignKey(Person, through='GroupMembers') 

Bây giờ, khi bạn thêm của bạn thành viên, bạn không thể sử dụng add nữa vì thông tin bổ sung cần phải hoàn thành mối quan hệ.Thay vào đó, bạn phải sử dụng mô hình thông qua:

prs = Person.objects.create(name="Tom") 
GroupMembers.objects.create(person=prs, group=grp, order=1) 
prs = Person.objects.create(name="Dick") 
GroupMembers.objects.create(person=prs, group=grp, order=2) 
prs = Person.objects.create(name="Harry") 
GroupMembers.objects.create(person=prs, group=grp, order=3) 

Sau đó, chỉ cần sử dụng:

Group.objects.get(id=1).members.all()[0] 

Ngoài ra, bạn có thể chỉ cần thêm một BooleanField để xác định đó là sử dụng chính:

class GroupMembers(models.Model): 
    group = models.ForeignKey(Group) 
    person = models.ForeignKey(Person) 
    is_main_user = models.BooleanField(default=False) 

Sau đó, thêm "Tom" như:

prs = Person.objects.create(name="Tom") 
GroupMembers.objects.create(person=prs, group=grp, is_main_user=True) 

Và cuối cùng, truy xuất "Tom" qua:

Group.objects.get(id=1).members.filter(is_main_user=True)[0] 
3

Cơ sở dữ liệu quan hệ không có bất kỳ khái niệm đặt hàng nào theo mặc định. Không có thứ gì như "đầu tiên". Bạn cần thêm trường "đơn đặt hàng" rõ ràng giữ thứ tự và sắp xếp theo thứ tự.

1

Bạn đã khá chặt chẽ:

Group.objects.get(id=1).members.all()[0] 

(Nhưng khi Alex Gaynor nói trong câu trả lời của mình, cho hành vi dự đoán bạn cần có một lĩnh vực thích hợp để sắp xếp trên)

+0

Tôi đã xem bảng whcih chứa mối quan hệ tức là 'group_persons' (tôi nghĩ), trong cơ sở dữ liệu và nó có cột' id' ngoài 'group_id' và' person_id'. Vì đây là một chuỗi đang chạy, tôi không thể lấy mục có 'id' thấp nhất. Ví dụ mà bạn đã đưa ra: không phải điều đó sẽ trả lại cho tôi đối tượng đầu tiên trong bộ này nhưng bộ đó sẽ không được đặt hàng và do đó không chính xác? Cảm ơn. –

+0

Bạn không cần "đối tượng" thứ hai (thậm chí có hoạt động không?) Chỉ cần 'members.all()'. –

+0

Bạn đúng, sai lầm của tôi. Tôi đã chỉnh sửa nó –

0

đáng tin cậy lưu giữ hồ sơ của người người "chính" trong một nhóm, bạn có thể muốn xem bảng sử dụng through để giữ siêu dữ liệu này

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