Django-поле формы nonrel для ListField
я экспериментирую с django-nonrel
на appengine и пытается использовать djangotoolbox.fields.ListField
для реализации отношения "многие ко многим". Как я читал в документации a ListField
это то, что вы можете использовать, чтобы сделать обходной путь для djamgo-nonrel, не поддерживая отношения "многие ко многим".
это выдержка из моей модели:
class MyClass(models.Model):
field = ListField(models.ForeignKey(AnotherClass))
поэтому, если я получаю это право, я создаю список внешних ключей к другому классу, чтобы показать связь с несколькими экземплярами другого класс!--13-->
при таком подходе все работает нормально ... ни одно исключение. Я могу создавать объекты MyClass в коде и представлениях. Но когда я пытаюсь использовать интерфейс администратора, я получаю следующую ошибку
No form field implemented for <class 'djangotoolbox.fields.ListField'>
поэтому я подумал, что попробую что-то, чего раньше не делал. Создайте свое собственное поле. Ну на самом деле моя собственная форма для редактирования MyClass
экземпляры в интерфейсе администратора. Вот что я сделал:--13-->
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
, SetField
, etc. от djangotoolbox.fields
в интерфейсе администратора это было бы очень признательно.
4 ответов
хорошо, вот что я сделал, чтобы все это работало ... Я начну с самого начала!--5-->
вот как выглядела моя модель
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
эти классы позволяют использовать listfield в admin. Затем я создал форму для использования в 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, поскольку я не очень разбираюсь в том, как он работает, и он может создавать неэффективные запросы.
насколько я понимаю, вы пытаетесь иметь отношения M2M в django-nonrel, что не является нестандартной функциональностью. Для начала, если вы хотите быстро взломать, вы можете пойти с этим простым классом и использовать 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. Вот что я сделал, чтобы подражать M2M отношение с использованием MultipleSelectField:
предположим, у вас есть отношение M2M между 2 классами, SomeClass и AnotherClass соответственно. Вы хотите выбрать отношение в форме для SomeClass. Также я предполагаю, что вы хотите сохранить ссылки как ListField в SomeClass. (Естественно, вы хотите создать отношения 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
надеюсь, это должно заставить вас начать, я реализовал эту функциональность для обычных форм, настроить ее для панели администратора не должно быть так сложно.
Это может быть не связано, но для интерфейса администратора убедитесь, что у вас есть djangotoolbox, указанный после django.ВНО.администратор в настройках.. INSTALLED_APPS
вы можете избежать пользовательского класса формы для такого использования, запросив объект модели
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