Django: добавление кнопки "Добавить новую" для ForeignKey в ModelForm
TL; DR. Как добавить кнопку "Добавить новую" для ForeignKey в ModelForm?
Длинная версия:
Я использую Django 1.7 для проекта. У меня есть две модели в моих моделях .py
class Client(models.Model):
name = models.CharField(max_length=100)
class Order(models.Model):
code = models.IntegerField()
client = models.ForeignKey(Client)
[некоторые другие не соответствующие поля опущены]
Я использую ModelForm для заполнения db новыми порядками, например:
class OrderNewForm(forms.ModelForm):
class Meta:
model = Order
Django неплохо работает над добавлением выпадающего меню для поля клиента, заполняя его записями, взятыми из Client. Тем не менее, я хотел бы добавить ссылку "Добавить новый клиент" /кнопку/что угодно, чтобы добавить нового клиента одновременно с добавлением соответствующего заказа.
Django admin делает это автоматически, добавляя кнопку "+", которая открывает всплывающее окно, но я не мог найти простой способ сделать это в ModelForm, как выше. Я прочитал много вопросов здесь и ссылки в другом месте, но ничего не помогло мне. Есть идея об этом?
Ответы
Ответ 1
Я решил его в пользовательском виджетах. Я не помню, принимал ли я части от администратора Django, или я построил с нуля.
Таким образом, форма будет:
class OrderNewForm(forms.ModelForm):
client = forms.ModelChoiceField(
required=False,
queryset=Client.objects.all(),
widget=RelatedFieldWidgetCanAdd(Client, related_url="so_client_add")
)
class Meta:
model = Order
fields = ('code', 'client')
И виджет, который отображает кнопку "+" и ссылается на всплывающее окно добавления в интерфейсе администратора или на пользовательский вид, который вы предоставляете с аргументом related_url, это:
from django.core.urlresolvers import reverse
from django.utils.safestring import mark_safe
from django.forms import widgets
from django.conf import settings
class RelatedFieldWidgetCanAdd(widgets.Select):
def __init__(self, related_model, related_url=None, *args, **kw):
super(RelatedFieldWidgetCanAdd, self).__init__(*args, **kw)
if not related_url:
rel_to = related_model
info = (rel_to._meta.app_label, rel_to._meta.object_name.lower())
related_url = 'admin:%s_%s_add' % info
# Be careful that here "reverse" is not allowed
self.related_url = related_url
def render(self, name, value, *args, **kwargs):
self.related_url = reverse(self.related_url)
output = [super(RelatedFieldWidgetCanAdd, self).render(name, value, *args, **kwargs)]
output.append(u'<a href="%s" class="add-another" id="add_id_%s" onclick="return showAddAnotherPopup(this);"> ' % \
(self.related_url, name))
output.append(u'<img src="%sadmin/img/icon_addlink.gif" width="10" height="10" alt="%s"/></a>' % (settings.STATIC_URL, _('Add Another')))
return mark_safe(u''.join(output))
Ответ 2
для python3:
class RelatedFieldWidgetCanAdd(widgets.Select):
def __init__(self, related_model, related_url=None, *args, **kw):
super(RelatedFieldWidgetCanAdd, self).__init__(*args, **kw)
if not related_url:
rel_to = related_model
info = (rel_to._meta.app_label, rel_to._meta.object_name.lower())
related_url = 'admin:%s_%s_add' % info
# Be careful that here "reverse" is not allowed
self.related_url = related_url
def render(self, name, value, *args, **kwargs):
self.related_url = reverse(self.related_url)
output = [super(RelatedFieldWidgetCanAdd, self).render(name, value, *args, **kwargs)]
output.append('<a href="%s" class="add-another" id="add_id_%s" onclick="return showAddAnotherPopup(this);"> ' % \
(self.related_url, name))
output.append('<img src="%sadmin/img/icon_addlink.gif" width="10" height="10" alt="%s"/></a>' % (settings.STATIC_URL, 'Add Another'))
return mark_safe(''.join(output))
Ответ 3
И чтобы добавить к функции RelatedFieldWidgetCanAdd, чтобы напрямую добавить новое значение в поле, добавьте "? _to_field = id & _popup = 1" в url...
таким образом, в python3 (благодаря Кириллу):
class RelatedFieldWidgetCanAdd(widgets.Select):
def __init__(self, related_model, related_url=None, *args, **kw):
super(RelatedFieldWidgetCanAdd, self).__init__(*args, **kw)
if not related_url:
rel_to = related_model
info = (rel_to._meta.app_label, rel_to._meta.object_name.lower())
related_url = 'admin:%s_%s_add' % info
# Be careful that here "reverse" is not allowed
self.related_url = related_url
def render(self, name, value, *args, **kwargs):
self.related_url = reverse(self.related_url)
output = [super(RelatedFieldWidgetCanAdd, self).render(name, value, *args, **kwargs)]
output.append('<a href="%s?_to_field=id&_popup=1" class="add-another" id="add_id_%s" onclick="return showAddAnotherPopup(this);"> ' % \
(self.related_url, name))
output.append('<img src="%sadmin/img/icon_addlink.gif" width="10" height="10" alt="%s"/></a>' % (settings.STATIC_URL, 'Add Another'))
return mark_safe(''.join(output))