2012-03-13 34 views
10

Tôi có một mô hình trông như thế này:Django Giới hạn ManytoMany queryset dựa trên chọn FK

class Invite(models.Model): 
    user = models.ForeignKey(User) 
    event = models.ForeignKey(Event) 
    roles = models.ManyToManyField(Role, blank=True, null=True) 
    sent = models.BooleanField("Invite Sent", default=False, editable=False) 
    created = models.DateTimeField(auto_now_add=True) 

    def __unicode__(self): 
     return u"%s" % self.user 

    class Meta: 
     unique_together =(('user','event'),) 


class Role(models.Model): 
    """ 
    This associates a user's role to an event 
    """ 
    event = models.ForeignKey(Event, related_name="roles") 
    roletype = models.ForeignKey(RoleType) 
    profiles = models.ManyToManyField(Profile, related_name="roles", 
      blank=True, null=True) 
    modified = models.DateTimeField(auto_now=True) 
    created = models.DateTimeField(auto_now_add=True) 

Vì vậy, bất cứ khi nào một sự kiện mới được tạo ra, một loạt các vai trò được tạo ra cùng với nó. Trong mô hình Mời, làm thế nào tôi có thể chỉ hiển thị các vai trò liên kết với sự kiện tôi đã chọn trong biểu mẫu thay đổi trong Quản trị Django thay vì hiển thị tất cả các mục trong mô hình Vai trò?

Trả lời

6

Bạn muốn tự động lọc các lựa chọn của roleschoices, vì vậy bạn sẽ cần ajax để thực hiện nhiệm vụ này.

Đây là cách bạn có thể làm cho công việc này ..

1:OnChange của event gửi event_id để tùy chỉnh của bạn view qua ajax.

2: Từ Roles mô hình filter dựa trên event_id bạn nhận được từ các yêu cầu ajax và trả lại lọc roles bởi serializing vào JSON.

3: Xóa số hiện tại roles và lặp lại bằng cách phân tích cú pháp thông qua phản hồi JSON.

Ví dụ: Đây là một ví dụ jquerygetJSON

javascript:

$("#event").change(function(){   
var event_id = $(this).val();    
    $.getJSON("/my-app/my-roles-filter-view/"+ event_id +"/",function(data){ 
     var roles_dd = $("#roles"); 
     $('#event >option').remove(); 
     $.each(data, function(index,value) { 
     roles_dd.append($("<option />").val(value).text(value)); 
    });     
})(django.jquery); 

url:

('^/my-app/my-roles-filter-view/(?P<event_id>\d+)/$','my_view'), 

lần xem:

def my_view(request,event_id): 
    qs = Role.objects.filter(event=event_id).values_list('id') 
    return HttpResponse(simplejson.dumps(qs),mimetype='application/javascript') 

Đây chỉ là ví dụ sử dụng jquery bạn có thể sử dụng bất kỳ loại ajax nào và đạt được điều này.

+4

Không, điều này có thể (và nên) đạt được trong mã Python. – DrMeers

+0

Giải pháp cần java script bởi vì khi anh ta chọn 'event' trong form, role phải được lọc động (không nhấn nút, submit toàn bộ form và sau đó quay trở lại với các lựa chọn đã được lọc), do đó' ajax' là cách đi. – Pannu

+0

Có, nếu bạn muốn thay đổi trong trình duyệt khi bạn thay đổi sự kiện đã chọn trong tiện ích, thì tất nhiên bạn cần sử dụng Javascript. Xin lỗi, tôi đã đọc sai. – DrMeers

2

Bạn cần cung cấp phương thức tùy chỉnh formfield_for_foreignkey trong lớp quản trị của mình cho mô hình.

Ví dụ này (từ các tài liệu mà tôi liên kết), bạn nên bắt đầu:

class MyModelAdmin(admin.ModelAdmin): 
    def formfield_for_foreignkey(self, db_field, request, **kwargs): 
     if db_field.name == "car": 
      kwargs["queryset"] = Car.objects.filter(owner=request.user) 
     return super(MyModelAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs) 
+1

Việc này sẽ được thực hiện vào thời gian tải và không hoạt động. Tôi tin rằng 'các lựa chọn' phải được' lọc' động. Đó là những gì câu hỏi dường như về. – Pannu

+0

@Pannu: Không, điều này thực sự gần với giải pháp đúng, nhưng để giải quyết vấn đề cụ thể này, bạn cần truy cập vào cá thể Mời được đề cập. – DrMeers

9

Bạn có thể muốn một cái gì đó dọc theo dòng:

class InviteAdmin(admin.ModelAdmin): 
    def get_form(self, request, obj=None, **kwargs): 
     self.instance = obj # Capture instance before the form gets generated 
     return super(InviteAdmin, self).get_form(request, obj=obj, **kwargs) 

    def formfield_for_manytomany(self, db_field, request=None, **kwargs): 
     if db_field.name == 'role' and self.instance: 
      # restrict role queryset to those related to this instance:   
      kwargs['queryset'] = self.instance.event.roles.all() 
     return super(InviteAdmin, self).formfield_for_manytomany(
      db_field, request=request, **kwargs) 

Django documentation for formfield_for_manytomany

+2

Câu hỏi rõ ràng nói "làm thế nào tôi chỉ có thể hiển thị các vai trò liên kết với sự kiện tôi đã ** được chọn ** trong biểu mẫu thay đổi ** **" Điều đó chắc chắn sẽ được thực hiện động (ajax). Giải pháp của bạn là tĩnh. – Pannu

+0

Ah, tôi nhớ chi tiết đó, cảm ơn. Tôi sẽ không nhất thiết phải gọi đây là giải pháp * tĩnh * vì nó thay đổi dựa trên đối tượng được tải và sự kiện được chọn trong cơ sở dữ liệu, nhưng tôi nghĩ bạn đúng không giải quyết được vấn đề * thực sự * đang được trình bày :) – DrMeers

1

Tôi tin rằng có hai cách giải quyết này: Phương pháp

  1. ajax như mô tả của @Pannu

  2. phương pháp không phải là ajax có thể đạt được d bằng cách di chuyển event trường bên ngoài biểu mẫu thay đổi (có nghĩa là sẽ có một biểu mẫu khác để thay đổi event) và lọc roles dựa trên số event hiện tại. Tôi đã phải giải quyết vấn đề tương tự gần đây với hạn chế các tùy chọn có sẵn dựa trên thuộc về một đối tượng đến trang web cụ thể. Dưới đây là mô tả và mã, nếu bạn quan tâm: http://source.mihelac.org/2011/09/8/django-sites-ext/

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