Подтвердить что ты не робот

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, как выше. Я прочитал много вопросов здесь и ссылки в другом месте, но ничего не помогло мне. Есть идея об этом?

4b9b3361

Ответ 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))