2012-07-25 10 views
18

私はインラインにしたいDjangoモデルフィールドを持っています。フィールドは多対多の関係です。したがって、「プロジェクト」と「ユーザープロファイル」があります。各ユーザープロファイルは、任意の数のプロジェクトを選択できます。Django管理インターフェース:インラインManyToManyフィールドでhorizo​​ntal_filterを使用

現在、「表形式」のインラインビューが機能しています。ユーザープロファイルからプロジェクトを簡単に追加したり削除したりできるように、「水平フィルタ」を使用する方法はありますか?

例については添付の図を参照してください。 enter image description here

は、ここでユーザープロファイルのためのモデルコードです:

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.") 

とプロジェクトのためのモデルコード:

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() 

とビューのための管理コード:

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) 

答えて

35

問題はインラインではありません。それは一般的に方法ModelFormの仕事からです。モデルの実際のフィールドのフォームフィールドのみを作成し、関連するマネージャー属性は作成しません。ただし、この機能をフォームに追加することもできます。

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 
    ... 

おそらく少し歩いているだけです。まず、userprofilesフォームフィールドを定義します。 ModelMultipleChoiceFieldを使用します。デフォルトでは複数の選択ボックスが表示されます。これはモデルの実際のフィールドではないので、単にfilter_horizontalに追加するだけではないので、filter_horizontalにリストされている場合に使用する同じウィジェットFilteredSelectMultipleを単に使用するように指示します。

最初にクエリーセット全体をUserProfileに設定しましたが、クラス定義のこの段階でフォームがインスタンス化されておらず、したがってinstanceが設定されていないため、フィルタリングできませんまだ。その結果、フィルターされたクエリーセットをフィールドの初期値として設定できるように、__init__をオーバーライドします。

最後に、saveメソッドをオーバーライドして、関連するマネージャーの内容をフォームのPOSTデータの内容と同じに設定できるようになりました。

+0

ありがとうございますChris!これは私が試した初めての魅力のように働いた! –

+0

ありがとう、あなたは男です。 – whooot

+0

偉大な解決策は、私のために素晴らしい仕事。 – Blackeagle52

1

多対多の関係を扱うときはマイナーな追加です。選択肢から自分自身を除外したい場合があります。

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""" 
関連する問題