9

私はappengineで実験しており、多対多の関係を実装するためdjango-nonrelにを使用しようとしています。djangotoolbox.fields.ListFieldドキュメントを読んだように、aListFieldは、多対多の関係をサポートしていないdjamgo-nonrelの回避策を作成するために使用できるものです。

これは私のモデルからの抜粋です:

class MyClass(models.Model):
    field = ListField(models.ForeignKey(AnotherClass))

したがって、これが正しく行われている場合は、別のクラスの複数のインスタンスとの関係を示すために、別のクラスへの外部キーのリストを作成しています。

このアプローチでは、すべてが正常に機能します...例外はありません。コードとビューで`MyClass'オブジェクトを作成できます。しかし、管理インターフェースを使用しようとすると、次のエラーが発生します

No form field implemented for <class 'djangotoolbox.fields.ListField'>

だから私は今までやったことのないことをやってみようと思います。自分のフィールドを作成します。MyClass実は、管理インターフェースでインスタンスを編集するための私自身のフォームです。これが私がしたことです:

class MyClassForm(ModelForm):
    field = fields.MultipleChoiceField(choices=AnotherClass.objects.all(), widget=FilteredSelectMultiple("verbose_name", is_stacked=False))
    class Meta:
        model = MyClass

MyClassForm次に、使用するフォームとして管理インターフェースに渡します

class MyClassAdmin(admin.ModelAdmin):
    form = MyClassForm

admin.site.register(MyClass, MyClassAdmin)

私はこれでうまくいくと思いますが、そうではありません。管理インターフェースに移動すると、以前と同じエラーが発生します。誰かが私がここで間違っていることを教えてもらえますか...または、管理インターフェースで、、などを使用する他の提案やサクセスストーリーがあれば、ListFieldそれSetFielddjangotoolbox.fields非常にありがたいです。

4

4 に答える 4

11

OK、これが私がこれをすべて機能させるためにしたことです...最初から始めます

これは私のモデルがどのように見えたかです

class MyClass(models.Model):
    field = ListField(models.ForeignKey(AnotherClass))

管理インターフェイスを使用して、リスト フィールドの複数選択ウィジェットを使用して、このモデルのインスタンスを作成/編集できるようにしたいと考えていました。したがって、次のようにいくつかのカスタムクラスを作成しました

class ModelListField(ListField):
    def formfield(self, **kwargs):
        return FormListField(**kwargs)

class ListFieldWidget(SelectMultiple):
    pass

class FormListField(MultipleChoiceField):
    """
    This is a custom form field that can display a ModelListField as a Multiple Select GUI element.
    """
    widget = ListFieldWidget

    def clean(self, value):
        #TODO: clean your data in whatever way is correct in your case and return cleaned data instead of just the value
        return value

これらのクラスにより、リストフィールドを admin で使用できるようになります。次に、管理サイトで使用するフォームを作成しました

class MyClassForm(ModelForm):
    def __init__(self, *args, **kwargs):
        super(MyClasstForm,self).__init__(*args, **kwargs)
        self.fields['field'].widget.choices = [(i.pk, i) for i in AnotherClass.objects.all()]
        if self.instance.pk:
            self.fields['field'].initial = self.instance.field

    class Meta:
        model = MyClass

これを行った後、管理モデルを作成し、管理サイトに登録しました

class MyClassAdmin(admin.ModelAdmin):
    form = MyClassForm

    def __init__(self, model, admin_site):
        super(MyClassAdmin,self).__init__(model, admin_site)

admin.site.register(MyClass, MyClassAdmin)

これは現在、私のコードで機能しています。このアプローチは google_appengine にはまったく適していない可能性があることに注意してください。私はそれがどのように機能するかについてあまり熟達しておらず、非効率的なクエリを作成する可能性があるためです。

于 2011-07-05T21:56:52.577 に答える
3

私が理解している限り、あなたは django-nonrel で M2M 関係を構築しようとしていますが、これはすぐに使用できる機能ではありません。手始めに、簡単なハックが必要な場合は、この単純なクラスを使用して、 aCharFieldを使用して外部キーを手動で入力できます。

class ListFormField(forms.Field):
    """ A form field for being able to display a djangotoolbox.fields.ListField. """

    widget = ListWidget

    def clean(self, value):
        return [v.strip() for v in value.split(',') if len(v.strip()) > 0]

しかし、通常、モデルのリストから複数選択したい場合は、ModelMultipleChoiceField を使用する必要がありますが、これも django-nonrel では機能しません。MultipleSelectField を使用して M2M 関係をエミュレートするために行ったことは次のとおりです。

SomeClass と AnotherClass という 2 つのクラスの間に M2M 関係があるとします。SomeClass のフォームでリレーションシップを選択します。また、参照を SomeClass の ListField として保持したいと考えています。(当然、ここで説明されているように M2M 関係を作成して、App Engine で作業している場合にインデックスの爆発を防ぐ必要があります)。

したがって、次のようなモデルがあります。

class SomeClass(models.Model):
    another_class_ids = ListField(models.PositiveIntegerField(), null=True, blank=True)
    #fields go here

class AnotherClass(models.Model):
    #fields go here

そしてあなたの形で:

class SomeClassForm(forms.ModelForm):

    #Empty field, will be populated after form is initialized
    #Otherwise selection list is not refreshed after new entities are created.
    another_class = forms.MultipleChoiceField(required=False)

def __init__(self, *args, **kwargs):
    super(SomeClassForm,self).__init__(*args, **kwargs)
    self.fields['another_class'].choices = [(item.pk,item) for item in AnotherClass.objects.all()]

    if self.instance.pk: #If class is saved, highlight the instances that are related
        self.fields['another_class'].initial = self.instance.another_class_ids

def save(self, *args, **kwargs):  
    self.instance.another_class_ids = self.cleaned_data['another_class']         
    return super(SomeClassForm, self).save()

class Meta:
    model = SomeClass

この機能を通常のフォームに実装しましたが、管理パネル用に調整するのはそれほど難しくありません。

于 2011-06-10T20:34:32.817 に答える
0

モデルオブジェクトを問い合わせることで、そのような使用法のためのカスタムフォームクラスを避けることができます

class ModelListField(ListField):
  def __init__(self, embedded_model=None, *args, **kwargs):
  super(ModelListField, self).__init__(*args, **kwargs)
  self._model = embedded_model.embedded_model

  def formfield(self, **kwargs):
    return FormListField(model=self._model, **kwargs)

class ListFieldWidget(SelectMultiple):
  pass

class FormListField(MultipleChoiceField):
  widget = ListFieldWidget

  def __init__(self, model=None, *args, **kwargs):
    self._model = model
    super(FormListField, self).__init__(*args, **kwargs)
    self.widget.choices = [(unicode(i.pk), i) for i in self._model.objects.all()]

  def to_python(self, value):
    return [self._model.objects.get(pk=key) for key in value]

  def clean(self, value):
    return value
于 2013-07-13T10:00:57.267 に答える
0

これは無関係かもしれませんが、管理インターフェースの場合、設定で django.contrib.admin の後に djangotoolbox がリストされていることを確認してください.. INSTALLED_APPS

于 2011-06-10T15:55:14.437 に答える