2012-07-25 32 views
18

Tôi có một trường mô hình Django mà tôi muốn nội tuyến. Lĩnh vực này là mối quan hệ nhiều-nhiều. Vì vậy, có "Dự án" và "Hồ sơ người dùng". Mỗi hồ sơ người dùng có thể chọn bất kỳ số lượng dự án nào.Giao diện quản trị Django: sử dụng horizontal_filter với trường nội tuyến ManyToMany

Hiện tại, tôi đã có chế độ xem nội tuyến "dạng bảng". Có cách nào để có một "bộ lọc ngang" để tôi có thể dễ dàng thêm và loại bỏ các dự án từ một hồ sơ người dùng?

Vui lòng xem ảnh đính kèm để biết ví dụ. enter image description here

Dưới đây là đoạn code mẫu cho các thành viên:

class UserProfile(models.Model): 
    user = models.OneToOneField(User, unique=True) 
    projects = models.ManyToManyField(Project, blank=True, help_text="Select the projects that this user is currently working on.") 

Và mã mô hình cho một dự án:

class Project(models.Model): 
    name = models.CharField(max_length=100, unique=True) 
    application_identifier = models.CharField(max_length=100) 
    type = models.IntegerField(choices=ProjectType) 
    account = models.ForeignKey(Account) 
    principle_investigator = models.ForeignKey(User) 
    active = models.BooleanField() 

Và mã quản trị cho quan điểm:

class UserProfileInline(admin.TabularInline): 
    model = UserProfile.projects.through 
    extra = 0 
    verbose_name = 'user' 
    verbose_name_plural = 'users' 

class ProjectAdmin(admin.ModelAdmin): 
    list_display = ('name', 'application_identifier', 'type', 'account', 'active') 
    search_fields = ('name', 'application_identifier', 'account__name') 
    list_filter = ('type', 'active') 
    inlines = [UserProfileInline,] 
admin.site.register(Project, ProjectAdmin) 

Trả lời

35

Vấn đề không phải là từ việc inline; nó theo cách của công việc ModelForm, nói chung. Chúng chỉ xây dựng các trường biểu mẫu cho các trường thực tế trên mô hình, chứ không phải các thuộc tính của người quản lý liên quan. Tuy nhiên, bạn có thể thêm chức năng này vào biểu mẫu:

from django.contrib.admin.widgets import FilteredSelectMultiple 

class ProjectAdminForm(forms.ModelForm): 
    class Meta: 
     model = Project 

    userprofiles = forms.ModelMultipleChoiceField(
     queryset=UserProfile.objects.all(), 
     required=False, 
     widget=FilteredSelectMultiple(
      verbose_name='User Profiles', 
      is_stacked=False 
     ) 
    ) 

    def __init__(self, *args, **kwargs): 
     super(ProjectAdminForm, self).__init__(*args, **kwargs) 
      if self.instance.pk: 
       self.fields['userprofiles'].initial = self.instance.userprofile_set.all() 

    def save(self, commit=True): 
     project = super(ProjectAdminForm, self).save(commit=False) 
     if commit: 
      project.save() 

     if project.pk: 
      project.userprofile_set = self.cleaned_data['userprofiles'] 
      self.save_m2m() 

     return project 

class ProjectAdmin(admin.ModelAdmin): 
    form = ProjectAdminForm 
    ... 

Một chút hướng dẫn có thể là theo thứ tự. Trước tiên, chúng tôi xác định trường biểu mẫu userprofiles. Nó sẽ sử dụng một ModelMultipleChoiceField, theo mặc định sẽ dẫn đến một hộp chọn nhiều. Vì đây không phải là trường thực tế trên mô hình, chúng tôi không thể thêm trường vào filter_horizontal, vì vậy, thay vào đó, hãy sử dụng cùng một tiện ích, FilteredSelectMultiple, mà nó sẽ sử dụng nếu được liệt kê trong filter_horizontal. Chúng tôi ban đầu thiết lập queryset như toàn bộ UserProfile thiết lập, bạn không thể lọc nó ở đây, nhưng, bởi vì ở giai đoạn này của định nghĩa lớp, biểu mẫu chưa được khởi tạo và do đó không có nó là instance bộ chưa. Do đó, chúng tôi ghi đè __init__ để chúng tôi có thể đặt bộ truy vấn được lọc làm giá trị ban đầu của trường.

Cuối cùng, chúng tôi ghi đè phương thức save để chúng tôi có thể đặt nội dung của người quản lý có liên quan giống như nội dung trong dữ liệu POST của biểu mẫu và bạn đã hoàn tất.

+0

Cảm ơn rất nhiều Chris! Điều này làm việc như một say mê lần đầu tiên tôi đã thử nó! –

+0

Cảm ơn, bạn là người đàn ông. – whooot

+0

Giải pháp tuyệt vời, làm việc tuyệt vời cho tôi. – Blackeagle52

1

Một bổ sung nhỏ khi giao dịch với nhiều mối quan hệ với chính nó. Người ta có thể muốn loại trừ chính nó khỏi các lựa chọn:

if self.instance.pk: 
     self.fields['field_being_added'].queryset = self.fields['field_being_added'].queryset.exclude(pk=self.instance.pk) 
     self.fields['field_being_added'].initial = """Corresponding result queryset""" 
Các vấn đề liên quan