9

我正在django-nonrelappengine 上进行试验并尝试使用 adjangotoolbox.fields.ListField来实现多对多关系。正如我在文档中所读到的ListField,您可以使用它来解决 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

好的,这就是我为使这一切正常工作所做的工作......我将从头开始

这就是我的模型的样子

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

这些类允许在管理员中使用列表字段。然后我创建了一个在管理站点中使用的表单

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 关系所做的工作:

假设您在 2 个类之间有 M2M 关系,分别是 SomeClass 和 AnotherClass。您想在 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

这可能是无关的,但对于管理界面,请确保您在设置中的 django.contrib.admin 之后列出了 djangotoolbox .. INSTALLED_APPS

于 2011-06-10T15:55:14.437 回答
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 回答