web-dev-qa-db-ja.com

Django AdminのManyToManyボックスをフィルタリングします

別のオブジェクトと多対多の関係を持つオブジェクトがあります。
Django Adminでは、これにより複数選択ボックスに非常に長いリストが表示されます。

ManyToManyリレーションをフィルター処理して、顧客が選択した市で利用可能なカテゴリのみを取得したいのですが。

これは可能ですか?そのためのウィジェットを作成する必要がありますか?そして、もしそうなら-filter_horizo​​ntal関数も欲しいので、標準のManyToManyフィールドからビヘイビアーをどのようにコピーしますか?.

これらは私の簡単なモデルです:

class City(models.Model):
    name = models.CharField(max_length=200)


class Category(models.Model):
    name = models.CharField(max_length=200)
    available_in = models.ManyToManyField(City)


class Customer(models.Model):
    name = models.CharField(max_length=200)
    city = models.ForeignKey(City)
    categories = models.ManyToManyField(Category)
34
schmilblick

OK、これは上記のクラスを使用した私のソリューションです。正しくフィルタリングするためにさらに多くのフィルターを追加しましたが、ここでコードを読みやすくしたいと思いました。

これはまさに私が探していたものであり、私はここに私の解決策を見つけました: http://www.slideshare.net/lincolnloop/customizing-the-Django-admin#stats-bottom (スライド50)

以下を私のadmin.pyに追加してください:

class CustomerForm(forms.ModelForm): 
    def __init__(self, *args, **kwargs):
        super(CustomerForm, self).__init__(*args, **kwargs)
        wtf = Category.objects.filter(pk=self.instance.cat_id);
        w = self.fields['categories'].widget
        choices = []
        for choice in wtf:
            choices.append((choice.id, choice.name))
        w.choices = choices


class CustomerAdmin(admin.ModelAdmin):
    list_per_page = 100
    ordering = ['submit_date',] # didnt have this one in the example, sorry
    search_fields = ['name', 'city',]
    filter_horizontal = ('categories',)
    form = CustomerForm

これにより、機能を削除せずに「カテゴリ」リストがフィルタリングされます。 (つまり:私はまだ最愛のfilter_horizo​​ntalを持つことができます:))

ModelFormsは非常に強力ですが、ドキュメントや本ではこれ以上取り上げられていないことに少し驚いています。

37
schmilblick

私が理解できる限り、基本的には、いくつかの基準(市別のカテゴリー)に従って表示された選択肢をフィルター処理したいということです。

limit_choices_tomodels.ManyToManyField属性を使用することで、正確にそれを行うことができます。したがって、モデル定義を次のように変更します...

class Customer(models.Model):
    name = models.CharField(max_length=200)
    city = models.ForeignKey(City)
    categories = models.ManyToManyField(Category, limit_choices_to = {'available_in': cityId})

limit_choices_toは、まさにこの目的で使用できるため、これは機能するはずです。

ただし、limit_choices_toは、カスタムの中間テーブルを持つManyToManyFieldで使用しても効果がありません。お役に立てれば。

15
simplyharsh

別の方法は、formfield_for_manytomany in Django管理者。

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

「車」がManyToManyフィールドであることを考えると。

詳細は this link を確認してください。

これはあなたが探しているものだと思います:

http://blog.philippmetzler.com/?p=52

django-smart-selectsを使用します。

http://github.com/digi604/Django-smart-selects

フィリップ

2
Googol

同じフォームで顧客の都市とカテゴリを選択しているので、選択した都市で利用可能なカテゴリのみにカテゴリセレクターを動的に調整するためのJavaScriptが必要になります。

1
Ryan Fugger

Ryanが言うように、ユーザーが選択した内容に基づいてオプションを動的に変更するには、JavaScriptが必要です。投稿されたソリューションは、都市が保存され、管理フォームが再ロードされた場合に機能します。つまり、フィルターが機能したときに、ユーザーがオブジェクトを編集して都市のドロップダウンを変更したが、カテゴリーのオプションが更新されない状況を考えてください。

0
Sharan666