ListField 的 Django 非相关表单字段

发布于 2024-11-14 12:27:42 字数 1204 浏览 3 评论 0原文

我正在 appengine 上试验 django-nonrel 并尝试使用 djangotoolbox.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)

我认为这可以工作,但事实并非如此。当我进入管理界面时,我收到与以前相同的错误。任何人都可以告诉我在这里做错了什么...或者如果您有使用 djangotoolbox 中的 ListFieldSetField 等的任何其他建议或成功案例.fields 在管理界面中,我们将非常感激。

I'm experimenting with django-nonrel on appengine and trying to use a djangotoolbox.fields.ListField to implement a many-to-many relation. As I read in the documentation a ListField is something that you can use to make a workaround for djamgo-nonrel not supporting many-to-many relations.

This is an excerpt from my model:

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

So if I am getting this right I am creating a list of foreign keys to another class to show a relationship with multiple instances of another class

With this approach everything works fine ... No Exceptions. I can create `MyClass' objects in code and views. But when I try to use the admin interface I get the following error

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

So I though I would try something that I haven't done before. Create my own field. Well actually my own form for editing MyClass instances in the admin interface. Here is what I did:

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

then I pass MyClassForm as the form to use to the admin interface

class MyClassAdmin(admin.ModelAdmin):
    form = MyClassForm

admin.site.register(MyClass, MyClassAdmin)

I though that this would work but It doesn't. When I go to the admin interface I get the same error as before. Can anyone tell what I am doing wrong here ... or if you have any other suggestions or success stories of using the ListField, SetField, etc. from djangotoolbox.fields in the admin interface it would be very much appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

久伴你 2024-11-21 12:27:42

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

这就是我的模型的样子,

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,因为我不太熟悉它的工作原理,并且可能会产生低效的查询等。

OK, here is what I did to get this all working ...
I'll start from the beginning

This is what what my model looked like

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

I wanted to be able to use the admin interface to create/edit instances of this model using a multiple select widget for the list field. Therefore, I created some custom classes as follows

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

These classes allow the listfield to be used in the admin. Then I created a form to use in the admin site

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

After having done this I created a admin model and registered it with the admin site

class MyClassAdmin(admin.ModelAdmin):
    form = MyClassForm

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

admin.site.register(MyClass, MyClassAdmin)

This is now working in my code. Keep in mind that this approach might not at all be well suited for google_appengine as I am not very adept at how it works and it might create inefficient queries an such.

梦开始←不甜 2024-11-21 12:27:42

据我了解,您正在尝试在 django-nonrel 中建立 M2M 关系,这不是开箱即用的功能。对于初学者来说,如果您想要快速破解,您可以使用这个简单的类并使用 CharField 手动输入外键:

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 个类(分别为 SomeClass 和 AnotherClass)之间有 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

希望这能让你开始,我为普通表单实现了此功能,为管理面板调整它应该不那么难。

As far as I understand, you're trying to have a M2M relationship in django-nonrel, which is not an out-of-the-box functionality. For starters, if you want a quick hack, you can go with this simple class and use a CharField to enter foreign keys manually:

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]

But if you want to have a multiple selection from a list of models normally you'd have to use ModelMultipleChoiceField, which is also not functional in django-nonrel. Here's what I've done to emulate a M2M relationship using a MultipleSelectField:

Let's say you have a M2M relationship between 2 classes, SomeClass and AnotherClass respectively. You want to select the relationship on the form for SomeClass. Also I assume you want to hold the references as a ListField in SomeClass. (Naturally you want to create M2M relationships as they're explained here, to prevent exploding indexes if you're working on App Engine).

So you have your models like:

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

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

And in your form:

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

Hopefully this should get you going for the start, I implemented this functionality for normal forms, adjust it for admin panel shouldn't be that hard.

红尘作伴 2024-11-21 12:27:42

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

This could be unrelated but for the admin interface, be sure you have djangotoolbox listed after django.contrib.admin in the settings.. INSTALLED_APPS

挽手叙旧 2024-11-21 12:27:42

您可以通过查询模型对象来避免使用自定义表单类

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

You could avoid a custom form class for such usage by inquiring for the model object

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文