标签归档:django-forms

创建动态选择字段

问题:创建动态选择字段

我在尝试了解如何在Django中创建动态选择字段时遇到了一些麻烦。我有一个模型设置类似:

class rider(models.Model):
     user = models.ForeignKey(User)
     waypoint = models.ManyToManyField(Waypoint)

class Waypoint(models.Model):
     lat = models.FloatField()
     lng = models.FloatField()

我想做的是创建一个选择字段whos的值是与该骑手相关联的航点(将是登录的人)。

目前,我以如下形式覆盖init:

class waypointForm(forms.Form):
     def __init__(self, *args, **kwargs):
          super(joinTripForm, self).__init__(*args, **kwargs)
          self.fields['waypoints'] = forms.ChoiceField(choices=[ (o.id, str(o)) for o in Waypoint.objects.all()])

但是所有要做的就是列出所有路标,它们与任何特定的骑手都没有关联。有任何想法吗?谢谢。

I’m having some trouble trying to understand how to create a dynamic choice field in django. I have a model set up something like:

class rider(models.Model):
     user = models.ForeignKey(User)
     waypoint = models.ManyToManyField(Waypoint)

class Waypoint(models.Model):
     lat = models.FloatField()
     lng = models.FloatField()

What I’m trying to do is create a choice Field whos values are the waypoints associated with that rider (which would be the person logged in).

Currently I’m overriding init in my forms like so:

class waypointForm(forms.Form):
     def __init__(self, *args, **kwargs):
          super(joinTripForm, self).__init__(*args, **kwargs)
          self.fields['waypoints'] = forms.ChoiceField(choices=[ (o.id, str(o)) for o in Waypoint.objects.all()])

But all that does is list all the waypoints, they’re not associated with any particular rider. Any ideas? Thanks.


回答 0

您可以通过将用户传递给表单init来过滤航点

class waypointForm(forms.Form):
    def __init__(self, user, *args, **kwargs):
        super(waypointForm, self).__init__(*args, **kwargs)
        self.fields['waypoints'] = forms.ChoiceField(
            choices=[(o.id, str(o)) for o in Waypoint.objects.filter(user=user)]
        )

您在启动表单时的视线通过了用户

form = waypointForm(user)

在模型形式的情况下

class waypointForm(forms.ModelForm):
    def __init__(self, user, *args, **kwargs):
        super(waypointForm, self).__init__(*args, **kwargs)
        self.fields['waypoints'] = forms.ModelChoiceField(
            queryset=Waypoint.objects.filter(user=user)
        )

    class Meta:
        model = Waypoint

you can filter the waypoints by passing the user to the form init

class waypointForm(forms.Form):
    def __init__(self, user, *args, **kwargs):
        super(waypointForm, self).__init__(*args, **kwargs)
        self.fields['waypoints'] = forms.ChoiceField(
            choices=[(o.id, str(o)) for o in Waypoint.objects.filter(user=user)]
        )

from your view while initiating the form pass the user

form = waypointForm(user)

in case of model form

class waypointForm(forms.ModelForm):
    def __init__(self, user, *args, **kwargs):
        super(waypointForm, self).__init__(*args, **kwargs)
        self.fields['waypoints'] = forms.ModelChoiceField(
            queryset=Waypoint.objects.filter(user=user)
        )

    class Meta:
        model = Waypoint

回答 1

有针对您的问题的内置解决方案:ModelChoiceField

通常,ModelForm当您需要创建/更改数据库对象时,总是值得尝试使用。在95%的情况下都有效,并且比创建自己的实现要干净得多。

There’s built-in solution for your problem: ModelChoiceField.

Generally, it’s always worth trying to use ModelForm when you need to create/change database objects. Works in 95% of the cases and it’s much cleaner than creating your own implementation.


回答 2

问题是你什么时候做

def __init__(self, user, *args, **kwargs):
    super(waypointForm, self).__init__(*args, **kwargs)
    self.fields['waypoints'] = forms.ChoiceField(choices=[ (o.id, str(o)) for o in Waypoint.objects.filter(user=user)])

在更新请求中,先前的值将丢失!

the problem is when you do

def __init__(self, user, *args, **kwargs):
    super(waypointForm, self).__init__(*args, **kwargs)
    self.fields['waypoints'] = forms.ChoiceField(choices=[ (o.id, str(o)) for o in Waypoint.objects.filter(user=user)])

in a update request, the previous value will lost!


回答 3

在初始化骑乘者实例时将其传递给表单怎么样?

class WaypointForm(forms.Form):
    def __init__(self, rider, *args, **kwargs):
      super(joinTripForm, self).__init__(*args, **kwargs)
      qs = rider.Waypoint_set.all()
      self.fields['waypoints'] = forms.ChoiceField(choices=[(o.id, str(o)) for o in qs])

# In view:
rider = request.user
form = WaypointForm(rider) 

How about passing the rider instance to the form while initializing it?

class WaypointForm(forms.Form):
    def __init__(self, rider, *args, **kwargs):
      super(joinTripForm, self).__init__(*args, **kwargs)
      qs = rider.Waypoint_set.all()
      self.fields['waypoints'] = forms.ChoiceField(choices=[(o.id, str(o)) for o in qs])

# In view:
rider = request.user
form = WaypointForm(rider) 

回答 4

在正常选择字段下的工作解决方案下。我的问题是,每个用户都基于很少的条件有自己的CUSTOM选择字段选项。

class SupportForm(BaseForm):

    affiliated = ChoiceField(required=False, label='Fieldname', choices=[], widget=Select(attrs={'onchange': 'sysAdminCheck();'}))

    def __init__(self, *args, **kwargs):

        self.request = kwargs.pop('request', None)
        grid_id = get_user_from_request(self.request)
        for l in get_all_choices().filter(user=user_id):
            admin = 'y' if l in self.core else 'n'
            choice = (('%s_%s' % (l.name, admin)), ('%s' % l.name))
            self.affiliated_choices.append(choice)
        super(SupportForm, self).__init__(*args, **kwargs)
        self.fields['affiliated'].choices = self.affiliated_choice

Underneath working solution with normal choice field. my problem was that each user have their own CUSTOM choicefield options based on few conditions.

class SupportForm(BaseForm):

    affiliated = ChoiceField(required=False, label='Fieldname', choices=[], widget=Select(attrs={'onchange': 'sysAdminCheck();'}))

    def __init__(self, *args, **kwargs):

        self.request = kwargs.pop('request', None)
        grid_id = get_user_from_request(self.request)
        for l in get_all_choices().filter(user=user_id):
            admin = 'y' if l in self.core else 'n'
            choice = (('%s_%s' % (l.name, admin)), ('%s' % l.name))
            self.affiliated_choices.append(choice)
        super(SupportForm, self).__init__(*args, **kwargs)
        self.fields['affiliated'].choices = self.affiliated_choice

回答 5

正如Breedly和Liang指出的那样,Ashok的解决方案将阻止您在发布表单时获取选择值。

一种稍微不同但仍然不完善的解决方法是:

class waypointForm(forms.Form):
    def __init__(self, user, *args, **kwargs):
        self.base_fields['waypoints'].choices = self._do_the_choicy_thing()
        super(waypointForm, self).__init__(*args, **kwargs)

但是,这可能会导致一些并发问题。

As pointed by Breedly and Liang, Ashok’s solution will prevent you from getting the select value when posting the form.

One slightly different, but still imperfect, way to solve that would be:

class waypointForm(forms.Form):
    def __init__(self, user, *args, **kwargs):
        self.base_fields['waypoints'].choices = self._do_the_choicy_thing()
        super(waypointForm, self).__init__(*args, **kwargs)

This could cause some concurrence problems, though.


回答 6

您可以将字段声明为表单的一流属性,并且可以动态设置选项:

class WaypointForm(forms.Form):
    waypoints = forms.ChoiceField(choices=[])

    def __init__(self, user, *args, **kwargs):
        super().__init__(*args, **kwargs)
        waypoint_choices = [(o.id, str(o)) for o in Waypoint.objects.filter(user=user)]
        self.fields['waypoints'].choices = waypoint_choices

您也可以使用ModelChoiceField并以类似方式在init上设置queryset。

You can declare the field as a first-class attribute of your form and just set choices dynamically:

class WaypointForm(forms.Form):
    waypoints = forms.ChoiceField(choices=[])

    def __init__(self, user, *args, **kwargs):
        super().__init__(*args, **kwargs)
        waypoint_choices = [(o.id, str(o)) for o in Waypoint.objects.filter(user=user)]
        self.fields['waypoints'].choices = waypoint_choices

You can also use a ModelChoiceField and set the queryset on init in a similar manner.


回答 7

如果您需要django admin中的动态选择字段;这适用于Django> = 2.1。

class CarAdminForm(forms.ModelForm):
    class Meta:
        model = Car

    def __init__(self, *args, **kwargs):
        super(CarForm, self).__init__(*args, **kwargs)

        # Now you can make it dynamic.
        choices = (
            ('audi', 'Audi'),
            ('tesla', 'Tesla')
        )

        self.fields.get('car_field').choices = choices

    car_field = forms.ChoiceField(choices=[])

@admin.register(Car)
class CarAdmin(admin.ModelAdmin):
    form = CarAdminForm

希望这可以帮助。

If you need a dynamic choice field in django admin; This works for django >=2.1.

class CarAdminForm(forms.ModelForm):
    class Meta:
        model = Car

    def __init__(self, *args, **kwargs):
        super(CarForm, self).__init__(*args, **kwargs)

        # Now you can make it dynamic.
        choices = (
            ('audi', 'Audi'),
            ('tesla', 'Tesla')
        )

        self.fields.get('car_field').choices = choices

    car_field = forms.ChoiceField(choices=[])

@admin.register(Car)
class CarAdmin(admin.ModelAdmin):
    form = CarAdminForm

Hope this helps.


将Django表单字段更改为隐藏字段

问题:将Django表单字段更改为隐藏字段

我有一个带的Django表单,与RegexField正常的文本输入字段非常相似。

我认为,在某些情况下,我想对用户隐藏它,并尝试使表单尽可能相似。将这个领域变成一个HiddenInput领域的最好方法是什么?

我知道我可以使用以下方法在字段上设置属性:

form['fieldname'].field.widget.attr['readonly'] = 'readonly'

我可以通过以下方式设置所需的初始值:

form.initial['fieldname'] = 'mydesiredvalue'

但是,这不会更改小部件的形式。

什么是使此字段成为<input type="hidden">字段的最佳/最“ django-y” /最不“ hacky”的方法?

I have a Django form with a RegexField, which is very similar to a normal text input field.

In my view, under certain conditions I want to hide it from the user, and trying to keep the form as similar as possible. What’s the best way to turn this field into a HiddenInput field?

I know I can set attributes on the field with:

form['fieldname'].field.widget.attr['readonly'] = 'readonly'

And I can set the desired initial value with:

form.initial['fieldname'] = 'mydesiredvalue'

However, that won’t change the form of the widget.

What’s the best / most “django-y” / least “hacky” way to make this field a <input type="hidden"> field?


回答 0

如果您具有自定义模板并查看,则可以排除该字段并用于{{ modelform.instance.field }}获取值。

您也可以在视图中使用:

form.fields['field_name'].widget = forms.HiddenInput()

但我不确定它是否会保护发布后的保存方法。

希望能帮助到你。

If you have a custom template and view you may exclude the field and use {{ modelform.instance.field }} to get the value.

also you may prefer to use in the view:

form.fields['field_name'].widget = forms.HiddenInput()

but I’m not sure it will protect save method on post.

Hope it helps.


回答 1

这也可能有用: {{ form.field.as_hidden }}

This may also be useful: {{ form.field.as_hidden }}


回答 2

一个对我有用的选项,将字段的原始形式定义为:

forms.CharField(widget = forms.HiddenInput(), required = False)

那么当您在新的类中覆盖它时,它将保留它的位置。

an option that worked for me, define the field in the original form as:

forms.CharField(widget = forms.HiddenInput(), required = False)

then when you override it in the new Class it will keep it’s place.


回答 3

首先,如果您不希望用户修改数据,则仅排除该字段似乎更干净。将其包含为隐藏字段只会增加更多数据以通过有线方式发送,并在您不希望恶意用户修改时邀请它们进行修改。如果确实有理由包括该字段但将其隐藏,则可以将关键字arg传递给modelform的构造函数。可能是这样的:

class MyModelForm(forms.ModelForm):
    class Meta:
        model = MyModel
    def __init__(self, *args, **kwargs):
        from django.forms.widgets import HiddenInput
        hide_condition = kwargs.pop('hide_condition',None)
        super(MyModelForm, self).__init__(*args, **kwargs)
        if hide_condition:
            self.fields['fieldname'].widget = HiddenInput()
            # or alternately:  del self.fields['fieldname']  to remove it from the form altogether.

然后在您看来:

form = MyModelForm(hide_condition=True)

在视图中,我更喜欢这种方法来修改模型形式的内部,但这只是一个问题。

Firstly, if you don’t want the user to modify the data, then it seems cleaner to simply exclude the field. Including it as a hidden field just adds more data to send over the wire and invites a malicious user to modify it when you don’t want them to. If you do have a good reason to include the field but hide it, you can pass a keyword arg to the modelform’s constructor. Something like this perhaps:

class MyModelForm(forms.ModelForm):
    class Meta:
        model = MyModel
    def __init__(self, *args, **kwargs):
        from django.forms.widgets import HiddenInput
        hide_condition = kwargs.pop('hide_condition',None)
        super(MyModelForm, self).__init__(*args, **kwargs)
        if hide_condition:
            self.fields['fieldname'].widget = HiddenInput()
            # or alternately:  del self.fields['fieldname']  to remove it from the form altogether.

Then in your view:

form = MyModelForm(hide_condition=True)

I prefer this approach to modifying the modelform’s internals in the view, but it’s a matter of taste.


回答 4

对于正常形式,您可以

class MyModelForm(forms.ModelForm):
    slug = forms.CharField(widget=forms.HiddenInput())

如果您有模型表格,则可以执行以下操作

class MyModelForm(forms.ModelForm):
    class Meta:
        model = TagStatus
        fields = ('slug', 'ext')
        widgets = {'slug': forms.HiddenInput()}

您也可以覆盖__init__方法

class Myform(forms.Form):
    def __init__(self, *args, **kwargs):
        super(Myform, self).__init__(*args, **kwargs)
        self.fields['slug'].widget = forms.HiddenInput()

For normal form you can do

class MyModelForm(forms.ModelForm):
    slug = forms.CharField(widget=forms.HiddenInput())

If you have model form you can do the following

class MyModelForm(forms.ModelForm):
    class Meta:
        model = TagStatus
        fields = ('slug', 'ext')
        widgets = {'slug': forms.HiddenInput()}

You can also override __init__ method

class Myform(forms.Form):
    def __init__(self, *args, **kwargs):
        super(Myform, self).__init__(*args, **kwargs)
        self.fields['slug'].widget = forms.HiddenInput()

回答 5

如果要始终隐藏该字段,请使用以下命令:

class MyForm(forms.Form):
    hidden_input = forms.CharField(widget=forms.HiddenInput(), initial="value")

If you want the field to always be hidden, use the following:

class MyForm(forms.Form):
    hidden_input = forms.CharField(widget=forms.HiddenInput(), initial="value")

回答 6

您可以只使用css:

#id_fieldname, label[for="id_fieldname"] {
  position: absolute;
  display: none
}

这将使该字段及其标签不可见。

You can just use css :

#id_fieldname, label[for="id_fieldname"] {
  position: absolute;
  display: none
}

This will make the field and its label invisible.


Django:使用形式在一个模板中的多个模型

问题:Django:使用形式在一个模板中的多个模型

我正在构建一个支持票证跟踪应用程序,并希望从一个页面创建一些模型。票证通过ForeignKey属于客户。注释也通过ForeignKey属于票证。我想选择一个客户(这是一个单独的项目)或创建一个新客户,然后创建一个工单,最后创建一个分配给新工单的便笺。

由于我是Django的新手,因此我倾向于反复工作,每次尝试新功能。我玩过ModelForms,但是我想隐藏一些字段并进行一些复杂的验证。似乎我正在寻找的控制级别需要表单集或手动完成所有操作,并完成一个繁琐的手工编码模板页面,而我试图避免这种情况。

我缺少一些可爱的功能吗?有人对使用表单集有很好的参考或示例吗?我花了整个周末为他们准备API文档,但我仍然一无所知。如果我分解并手工编码所有内容,这是设计问题吗?

I’m building a support ticket tracking app and have a few models I’d like to create from one page. Tickets belong to a Customer via a ForeignKey. Notes belong to Tickets via a ForeignKey as well. I’d like to have the option of selecting a Customer (that’s a whole separate project) OR creating a new Customer, then creating a Ticket and finally creating a Note assigned to the new ticket.

Since I’m fairly new to Django, I tend to work iteratively, trying out new features each time. I’ve played with ModelForms but I want to hide some of the fields and do some complex validation. It seems like the level of control I’m looking for either requires formsets or doing everything by hand, complete with a tedious, hand-coded template page, which I’m trying to avoid.

Is there some lovely feature I’m missing? Does someone have a good reference or example for using formsets? I spent a whole weekend on the API docs for them and I’m still clueless. Is it a design issue if I break down and hand-code everything?


回答 0

使用ModelForms实在不是太难。假设您有A,B和C表单。您打印出每个表单和页面,现在需要处理POST。

if request.POST():
    a_valid = formA.is_valid()
    b_valid = formB.is_valid()
    c_valid = formC.is_valid()
    # we do this since 'and' short circuits and we want to check to whole page for form errors
    if a_valid and b_valid and c_valid:
        a = formA.save()
        b = formB.save(commit=False)
        c = formC.save(commit=False)
        b.foreignkeytoA = a
        b.save()
        c.foreignkeytoB = b
        c.save()

是用于自定义验证的文档。

This really isn’t too hard to implement with ModelForms. So lets say you have Forms A, B, and C. You print out each of the forms and the page and now you need to handle the POST.

if request.POST():
    a_valid = formA.is_valid()
    b_valid = formB.is_valid()
    c_valid = formC.is_valid()
    # we do this since 'and' short circuits and we want to check to whole page for form errors
    if a_valid and b_valid and c_valid:
        a = formA.save()
        b = formB.save(commit=False)
        c = formC.save(commit=False)
        b.foreignkeytoA = a
        b.save()
        c.foreignkeytoB = b
        c.save()

Here are the docs for custom validation.


回答 1

我一天前也处于相同的情况,这是我的2美分:

1)我可以在这里找到单一形式的多个模型输入的最短,最简洁的演示:http : //collingrady.wordpress.com/2008/02/18/editing-multiple-objects-in-django-with-newforms/

简而言之:为每个模型创建一个表单<form>,使用prefixkeyarg 将它们都提交到模板中,并进行视图句柄验证。如果存在依赖关系,只需确保在依赖关系之前保存“父”模型,并在提交“子”模型的保存之前使用父代的ID作为外键。链接中有演示。

2)也许表单集可打成了这样做,但据我的钻研,表单集主要用于输入相同的模型,它的倍数可能 /模型由外键可以任意捆绑到另一种模式。但是,似乎没有默认选项可输入多个模型的数据,而这并不是表单集的含义。

I just was in about the same situation a day ago, and here are my 2 cents:

1) I found arguably the shortest and most concise demonstration of multiple model entry in single form here: http://collingrady.wordpress.com/2008/02/18/editing-multiple-objects-in-django-with-newforms/ .

In a nutshell: Make a form for each model, submit them both to template in a single <form>, using prefix keyarg and have the view handle validation. If there is dependency, just make sure you save the “parent” model before dependant, and use parent’s ID for foreign key before commiting save of “child” model. The link has the demo.

2) Maybe formsets can be beaten into doing this, but as far as I delved in, formsets are primarily for entering multiples of the same model, which may be optionally tied to another model/models by foreign keys. However, there seem to be no default option for entering more than one model’s data and that’s not what formset seems to be meant for.


回答 2

我最近遇到了一些问题,只是想出了解决方法。假设您有三个类,Primary,B,C,并且B,C具有Primary的外键

    class PrimaryForm(ModelForm):
        class Meta:
            model = Primary

    class BForm(ModelForm):
        class Meta:
            model = B
            exclude = ('primary',)

    class CForm(ModelForm):
         class Meta:
            model = C
            exclude = ('primary',)

    def generateView(request):
        if request.method == 'POST': # If the form has been submitted...
            primary_form = PrimaryForm(request.POST, prefix = "primary")
            b_form = BForm(request.POST, prefix = "b")
            c_form = CForm(request.POST, prefix = "c")
            if primary_form.is_valid() and b_form.is_valid() and c_form.is_valid(): # All validation rules pass
                    print "all validation passed"
                    primary = primary_form.save()
                    b_form.cleaned_data["primary"] = primary
                    b = b_form.save()
                    c_form.cleaned_data["primary"] = primary
                    c = c_form.save()
                    return HttpResponseRedirect("/viewer/%s/" % (primary.name))
            else:
                    print "failed"

        else:
            primary_form = PrimaryForm(prefix = "primary")
            b_form = BForm(prefix = "b")
            c_form = Form(prefix = "c")
     return render_to_response('multi_model.html', {
     'primary_form': primary_form,
     'b_form': b_form,
     'c_form': c_form,
      })

此方法应允许您执行所需的任何验证,以及在同一页面上生成所有三个对象。我还使用了JavaScript和隐藏字段来允许在同一页面上生成多个B,C对象。

I very recently had the some problem and just figured out how to do this. Assuming you have three classes, Primary, B, C and that B,C have a foreign key to primary

    class PrimaryForm(ModelForm):
        class Meta:
            model = Primary

    class BForm(ModelForm):
        class Meta:
            model = B
            exclude = ('primary',)

    class CForm(ModelForm):
         class Meta:
            model = C
            exclude = ('primary',)

    def generateView(request):
        if request.method == 'POST': # If the form has been submitted...
            primary_form = PrimaryForm(request.POST, prefix = "primary")
            b_form = BForm(request.POST, prefix = "b")
            c_form = CForm(request.POST, prefix = "c")
            if primary_form.is_valid() and b_form.is_valid() and c_form.is_valid(): # All validation rules pass
                    print "all validation passed"
                    primary = primary_form.save()
                    b_form.cleaned_data["primary"] = primary
                    b = b_form.save()
                    c_form.cleaned_data["primary"] = primary
                    c = c_form.save()
                    return HttpResponseRedirect("/viewer/%s/" % (primary.name))
            else:
                    print "failed"

        else:
            primary_form = PrimaryForm(prefix = "primary")
            b_form = BForm(prefix = "b")
            c_form = Form(prefix = "c")
     return render_to_response('multi_model.html', {
     'primary_form': primary_form,
     'b_form': b_form,
     'c_form': c_form,
      })

This method should allow you to do whatever validation you require, as well as generating all three objects on the same page. I have also used javascript and hidden fields to allow the generation of multiple B,C objects on the same page.


回答 3

来自的MultiModelFormdjango-betterforms是一个方便的包装程序,可以执行Gnudiff的答案中所述。它将regulars包装ModelForm在单个类中,该类透明(至少对于基本用法而言)用作单个形式。我从下面的文档中复制了一个示例。

# forms.py
from django import forms
from django.contrib.auth import get_user_model
from betterforms.multiform import MultiModelForm
from .models import UserProfile

User = get_user_model()

class UserEditForm(forms.ModelForm):
    class Meta:
        fields = ('email',)

class UserProfileForm(forms.ModelForm):
    class Meta:
        fields = ('favorite_color',)

class UserEditMultiForm(MultiModelForm):
    form_classes = {
        'user': UserEditForm,
        'profile': UserProfileForm,
    }

# views.py
from django.views.generic import UpdateView
from django.core.urlresolvers import reverse_lazy
from django.shortcuts import redirect
from django.contrib.auth import get_user_model
from .forms import UserEditMultiForm

User = get_user_model()

class UserSignupView(UpdateView):
    model = User
    form_class = UserEditMultiForm
    success_url = reverse_lazy('home')

    def get_form_kwargs(self):
        kwargs = super(UserSignupView, self).get_form_kwargs()
        kwargs.update(instance={
            'user': self.object,
            'profile': self.object.profile,
        })
        return kwargs

The MultiModelForm from django-betterforms is a convenient wrapper to do what is described in Gnudiff’s answer. It wraps regular ModelForms in a single class which is transparently (at least for basic usage) used as a single form. I’ve copied an example from their docs below.

# forms.py
from django import forms
from django.contrib.auth import get_user_model
from betterforms.multiform import MultiModelForm
from .models import UserProfile

User = get_user_model()

class UserEditForm(forms.ModelForm):
    class Meta:
        fields = ('email',)

class UserProfileForm(forms.ModelForm):
    class Meta:
        fields = ('favorite_color',)

class UserEditMultiForm(MultiModelForm):
    form_classes = {
        'user': UserEditForm,
        'profile': UserProfileForm,
    }

# views.py
from django.views.generic import UpdateView
from django.core.urlresolvers import reverse_lazy
from django.shortcuts import redirect
from django.contrib.auth import get_user_model
from .forms import UserEditMultiForm

User = get_user_model()

class UserSignupView(UpdateView):
    model = User
    form_class = UserEditMultiForm
    success_url = reverse_lazy('home')

    def get_form_kwargs(self):
        kwargs = super(UserSignupView, self).get_form_kwargs()
        kwargs.update(instance={
            'user': self.object,
            'profile': self.object.profile,
        })
        return kwargs

回答 4

我目前有一个解决方法功能(它通过了我的单元测试)。当您只想从其他模型中添加有限数量的字段时,这是一个很好的解决方案。

我在这里想念什么吗?

class UserProfileForm(ModelForm):
    def __init__(self, instance=None, *args, **kwargs):
        # Add these fields from the user object
        _fields = ('first_name', 'last_name', 'email',)
        # Retrieve initial (current) data from the user object
        _initial = model_to_dict(instance.user, _fields) if instance is not None else {}
        # Pass the initial data to the base
        super(UserProfileForm, self).__init__(initial=_initial, instance=instance, *args, **kwargs)
        # Retrieve the fields from the user model and update the fields with it
        self.fields.update(fields_for_model(User, _fields))

    class Meta:
        model = UserProfile
        exclude = ('user',)

    def save(self, *args, **kwargs):
        u = self.instance.user
        u.first_name = self.cleaned_data['first_name']
        u.last_name = self.cleaned_data['last_name']
        u.email = self.cleaned_data['email']
        u.save()
        profile = super(UserProfileForm, self).save(*args,**kwargs)
        return profile

I currently have a workaround functional (it passes my unit tests). It is a good solution to my opinion when you only want to add a limited number of fields from other models.

Am I missing something here ?

class UserProfileForm(ModelForm):
    def __init__(self, instance=None, *args, **kwargs):
        # Add these fields from the user object
        _fields = ('first_name', 'last_name', 'email',)
        # Retrieve initial (current) data from the user object
        _initial = model_to_dict(instance.user, _fields) if instance is not None else {}
        # Pass the initial data to the base
        super(UserProfileForm, self).__init__(initial=_initial, instance=instance, *args, **kwargs)
        # Retrieve the fields from the user model and update the fields with it
        self.fields.update(fields_for_model(User, _fields))

    class Meta:
        model = UserProfile
        exclude = ('user',)

    def save(self, *args, **kwargs):
        u = self.instance.user
        u.first_name = self.cleaned_data['first_name']
        u.last_name = self.cleaned_data['last_name']
        u.email = self.cleaned_data['email']
        u.save()
        profile = super(UserProfileForm, self).save(*args,**kwargs)
        return profile

回答 5

“我想隐藏一些字段并进行一些复杂的验证。”

我从内置的管理界面开始。

  1. 构建ModelForm以显示所需的字段。

  2. 用表单中的验证规则扩展表单。通常这是一种clean方法。

    确保这部分工作正常。

完成此操作后,您可以离开内置的管理界面。

然后,您可以在单个网页上四处查找与部分相关的表单。这是一堆模板材料,可在一个页面上显示所有表单。

然后,您必须编写视图函数来读取和验证各种表单内容,并执行各种对象saves()。

“如果我分解并手动编码所有内容,这是设计问题吗?” 不,只是很多时间而没有太多好处。

“I want to hide some of the fields and do some complex validation.”

I start with the built-in admin interface.

  1. Build the ModelForm to show the desired fields.

  2. Extend the Form with the validation rules within the form. Usually this is a clean method.

    Be sure this part works reasonably well.

Once this is done, you can move away from the built-in admin interface.

Then you can fool around with multiple, partially related forms on a single web page. This is a bunch of template stuff to present all the forms on a single page.

Then you have to write the view function to read and validated the various form things and do the various object saves().

“Is it a design issue if I break down and hand-code everything?” No, it’s just a lot of time for not much benefit.


回答 6

根据Django文档,内联表单集用于此目的:“内联表单集是模型表单集之上的一个小抽象层。它们简化了通过外键处理相关对象的情况”。

参见https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#inline-formsets

According to Django documentation, inline formsets are for this purpose: “Inline formsets is a small abstraction layer on top of model formsets. These simplify the case of working with related objects via a foreign key”.

See https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#inline-formsets


单个Django ModelForm中有多个模型?

问题:单个Django ModelForm中有多个模型?

ModelFormDjango 是否可以在一个模型中包含多个模型?我正在尝试创建个人资料编辑表单。因此,我需要包括User模型 UserProfile模型中的某些字段。目前我正在使用2种形式

class UserEditForm(ModelForm):

    class Meta:
        model = User
        fields = ("first_name", "last_name")

class UserProfileForm(ModelForm):

    class Meta:
        model = UserProfile
        fields = ("middle_name", "home_phone", "work_phone", "cell_phone")

有没有一种方法可以将这些合并为一个表单,或者我是否只需要创建一个表单并处理数据库加载并保存自己?

Is it possible to have multiple models included in a single ModelForm in django? I am trying to create a profile edit form. So I need to include some fields from the User model and the UserProfile model. Currently I am using 2 forms like this

class UserEditForm(ModelForm):

    class Meta:
        model = User
        fields = ("first_name", "last_name")

class UserProfileForm(ModelForm):

    class Meta:
        model = UserProfile
        fields = ("middle_name", "home_phone", "work_phone", "cell_phone")

Is there a way to consolidate these into one form or do I just need to create a form and handle the db loading and saving myself?


回答 0

您可以只在一个<form>html元素内的模板中显示两种形式。然后,只需在视图中分别处理表单即可。您仍然可以使用数据库,form.save()而不必自己进行数据库加载和保存。

在这种情况下,您不需要它,但是如果您要使用具有相同字段名的表单,请查看prefixdjango表单的kwarg。(我在这里回答了一个问题)。

You can just show both forms in the template inside of one <form> html element. Then just process the forms separately in the view. You’ll still be able to use form.save() and not have to process db loading and saving yourself.

In this case you shouldn’t need it, but if you’re going to be using forms with the same field names, look into the prefix kwarg for django forms. (I answered a question about it here).


回答 1

您可以尝试使用以下代码:

class CombinedFormBase(forms.Form):
    form_classes = []

    def __init__(self, *args, **kwargs):
        super(CombinedFormBase, self).__init__(*args, **kwargs)
        for f in self.form_classes:
            name = f.__name__.lower()
            setattr(self, name, f(*args, **kwargs))
            form = getattr(self, name)
            self.fields.update(form.fields)
            self.initial.update(form.initial)

    def is_valid(self):
        isValid = True
        for f in self.form_classes:
            name = f.__name__.lower()
            form = getattr(self, name)
            if not form.is_valid():
                isValid = False
        # is_valid will trigger clean method
        # so it should be called after all other forms is_valid are called
        # otherwise clean_data will be empty
        if not super(CombinedFormBase, self).is_valid() :
            isValid = False
        for f in self.form_classes:
            name = f.__name__.lower()
            form = getattr(self, name)
            self.errors.update(form.errors)
        return isValid

    def clean(self):
        cleaned_data = super(CombinedFormBase, self).clean()
        for f in self.form_classes:
            name = f.__name__.lower()
            form = getattr(self, name)
            cleaned_data.update(form.cleaned_data)
        return cleaned_data

用法示例:

class ConsumerRegistrationForm(CombinedFormBase):
    form_classes = [RegistrationForm, ConsumerProfileForm]

class RegisterView(FormView):
    template_name = "register.html"
    form_class = ConsumerRegistrationForm

    def form_valid(self, form):
        # some actions...
        return redirect(self.get_success_url())

You can try to use this pieces of code:

class CombinedFormBase(forms.Form):
    form_classes = []

    def __init__(self, *args, **kwargs):
        super(CombinedFormBase, self).__init__(*args, **kwargs)
        for f in self.form_classes:
            name = f.__name__.lower()
            setattr(self, name, f(*args, **kwargs))
            form = getattr(self, name)
            self.fields.update(form.fields)
            self.initial.update(form.initial)

    def is_valid(self):
        isValid = True
        for f in self.form_classes:
            name = f.__name__.lower()
            form = getattr(self, name)
            if not form.is_valid():
                isValid = False
        # is_valid will trigger clean method
        # so it should be called after all other forms is_valid are called
        # otherwise clean_data will be empty
        if not super(CombinedFormBase, self).is_valid() :
            isValid = False
        for f in self.form_classes:
            name = f.__name__.lower()
            form = getattr(self, name)
            self.errors.update(form.errors)
        return isValid

    def clean(self):
        cleaned_data = super(CombinedFormBase, self).clean()
        for f in self.form_classes:
            name = f.__name__.lower()
            form = getattr(self, name)
            cleaned_data.update(form.cleaned_data)
        return cleaned_data

Example Usage:

class ConsumerRegistrationForm(CombinedFormBase):
    form_classes = [RegistrationForm, ConsumerProfileForm]

class RegisterView(FormView):
    template_name = "register.html"
    form_class = ConsumerRegistrationForm

    def form_valid(self, form):
        # some actions...
        return redirect(self.get_success_url())

回答 2

我和erikbwork都有一个问题,即一个模型只能包含在一个通用的基于类的视图中。我找到了类似苗的类似方法,但是更加模块化。

我写了一个Mixin,因此您可以使用所有通用的基于类的视图。定义模型,字段,现在还定义child_model和child_field-然后可以将两个模型的字段包装在标签中,如Zach描述。

class ChildModelFormMixin: 
    ''' extends ModelFormMixin with the ability to include ChildModelForm '''
    child_model = ""
    child_fields = ()
    child_form_class = None

    def get_child_model(self):
        return self.child_model

    def get_child_fields(self):
        return self.child_fields

    def get_child_form(self):
        if not self.child_form_class:
            self.child_form_class = model_forms.modelform_factory(self.get_child_model(), fields=self.get_child_fields())
        return self.child_form_class(**self.get_form_kwargs())

    def get_context_data(self, **kwargs):
        if 'child_form' not in kwargs:
            kwargs['child_form'] = self.get_child_form()
        return super().get_context_data(**kwargs)

    def post(self, request, *args, **kwargs):
        form = self.get_form()
        child_form = self.get_child_form()

        # check if both forms are valid
        form_valid = form.is_valid()
        child_form_valid = child_form.is_valid()

        if form_valid and child_form_valid:
            return self.form_valid(form, child_form)
        else:
            return self.form_invalid(form)

    def form_valid(self, form, child_form):
        self.object = form.save()
        save_child_form = child_form.save(commit=False)
        save_child_form.course_key = self.object
        save_child_form.save()

        return HttpResponseRedirect(self.get_success_url())

用法示例:

class ConsumerRegistrationUpdateView(UpdateView):
    model = Registration
    fields = ('firstname', 'lastname',)
    child_model = ConsumerProfile
    child_fields = ('payment_token', 'cart',)

或使用ModelFormClass:

class ConsumerRegistrationUpdateView(UpdateView):
    model = Registration
    fields = ('firstname', 'lastname',)
    child_model = ConsumerProfile
    child_form_class = ConsumerProfileForm

做完了 希望能对某人有所帮助。

erikbwork and me both had the problem that one can only include one model into a generic Class Based View. I found a similar way of approaching it like Miao, but more modular.

I wrote a Mixin so you can use all generic Class Based Views. Define model, fields and now also child_model and child_field – and then you can wrap fields of both models in a tag like Zach describes.

class ChildModelFormMixin: 
    ''' extends ModelFormMixin with the ability to include ChildModelForm '''
    child_model = ""
    child_fields = ()
    child_form_class = None

    def get_child_model(self):
        return self.child_model

    def get_child_fields(self):
        return self.child_fields

    def get_child_form(self):
        if not self.child_form_class:
            self.child_form_class = model_forms.modelform_factory(self.get_child_model(), fields=self.get_child_fields())
        return self.child_form_class(**self.get_form_kwargs())

    def get_context_data(self, **kwargs):
        if 'child_form' not in kwargs:
            kwargs['child_form'] = self.get_child_form()
        return super().get_context_data(**kwargs)

    def post(self, request, *args, **kwargs):
        form = self.get_form()
        child_form = self.get_child_form()

        # check if both forms are valid
        form_valid = form.is_valid()
        child_form_valid = child_form.is_valid()

        if form_valid and child_form_valid:
            return self.form_valid(form, child_form)
        else:
            return self.form_invalid(form)

    def form_valid(self, form, child_form):
        self.object = form.save()
        save_child_form = child_form.save(commit=False)
        save_child_form.course_key = self.object
        save_child_form.save()

        return HttpResponseRedirect(self.get_success_url())

Example Usage:

class ConsumerRegistrationUpdateView(UpdateView):
    model = Registration
    fields = ('firstname', 'lastname',)
    child_model = ConsumerProfile
    child_fields = ('payment_token', 'cart',)

Or with ModelFormClass:

class ConsumerRegistrationUpdateView(UpdateView):
    model = Registration
    fields = ('firstname', 'lastname',)
    child_model = ConsumerProfile
    child_form_class = ConsumerProfileForm

Done. Hope that helps someone.


回答 3

您可能应该看一下Inline表单集。当模型通过外键关联时,将使用内联表单集。

You probably should take a look at Inline formsets. Inline formsets are used when your models are related by a foreign key.


回答 4

您可以在此处检查我的答案是否存在类似问题。

它讨论了如何将注册和用户配置文件合并为一种形式,但是可以将其推广到任何ModelForm组合。

You can check my answer here for a similar problem.

It talks about how to combine registration and user profile into one form, but it can be generalized to any ModelForm combination.


回答 5

我在项目中使用了django BetterformsMultiForm和MultiModelForm。但是,可以改进代码。例如,它依赖于django.six,而3. +不支持,但所有这些都可以轻松修复。

这个问题在StackOverflow中已经出现 几次了,所以我认为是时候找到一种标准的方法来解决这个问题了。

I used django betterforms‘s MultiForm and MultiModelForm in my project. The code can be improved, though. For example, it’s dependent on django.six, which isn’t supported by 3.+, but all of these can easily be fixed

This question has appeared several times in StackOverflow, so I think it’s time to find a standardized way of coping with this.


django模板中的“ none”是什么意思?

问题:django模板中的“ none”是什么意思?

我想看看Django模板中是否没有字段/变量。正确的语法是什么?

这是我目前拥有的:

{% if profile.user.first_name is null %}
  <p> -- </p>
{% elif %}
  {{ profile.user.first_name }} {{ profile.user.last_name }}
{% endif%}

在上面的示例中,我将用什么来替换“空”?

I want to see if a field/variable is none within a Django template. What is the correct syntax for that?

This is what I currently have:

{% if profile.user.first_name is null %}
  <p> -- </p>
{% elif %}
  {{ profile.user.first_name }} {{ profile.user.last_name }}
{% endif%}

In the example above, what would I use to replace “null”?


回答 0

None, False and True所有这些都可在模板标记和过滤器中找到。None, False,空字符串('', "", """""")和空列表/元组False都由进行求值if,因此您可以轻松地执行

{% if profile.user.first_name == None %}
{% if not profile.user.first_name %}

提示:@fabiocerqueira是正确的,将逻辑留给模型,将模板限制为唯一的表示层,并计算模型中的内容。一个例子:

# someapp/models.py
class UserProfile(models.Model):
    user = models.OneToOneField('auth.User')
    # other fields

    def get_full_name(self):
        if not self.user.first_name:
            return
        return ' '.join([self.user.first_name, self.user.last_name])

# template
{{ user.get_profile.get_full_name }}

希望这可以帮助 :)

None, False and True all are available within template tags and filters. None, False, the empty string ('', "", """""") and empty lists/tuples all evaluate to False when evaluated by if, so you can easily do

{% if profile.user.first_name == None %}
{% if not profile.user.first_name %}

A hint: @fabiocerqueira is right, leave logic to models, limit templates to be the only presentation layer and calculate stuff like that in you model. An example:

# someapp/models.py
class UserProfile(models.Model):
    user = models.OneToOneField('auth.User')
    # other fields

    def get_full_name(self):
        if not self.user.first_name:
            return
        return ' '.join([self.user.first_name, self.user.last_name])

# template
{{ user.get_profile.get_full_name }}

Hope this helps :)


回答 1

您还可以使用其他内置模板 default_if_none

{{ profile.user.first_name|default_if_none:"--" }}

You can also use another built-in template default_if_none

{{ profile.user.first_name|default_if_none:"--" }}

回答 2

is运算符:Django 1.10中的新增功能

{% if somevar is None %}
  This appears if somevar is None, or if somevar is not found in the context.
{% endif %}

isoperator : New in Django 1.10

{% if somevar is None %}
  This appears if somevar is None, or if somevar is not found in the context.
{% endif %}

回答 3

看看yesno助手

例如:

{{ myValue|yesno:"itwasTrue,itWasFalse,itWasNone" }}

Look at the yesno helper

Eg:

{{ myValue|yesno:"itwasTrue,itWasFalse,itWasNone" }}

回答 4

{% if profile.user.first_name %}起作用(假设您也不想接受'')。

if在Python一般对待NoneFalse''[]{},…所有为假。

{% if profile.user.first_name %} works (assuming you also don’t want to accept '').

if in Python in general treats None, False, '', [], {}, … all as false.


回答 5

您还可以使用内置的模板过滤器default

如果value的值为False(例如None,一个空字符串,0,False);默认显示为“-”。

{{ profile.user.first_name|default:"--" }}

文档:https : //docs.djangoproject.com/en/dev/ref/templates/builtins/#default

You can also use the built-in template filter default:

If value evaluates to False (e.g. None, an empty string, 0, False); the default “–” is displayed.

{{ profile.user.first_name|default:"--" }}

Documentation: https://docs.djangoproject.com/en/dev/ref/templates/builtins/#default


回答 6

您可以尝试以下方法:

{% if not profile.user.first_name.value %}
  <p> -- </p>
{% else %}
  {{ profile.user.first_name }} {{ profile.user.last_name }}
{% endif %}

这样,您实际上是在检查表单字段first_name是否具有与其关联的任何值。见{{ field.value }}循环遍历Django文档形式的领域

我正在使用Django 3.0。

You could try this:

{% if not profile.user.first_name.value %}
  <p> -- </p>
{% else %}
  {{ profile.user.first_name }} {{ profile.user.last_name }}
{% endif %}

This way, you’re essentially checking to see if the form field first_name has any value associated with it. See {{ field.value }} in Looping over the form’s fields in Django Documentation.

I’m using Django 3.0.


如何建立多个提交按钮Django表单?

问题:如何建立多个提交按钮Django表单?

我有一个带有一个电子邮件输入和两个提交按钮的表单,用于订阅和取消订阅新闻通讯:

<form action="" method="post">
{{ form_newsletter }}
<input type="submit" name="newsletter_sub" value="Subscribe" />
<input type="submit" name="newsletter_unsub" value="Unsubscribe" />
</form>

我也有上课表格:

class NewsletterForm(forms.ModelForm):
    class Meta:
        model = Newsletter
        fields = ('email',)

我必须编写自己的clean_email方法,并且我需要知道表单是通过哪个按钮提交的。但是提交按钮的值不在self.cleaned_data字典中。否则我可以获取按钮的值吗?

I have form with one input for email and two submit buttons to subscribe and unsubscribe from newsletter:

<form action="" method="post">
{{ form_newsletter }}
<input type="submit" name="newsletter_sub" value="Subscribe" />
<input type="submit" name="newsletter_unsub" value="Unsubscribe" />
</form>

I have also class form:

class NewsletterForm(forms.ModelForm):
    class Meta:
        model = Newsletter
        fields = ('email',)

I must write my own clean_email method and I need to know by which button was form submited. But the value of submit buttons aren’t in self.cleaned_data dictionary. Could I get values of buttons otherwise?


回答 0

您可以self.dataclean_email方法中使用来在验证之前访问POST数据。它应包含一个称为newsletter_subnewsletter_unsub取决于所按下按钮的键。

# in the context of a django.forms form

def clean(self):
    if 'newsletter_sub' in self.data:
        # do subscribe
    elif 'newsletter_unsub' in self.data:
        # do unsubscribe

You can use self.data in the clean_email method to access the POST data before validation. It should contain a key called newsletter_sub or newsletter_unsub depending on which button was pressed.

# in the context of a django.forms form

def clean(self):
    if 'newsletter_sub' in self.data:
        # do subscribe
    elif 'newsletter_unsub' in self.data:
        # do unsubscribe

回答 1

例如:

if 'newsletter_sub' in request.POST:
    # do subscribe
elif 'newsletter_unsub' in request.POST:
    # do unsubscribe

Eg:

if 'newsletter_sub' in request.POST:
    # do subscribe
elif 'newsletter_unsub' in request.POST:
    # do unsubscribe

回答 2

你也可以这样

 <form method='POST'>
    {{form1.as_p}}
    <button type="submit" name="btnform1">Save Changes</button>
    </form>
    <form method='POST'>
    {{form2.as_p}}
    <button type="submit" name="btnform2">Save Changes</button>
    </form>


if request.method=='POST' and 'btnform1' in request.POST:
    do something...
if request.method=='POST' and 'btnform2' in request.POST:
    do something...

You can also do like this,

 <form method='POST'>
    {{form1.as_p}}
    <button type="submit" name="btnform1">Save Changes</button>
    </form>
    <form method='POST'>
    {{form2.as_p}}
    <button type="submit" name="btnform2">Save Changes</button>
    </form>

CODE

if request.method=='POST' and 'btnform1' in request.POST:
    do something...
if request.method=='POST' and 'btnform2' in request.POST:
    do something...

回答 3

现在这是一个老问题,但是我遇到了同样的问题,并找到了一个对我有用的解决方案:我写了MultiRedirectMixin。

from django.http import HttpResponseRedirect

class MultiRedirectMixin(object):
    """
    A mixin that supports submit-specific success redirection.
     Either specify one success_url, or provide dict with names of 
     submit actions given in template as keys
     Example: 
       In template:
         <input type="submit" name="create_new" value="Create"/>
         <input type="submit" name="delete" value="Delete"/>
       View:
         MyMultiSubmitView(MultiRedirectMixin, forms.FormView):
             success_urls = {"create_new": reverse_lazy('create'),
                               "delete": reverse_lazy('delete')}
    """
    success_urls = {}  

    def form_valid(self, form):
        """ Form is valid: Pick the url and redirect.
        """

        for name in self.success_urls:
            if name in form.data:
                self.success_url = self.success_urls[name]
                break

        return HttpResponseRedirect(self.get_success_url())

    def get_success_url(self):
        """
        Returns the supplied success URL.
        """
        if self.success_url:
            # Forcing possible reverse_lazy evaluation
            url = force_text(self.success_url)
        else:
            raise ImproperlyConfigured(
                _("No URL to redirect to. Provide a success_url."))
        return url

It’s an old question now, nevertheless I had the same issue and found a solution that works for me: I wrote MultiRedirectMixin.

from django.http import HttpResponseRedirect

class MultiRedirectMixin(object):
    """
    A mixin that supports submit-specific success redirection.
     Either specify one success_url, or provide dict with names of 
     submit actions given in template as keys
     Example: 
       In template:
         <input type="submit" name="create_new" value="Create"/>
         <input type="submit" name="delete" value="Delete"/>
       View:
         MyMultiSubmitView(MultiRedirectMixin, forms.FormView):
             success_urls = {"create_new": reverse_lazy('create'),
                               "delete": reverse_lazy('delete')}
    """
    success_urls = {}  

    def form_valid(self, form):
        """ Form is valid: Pick the url and redirect.
        """

        for name in self.success_urls:
            if name in form.data:
                self.success_url = self.success_urls[name]
                break

        return HttpResponseRedirect(self.get_success_url())

    def get_success_url(self):
        """
        Returns the supplied success URL.
        """
        if self.success_url:
            # Forcing possible reverse_lazy evaluation
            url = force_text(self.success_url)
        else:
            raise ImproperlyConfigured(
                _("No URL to redirect to. Provide a success_url."))
        return url

回答 4

一个网址到同一视图!像这样!

urls.py

url(r'^$', views.landing.as_view(), name = 'landing'),

views.py

class landing(View):
        template_name = '/home.html'
        form_class1 = forms.pynamehere1
        form_class2 = forms.pynamehere2
            def get(self, request):
                form1 = self.form_class1(None)
                form2 = self.form_class2(None)
                return render(request, self.template_name, { 'register':form1, 'login':form2,})

             def post(self, request):
                 if request.method=='POST' and 'htmlsubmitbutton1' in request.POST:
                        ## do what ever you want to do for first function ####
                 if request.method=='POST' and 'htmlsubmitbutton2' in request.POST:
                         ## do what ever you want to do for second function ####
                        ## return def post###  
                 return render(request, self.template_name, {'form':form,})
/home.html
    <!-- #### form 1 #### -->
    <form action="" method="POST" >
      {% csrf_token %}
      {{ register.as_p }}
    <button type="submit" name="htmlsubmitbutton1">Login</button>
    </form>
    <!--#### form 2 #### -->
    <form action="" method="POST" >
      {% csrf_token %}
      {{ login.as_p }}
    <button type="submit" name="htmlsubmitbutton2">Login</button>
    </form>

one url to the same view! like so!

urls.py

url(r'^$', views.landing.as_view(), name = 'landing'),

views.py

class landing(View):
        template_name = '/home.html'
        form_class1 = forms.pynamehere1
        form_class2 = forms.pynamehere2
            def get(self, request):
                form1 = self.form_class1(None)
                form2 = self.form_class2(None)
                return render(request, self.template_name, { 'register':form1, 'login':form2,})

             def post(self, request):
                 if request.method=='POST' and 'htmlsubmitbutton1' in request.POST:
                        ## do what ever you want to do for first function ####
                 if request.method=='POST' and 'htmlsubmitbutton2' in request.POST:
                         ## do what ever you want to do for second function ####
                        ## return def post###  
                 return render(request, self.template_name, {'form':form,})
/home.html
    <!-- #### form 1 #### -->
    <form action="" method="POST" >
      {% csrf_token %}
      {{ register.as_p }}
    <button type="submit" name="htmlsubmitbutton1">Login</button>
    </form>
    <!--#### form 2 #### -->
    <form action="" method="POST" >
      {% csrf_token %}
      {{ login.as_p }}
    <button type="submit" name="htmlsubmitbutton2">Login</button>
    </form>

Django将自定义表单参数传递给Formset

问题:Django将自定义表单参数传递给Formset

这在Django 1.9中用form_kwargs修复

我有一个看起来像这样的Django表单:

class ServiceForm(forms.Form):
    option = forms.ModelChoiceField(queryset=ServiceOption.objects.none())
    rate = forms.DecimalField(widget=custom_widgets.SmallField())
    units = forms.IntegerField(min_value=1, widget=custom_widgets.SmallField())

    def __init__(self, *args, **kwargs):
        affiliate = kwargs.pop('affiliate')
        super(ServiceForm, self).__init__(*args, **kwargs)
        self.fields["option"].queryset = ServiceOption.objects.filter(affiliate=affiliate)

我称这种形式是这样的:

form = ServiceForm(affiliate=request.affiliate)

request.affiliate登录用户在哪里。这按预期工作。

我的问题是我现在想将此单一表单转换为表单集。我不知道的是在创建表单集时如何将会员信息传递给各个表单。根据文档来制作一个表单集,我需要做这样的事情:

ServiceFormSet = forms.formsets.formset_factory(ServiceForm, extra=3)

然后我需要这样创建它:

formset = ServiceFormSet()

现在如何以这种方式将affiliate = request.affiliate传递给各个表单?

This was fixed in Django 1.9 with form_kwargs.

I have a Django Form that looks like this:

class ServiceForm(forms.Form):
    option = forms.ModelChoiceField(queryset=ServiceOption.objects.none())
    rate = forms.DecimalField(widget=custom_widgets.SmallField())
    units = forms.IntegerField(min_value=1, widget=custom_widgets.SmallField())

    def __init__(self, *args, **kwargs):
        affiliate = kwargs.pop('affiliate')
        super(ServiceForm, self).__init__(*args, **kwargs)
        self.fields["option"].queryset = ServiceOption.objects.filter(affiliate=affiliate)

I call this form with something like this:

form = ServiceForm(affiliate=request.affiliate)

Where request.affiliate is the logged in user. This works as intended.

My problem is that I now want to turn this single form into a formset. What I can’t figure out is how I can pass the affiliate information to the individual forms when creating the formset. According to the docs to make a formset out of this I need to do something like this:

ServiceFormSet = forms.formsets.formset_factory(ServiceForm, extra=3)

And then I need to create it like this:

formset = ServiceFormSet()

Now how can I pass affiliate=request.affiliate to the individual forms this way?


回答 0

我会用functools.partialfunctools.wraps

from functools import partial, wraps
from django.forms.formsets import formset_factory

ServiceFormSet = formset_factory(wraps(ServiceForm)(partial(ServiceForm, affiliate=request.affiliate)), extra=3)

我认为这是最干净的方法,并且不会以任何方式影响ServiceForm(即,使子类难以继承)。

I would use functools.partial and functools.wraps:

from functools import partial, wraps
from django.forms.formsets import formset_factory

ServiceFormSet = formset_factory(wraps(ServiceForm)(partial(ServiceForm, affiliate=request.affiliate)), extra=3)

I think this is the cleanest approach, and doesn’t affect ServiceForm in any way (i.e. by making it difficult to subclass).


回答 1

正式文件方式

Django 2.0:

ArticleFormSet = formset_factory(MyArticleForm)
formset = ArticleFormSet(form_kwargs={'user': request.user})

https://docs.djangoproject.com/zh-CN/2.0/topics/forms/formsets/#passing-custom-parameters-to-formset-forms

Official Document Way

Django 2.0:

ArticleFormSet = formset_factory(MyArticleForm)
formset = ArticleFormSet(form_kwargs={'user': request.user})

https://docs.djangoproject.com/en/2.0/topics/forms/formsets/#passing-custom-parameters-to-formset-forms


回答 2

我将在一个函数中动态构建表单类,以便它可以通过闭包访问关联:

def make_service_form(affiliate):
    class ServiceForm(forms.Form):
        option = forms.ModelChoiceField(
                queryset=ServiceOption.objects.filter(affiliate=affiliate))
        rate = forms.DecimalField(widget=custom_widgets.SmallField())
        units = forms.IntegerField(min_value=1, 
                widget=custom_widgets.SmallField())
    return ServiceForm

另外,您不必在选项字段中重写查询集。缺点是子类化有点时髦。(任何子类都必须以类似的方式创建。)

编辑:

为了回应评论,您可以在使用类名的任何地方调用此函数:

def view(request):
    affiliate = get_object_or_404(id=request.GET.get('id'))
    formset_cls = formset_factory(make_service_form(affiliate))
    formset = formset_cls(request.POST)
    ...

I would build the form class dynamically in a function, so that it has access to the affiliate via closure:

def make_service_form(affiliate):
    class ServiceForm(forms.Form):
        option = forms.ModelChoiceField(
                queryset=ServiceOption.objects.filter(affiliate=affiliate))
        rate = forms.DecimalField(widget=custom_widgets.SmallField())
        units = forms.IntegerField(min_value=1, 
                widget=custom_widgets.SmallField())
    return ServiceForm

As a bonus, you don’t have to rewrite the queryset in the option field. The downside is that subclassing is a little funky. (Any subclass has to be made in a similar way.)

edit:

In response to a comment, you can call this function about any place you would use the class name:

def view(request):
    affiliate = get_object_or_404(id=request.GET.get('id'))
    formset_cls = formset_factory(make_service_form(affiliate))
    formset = formset_cls(request.POST)
    ...

回答 3

这是对我有效的Django 1.7:

from django.utils.functional import curry    

lols = {'lols':'lols'}
formset = modelformset_factory(MyModel, form=myForm, extra=0)
formset.form = staticmethod(curry(MyForm, lols=lols))
return formset

#form.py
class MyForm(forms.ModelForm):

    def __init__(self, lols, *args, **kwargs):

希望它能对某人有所帮助,花了我足够长的时间才能弄清楚;)

This is what worked for me, Django 1.7:

from django.utils.functional import curry    

lols = {'lols':'lols'}
formset = modelformset_factory(MyModel, form=myForm, extra=0)
formset.form = staticmethod(curry(MyForm, lols=lols))
return formset

#form.py
class MyForm(forms.ModelForm):

    def __init__(self, lols, *args, **kwargs):

Hope it helps someone, took me long enough to figure it out ;)


回答 4

我喜欢闭包解决方案,因为它更“干净”,并且使用了更多的Python语言(因此对+1表示响应),但Django表单也具有可用于过滤表单集中的查询集的回调机制。

它也没有记录,我认为这表明Django开发人员可能不太喜欢它。

因此,您基本上创建了相同的表单集,但添加了回调:

ServiceFormSet = forms.formsets.formset_factory(
    ServiceForm, extra=3, formfield_callback=Callback('option', affiliate).cb)

这将创建一个如下所示的类的实例:

class Callback(object):
    def __init__(self, field_name, aff):
        self._field_name = field_name
        self._aff = aff
    def cb(self, field, **kwargs):
        nf = field.formfield(**kwargs)
        if field.name == self._field_name:  # this is 'options' field
            nf.queryset = ServiceOption.objects.filter(affiliate=self._aff)
        return nf

这应该给您大致的想法。使回调成为这样的对象方法要稍微复杂一些,但是与执行简单的函数回调相比,它具有更多的灵活性。

I like the closure solution for being “cleaner” and more Pythonic (so +1 to mmarshall answer) but Django forms also have a callback mechanism you can use for filtering querysets in formsets.

It’s also not documented, which I think is an indicator the Django devs might not like it as much.

So you basically create your formset the same but add the callback:

ServiceFormSet = forms.formsets.formset_factory(
    ServiceForm, extra=3, formfield_callback=Callback('option', affiliate).cb)

This is creating an instance of a class that looks like this:

class Callback(object):
    def __init__(self, field_name, aff):
        self._field_name = field_name
        self._aff = aff
    def cb(self, field, **kwargs):
        nf = field.formfield(**kwargs)
        if field.name == self._field_name:  # this is 'options' field
            nf.queryset = ServiceOption.objects.filter(affiliate=self._aff)
        return nf

This should give you the general idea. It’s a little more complex making the callback an object method like this, but gives you a little more flexibility as opposed to doing a simple function callback.


回答 5

我想将其作为对卡尔·迈耶斯答案的评论,但由于这需要要点,因此我将其放在此处。我花了2个小时才弄清楚,所以希望对您有所帮助。

有关使用inlineformset_factory的注释。

我自己使用了该解决方案,并且效果很好,直到我使用inlineformset_factory对其进行了尝试。我正在运行Django 1.0.2,并遇到了一些奇怪的KeyError异常。我升级到最新的后备箱,并且可以直接使用。

我现在可以像这样使用它:

BookFormSet = inlineformset_factory(Author, Book, form=BookForm)
BookFormSet.form = staticmethod(curry(BookForm, user=request.user))

I wanted to place this as a comment to Carl Meyers answer, but since that requires points I just placed it here. This took me 2 hours to figure out so I hope it will help someone.

A note about using the inlineformset_factory.

I used that solution my self and it worked perfect, until I tried it with the inlineformset_factory. I was running Django 1.0.2 and got some strange KeyError exception. I upgraded to latest trunk and it worked direct.

I can now use it similar to this:

BookFormSet = inlineformset_factory(Author, Book, form=BookForm)
BookFormSet.form = staticmethod(curry(BookForm, user=request.user))

回答 6

从2012年8月14日星期二23:44:46 +0200提交e091c18f50266097f648efc7cac2503968e9d217开始,已接受的解决方案不再起作用。

当前版本的django.forms.models.modelform_factory()函数使用“类型构造技术”,在传递的表单上调用type()函数以获取元类类型,然后使用结果来构造其类对象即时输入::

# Instatiate type(form) in order to use the same metaclass as form.
return type(form)(class_name, (form,), form_class_attrs)

这意味着即使是一个curryed或partial对象,而不是一种形式的传递,也可以说是“导致鸭子咬你”:它会使用ModelFormClass对象的构造参数调用函数,并返回错误消息:

function() argument 1 must be code, not str

为了解决这个问题,我编写了一个生成器函数,该函数使用闭包返回指定为第一个参数的任何类的子类,然后在使用生成器函数的调用中提供的kwargs进行调用super.__init__之后update调用:

def class_gen_with_kwarg(cls, **additionalkwargs):
  """class generator for subclasses with additional 'stored' parameters (in a closure)
     This is required to use a formset_factory with a form that need additional 
     initialization parameters (see http://stackoverflow.com/questions/622982/django-passing-custom-form-parameters-to-formset)
  """
  class ClassWithKwargs(cls):
      def __init__(self, *args, **kwargs):
          kwargs.update(additionalkwargs)
          super(ClassWithKwargs, self).__init__(*args, **kwargs)
  return ClassWithKwargs

然后在您的代码中将表单工厂称为::

MyFormSet = inlineformset_factory(ParentModel, Model,form = class_gen_with_kwarg(MyForm, user=self.request.user))

注意事项:

  • 至少到目前为止,这很少接受测试
  • 提供的参数可能会冲突并覆盖那些将使用构造函数返回的对象的代码所使用的参数

As of commit e091c18f50266097f648efc7cac2503968e9d217 on Tue Aug 14 23:44:46 2012 +0200 the accepted solution can’t work anymore.

The current version of django.forms.models.modelform_factory() function uses a “type construction technique”, calling the type() function on the passed form to get the metaclass type, then using the result to construct a class-object of its type on the fly::

# Instatiate type(form) in order to use the same metaclass as form.
return type(form)(class_name, (form,), form_class_attrs)

This means even a curryed or partial object passed instead of a form “causes the duck to bite you” so to speak: it’ll call a function with the construction parameters of a ModelFormClass object, returning the error message::

function() argument 1 must be code, not str

To work around this I wrote a generator function that uses a closure to return a subclass of any class specified as first parameter, that then calls super.__init__ after updateing the kwargs with the ones supplied on the generator function’s call::

def class_gen_with_kwarg(cls, **additionalkwargs):
  """class generator for subclasses with additional 'stored' parameters (in a closure)
     This is required to use a formset_factory with a form that need additional 
     initialization parameters (see http://stackoverflow.com/questions/622982/django-passing-custom-form-parameters-to-formset)
  """
  class ClassWithKwargs(cls):
      def __init__(self, *args, **kwargs):
          kwargs.update(additionalkwargs)
          super(ClassWithKwargs, self).__init__(*args, **kwargs)
  return ClassWithKwargs

Then in your code you’ll call the form factory as::

MyFormSet = inlineformset_factory(ParentModel, Model,form = class_gen_with_kwarg(MyForm, user=self.request.user))

caveats:

  • this received very little testing, at least for now
  • supplied parameters could clash and overwrite those used by whatever code will use the object returned by the constructor

回答 7

卡尔·迈耶的解决方案看起来非常优雅。我尝试为modelformsets实现它。我的印象是我无法在类中调用静态方法,但是以下操作莫名其妙地起作用:

class MyModel(models.Model):
  myField = models.CharField(max_length=10)

class MyForm(ModelForm):
  _request = None
  class Meta:
    model = MyModel

    def __init__(self,*args,**kwargs):      
      self._request = kwargs.pop('request', None)
      super(MyForm,self).__init__(*args,**kwargs)

class MyFormsetBase(BaseModelFormSet):
  _request = None

def __init__(self,*args,**kwargs):
  self._request = kwargs.pop('request', None)
  subFormClass = self.form
  self.form = curry(subFormClass,request=self._request)
  super(MyFormsetBase,self).__init__(*args,**kwargs)

MyFormset =  modelformset_factory(MyModel,formset=MyFormsetBase,extra=1,max_num=10,can_delete=True)
MyFormset.form = staticmethod(curry(MyForm,request=MyFormsetBase._request))

在我看来,如果我做这样的事情:

formset = MyFormset(request.POST,queryset=MyModel.objects.all(),request=request)

然后,“ request”关键字传播到我的表单集中的所有成员表单。我很高兴,但我不知道为什么这样做有效-似乎错了。有什么建议?

Carl Meyer’s solution looks very elegant. I tried implementing it for modelformsets. I was under the impression that I could not call staticmethods within a class, but the following inexplicably works:

class MyModel(models.Model):
  myField = models.CharField(max_length=10)

class MyForm(ModelForm):
  _request = None
  class Meta:
    model = MyModel

    def __init__(self,*args,**kwargs):      
      self._request = kwargs.pop('request', None)
      super(MyForm,self).__init__(*args,**kwargs)

class MyFormsetBase(BaseModelFormSet):
  _request = None

def __init__(self,*args,**kwargs):
  self._request = kwargs.pop('request', None)
  subFormClass = self.form
  self.form = curry(subFormClass,request=self._request)
  super(MyFormsetBase,self).__init__(*args,**kwargs)

MyFormset =  modelformset_factory(MyModel,formset=MyFormsetBase,extra=1,max_num=10,can_delete=True)
MyFormset.form = staticmethod(curry(MyForm,request=MyFormsetBase._request))

In my view, if I do something like this:

formset = MyFormset(request.POST,queryset=MyModel.objects.all(),request=request)

Then the “request” keyword gets propagated to all of the member forms of my formset. I’m pleased, but I have no idea why this is working – it seems wrong. Any suggestions?


回答 8

在看到这篇文章之前,我花了一些时间试图解决这个问题。

我想到的解决方案是闭包解决方案(这是我之前在Django模型表单中使用的解决方案)。

我如上所述尝试了curry()方法,但是我无法使它与Django 1.0一起使用,因此最终我恢复为闭包方法。

闭合方法非常简洁,唯一的奇怪之处是类定义嵌套在视图或其他函数中。我认为这对我来说似乎很奇怪,这是我以前的编程经验的遗忘,而且我认为具有动态语言背景的人也不会蒙上双眼!

I spent some time trying to figure out this problem before I saw this posting.

The solution I came up with was the closure solution (and it is a solution I’ve used before with Django model forms).

I tried the curry() method as described above, but I just couldn’t get it to work with Django 1.0 so in the end I reverted to the closure method.

The closure method is very neat and the only slight oddness is that the class definition is nested inside the view or another function. I think the fact that this looks odd to me is a hangup from my previous programming experience and I think someone with a background in more dynamic languages wouldn’t bat an eyelid!


回答 9

我不得不做类似的事情。这类似于curry解决方案:

def form_with_my_variable(myvar):
   class MyForm(ServiceForm):
     def __init__(self, myvar=myvar, *args, **kwargs):
       super(SeriveForm, self).__init__(myvar=myvar, *args, **kwargs)
   return MyForm

factory = inlineformset_factory(..., form=form_with_my_variable(myvar), ... )

I had to do a similar thing. This is similar to the curry solution:

def form_with_my_variable(myvar):
   class MyForm(ServiceForm):
     def __init__(self, myvar=myvar, *args, **kwargs):
       super(SeriveForm, self).__init__(myvar=myvar, *args, **kwargs)
   return MyForm

factory = inlineformset_factory(..., form=form_with_my_variable(myvar), ... )

回答 10

基于此答案,我找到了更清晰的解决方案:

class ServiceForm(forms.Form):
    option = forms.ModelChoiceField(
            queryset=ServiceOption.objects.filter(affiliate=self.affiliate))
    rate = forms.DecimalField(widget=custom_widgets.SmallField())
    units = forms.IntegerField(min_value=1, 
            widget=custom_widgets.SmallField())

    @staticmethod
    def make_service_form(affiliate):
        self.affiliate = affiliate
        return ServiceForm

并像这样运行它

formset_factory(form=ServiceForm.make_service_form(affiliate))

based on this answer I found more clear solution:

class ServiceForm(forms.Form):
    option = forms.ModelChoiceField(
            queryset=ServiceOption.objects.filter(affiliate=self.affiliate))
    rate = forms.DecimalField(widget=custom_widgets.SmallField())
    units = forms.IntegerField(min_value=1, 
            widget=custom_widgets.SmallField())

    @staticmethod
    def make_service_form(affiliate):
        self.affiliate = affiliate
        return ServiceForm

And run it in view like

formset_factory(form=ServiceForm.make_service_form(affiliate))

回答 11

我是这里的新手,因此无法添加评论。我希望这段代码也能工作:

ServiceFormSet = formset_factory(ServiceForm, extra=3)

ServiceFormSet.formset = staticmethod(curry(ServiceForm, affiliate=request.affiliate))

至于向BaseFormSet表单集(而不是表单)添加其他参数。

I’m a newbie here so I can’t add comment. I hope this code will work too:

ServiceFormSet = formset_factory(ServiceForm, extra=3)

ServiceFormSet.formset = staticmethod(curry(ServiceForm, affiliate=request.affiliate))

as for adding additional parameters to the formset’s BaseFormSet instead of form.


如何在Django的CharField上添加占位符?

问题:如何在Django的CharField上添加占位符?

以这个非常简单的形式为例:

class SearchForm(Form):
    q = forms.CharField(label='search')

这将在模板中呈现:

<input type="text" name="q" id="id_q" />

但是,我想将placeholder属性值添加到此字段,Search以便HTML看起来像这样:

<input type="text" name="q" id="id_q" placeholder="Search" />

最好我想CharField通过字典或类似的东西将占位符值传递给表单类中的:

q = forms.CharField(label='search', placeholder='Search')

做到这一点的最佳方法是什么?

Take this very simple form for example:

class SearchForm(Form):
    q = forms.CharField(label='search')

This gets rendered in the template:

<input type="text" name="q" id="id_q" />

However, I want to add the placeholder attribute to this field with a value of Search so that the HTML would look something like:

<input type="text" name="q" id="id_q" placeholder="Search" />

Preferably I would like to pass the placeholder value in to CharField in the form class through a dictionary or something like:

q = forms.CharField(label='search', placeholder='Search')

What would be the best way to accomplish this?


回答 0

查看小部件文档。基本上看起来像:

q = forms.CharField(label='search', 
                    widget=forms.TextInput(attrs={'placeholder': 'Search'}))

是的,更多的写作,但是分离允许更好地抽象更复杂的情况。

您也可以声明widgets包含一个属性<field name> => <widget instance>直接映射Meta你的ModelForm子类。

Look at the widgets documentation. Basically it would look like:

q = forms.CharField(label='search', 
                    widget=forms.TextInput(attrs={'placeholder': 'Search'}))

More writing, yes, but the separation allows for better abstraction of more complicated cases.

You can also declare a widgets attribute containing a <field name> => <widget instance> mapping directly on the Meta of your ModelForm sub-class.


回答 1

对于ModelForm,您可以这样使用Meta类:

from django import forms

from .models import MyModel

class MyModelForm(forms.ModelForm):
    class Meta:
        model = MyModel
        widgets = {
            'name': forms.TextInput(attrs={'placeholder': 'Name'}),
            'description': forms.Textarea(
                attrs={'placeholder': 'Enter description here'}),
        }

For a ModelForm, you can use the Meta class thus:

from django import forms

from .models import MyModel

class MyModelForm(forms.ModelForm):
    class Meta:
        model = MyModel
        widgets = {
            'name': forms.TextInput(attrs={'placeholder': 'Name'}),
            'description': forms.Textarea(
                attrs={'placeholder': 'Enter description here'}),
        }

回答 2

其他方法都很好。但是,如果您不想指定该字段(例如,对于某些动态方法),则可以使用以下方法:

def __init__(self, *args, **kwargs):
    super(MyForm, self).__init__(*args, **kwargs)
    self.fields['email'].widget.attrs['placeholder'] = self.fields['email'].label or 'email@address.nl'

它还允许占位符依赖于具有指定实例的ModelForms的实例。

The other methods are all good. However, if you prefer to not specify the field (e.g. for some dynamic method), you can use this:

def __init__(self, *args, **kwargs):
    super(MyForm, self).__init__(*args, **kwargs)
    self.fields['email'].widget.attrs['placeholder'] = self.fields['email'].label or 'email@address.nl'

It also allows the placeholder to depend on the instance for ModelForms with instance specified.


回答 3

您可以使用此代码为表单中的每个TextInput字段添加占位符attr。占位符的文本将从模型字段标签中获取。

class PlaceholderDemoForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(PlaceholderDemoForm, self).__init__(*args, **kwargs)
        for field_name in self.fields:
            field = self.fields.get(field_name)  
            if field:
                if type(field.widget) in (forms.TextInput, forms.DateInput):
                    field.widget = forms.TextInput(attrs={'placeholder': field.label})

    class Meta:
        model = DemoModel

You can use this code to add placeholder attr for every TextInput field in you form. Text for placeholders will be taken from model field labels.

class PlaceholderDemoForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(PlaceholderDemoForm, self).__init__(*args, **kwargs)
        for field_name in self.fields:
            field = self.fields.get(field_name)  
            if field:
                if type(field.widget) in (forms.TextInput, forms.DateInput):
                    field.widget = forms.TextInput(attrs={'placeholder': field.label})

    class Meta:
        model = DemoModel

回答 4

好问题。我知道三种解决方案:

解决方案1

替换默认的小部件。

class SearchForm(forms.Form):  
    q = forms.CharField(
            label='Search',
            widget=forms.TextInput(attrs={'placeholder': 'Search'})
        )

解决方案#2

自定义默认窗口小部件。如果您使用的是该字段通常使用的同一小部件​​,则可以简单地自定义该小部件,而不用实例化一个全新的小部件。

class SearchForm(forms.Form):  
    q = forms.CharField(label='Search')

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['q'].widget.attrs.update({'placeholder': 'Search'})

解决方案#3

最后,如果您正在使用模型表单,那么(除了前两个解决方案之外),您可以选择通过设置widgets内部Meta类的属性来为字段指定自定义窗口小部件。

class CommentForm(forms.ModelForm):  
    class Meta:
        model = Comment
        widgets = {
            'body': forms.Textarea(attrs={'cols': 80, 'rows': 20})
        }

Great question. There are three solutions I know about:

Solution #1

Replace the default widget.

class SearchForm(forms.Form):  
    q = forms.CharField(
            label='Search',
            widget=forms.TextInput(attrs={'placeholder': 'Search'})
        )

Solution #2

Customize the default widget. If you’re using the same widget that the field usually uses then you can simply customize that one instead of instantiating an entirely new one.

class SearchForm(forms.Form):  
    q = forms.CharField(label='Search')

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['q'].widget.attrs.update({'placeholder': 'Search'})

Solution #3

Finally, if you’re working with a model form then (in addition to the previous two solutions) you have the option to specify a custom widget for a field by setting the widgets attribute of the inner Meta class.

class CommentForm(forms.ModelForm):  
    class Meta:
        model = Comment
        widgets = {
            'body': forms.Textarea(attrs={'cols': 80, 'rows': 20})
        }

回答 5

当您只想覆盖其占位符时,不知道如何实例化窗口小部件是不可取的。

    q = forms.CharField(label='search')
    ...
    q.widget.attrs['placeholder'] = "Search"

It’s undesirable to have to know how to instantiate a widget when you just want to override its placeholder.

    q = forms.CharField(label='search')
    ...
    q.widget.attrs['placeholder'] = "Search"

回答 6

大多数时候,我只是希望所有占位符都等于模型中定义的字段的详细名称

我添加了一个mixin,可以轻松地对我创建的任何表单执行此操作,

class ProductForm(PlaceholderMixin, ModelForm):
    class Meta:
        model = Product
        fields = ('name', 'description', 'location', 'store')

class PlaceholderMixin:
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs):
        field_names = [field_name for field_name, _ in self.fields.items()]
        for field_name in field_names:
            field = self.fields.get(field_name)
            field.widget.attrs.update({'placeholder': field.label})

Most of the time I just wish to have all placeholders equal to the verbose name of the field defined in my models

I’ve added a mixin to easily do this to any form that I create,

class ProductForm(PlaceholderMixin, ModelForm):
    class Meta:
        model = Product
        fields = ('name', 'description', 'location', 'store')

And

class PlaceholderMixin:
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        field_names = [field_name for field_name, _ in self.fields.items()]
        for field_name in field_names:
            field = self.fields.get(field_name)
            field.widget.attrs.update({'placeholder': field.label})

回答 7

在查看了您的方法之后,我使用了这种方法来解决它。

class Register(forms.Form):
    username = forms.CharField(label='用户名', max_length=32)
    email = forms.EmailField(label='邮箱', max_length=64)
    password = forms.CharField(label="密码", min_length=6, max_length=16)
    captcha = forms.CharField(label="验证码", max_length=4)

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    for field_name in self.fields:
        field = self.fields.get(field_name)
        self.fields[field_name].widget.attrs.update({
            "placeholder": field.label,
            'class': "input-control"
        })

After looking at your method, I used this method to solve it.

class Register(forms.Form):
    username = forms.CharField(label='用户名', max_length=32)
    email = forms.EmailField(label='邮箱', max_length=64)
    password = forms.CharField(label="密码", min_length=6, max_length=16)
    captcha = forms.CharField(label="验证码", max_length=4)

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    for field_name in self.fields:
        field = self.fields.get(field_name)
        self.fields[field_name].widget.attrs.update({
            "placeholder": field.label,
            'class': "input-control"
        })

在Django Forms中定义CSS类

问题:在Django Forms中定义CSS类

假设我有一个表格

class SampleClass(forms.Form):
    name = forms.CharField(max_length=30)
    age = forms.IntegerField()
    django_hacker = forms.BooleanField(required=False)

有没有一种方法可以在每个字段上定义CSS类,以便可以在渲染页面中基于类使用jQuery?

我希望不必手动构建表单。

Assume I have a form

class SampleClass(forms.Form):
    name = forms.CharField(max_length=30)
    age = forms.IntegerField()
    django_hacker = forms.BooleanField(required=False)

Is there a way for me to define css classes on each field such that I can then use jQuery based on class in my rendered page?

I was hoping not to have to manually build the form.


回答 0

另一种不需要更改python代码的解决方案,因此对于设计人员和一次性演示更改更好:django-widget-tweaks。希望有人会发现它有用。

Yet another solution that doesn’t require changes in python code and so is better for designers and one-off presentational changes: django-widget-tweaks. Hope somebody will find it useful.


回答 1

回答了我自己的问题。

http://docs.djangoproject.com/en/dev/ref/forms/widgets/#django.forms.Widget.attrs

我没有意识到它已传递到小部件构造函数中。

Answered my own question. Sigh

http://docs.djangoproject.com/en/dev/ref/forms/widgets/#django.forms.Widget.attrs

I didn’t realize it was passed into the widget constructor.


回答 2

这是在类中声明字段后将类定义添加到小部件的另一种解决方案。

def __init__(self, *args, **kwargs):
    super(SampleClass, self).__init__(*args, **kwargs)
    self.fields['name'].widget.attrs['class'] = 'my_class'

Here is another solution for adding class definitions to the widgets after declaring the fields in the class.

def __init__(self, *args, **kwargs):
    super(SampleClass, self).__init__(*args, **kwargs)
    self.fields['name'].widget.attrs['class'] = 'my_class'

回答 3

使用django-widget-tweaks,它易于使用并且效果很好。

否则,可以使用自定义模板过滤器来完成此操作。

考虑到您以这种方式呈现表单:

<form action="/contact/" method="post">
    {{ form.non_field_errors }}
    <div class="fieldWrapper">
        {{ form.subject.errors }}
        <label for="id_subject">Email subject:</label>
        {{ form.subject }}
    </div>
</form>

form.subject是具有as_widget方法的BoundField的实例。

您可以在“ my_app / templatetags / myfilters.py”中创建自定义过滤器“ addcss”

from django import template

register = template.Library()

@register.filter(name='addcss')
def addcss(value, arg):
    css_classes = value.field.widget.attrs.get('class', '').split(' ')
    if css_classes and arg not in css_classes:
        css_classes = '%s %s' % (css_classes, arg)
    return value.as_widget(attrs={'class': css_classes})

然后应用您的过滤器:

{% load myfilters %}
<form action="/contact/" method="post">
    {{ form.non_field_errors }}
    <div class="fieldWrapper">
        {{ form.subject.errors }}
        <label for="id_subject">Email subject:</label>
        {{ form.subject|addcss:'MyClass' }}
    </div>
</form>

然后,将使用“ MyClass” css类呈现form.subjects。

希望能有所帮助。

编辑1

  • 根据dimyG的答案更新过滤器

  • 添加django-widget-tweak链接

编辑2

  • 根据Bhyd的评论更新过滤器

Use django-widget-tweaks, it is easy to use and works pretty well.

Otherwise this can be done using a custom template filter.

Considering you render your form this way :

<form action="/contact/" method="post">
    {{ form.non_field_errors }}
    <div class="fieldWrapper">
        {{ form.subject.errors }}
        <label for="id_subject">Email subject:</label>
        {{ form.subject }}
    </div>
</form>

form.subject is an instance of BoundField which has the as_widget method.

you can create a custom filter “addcss” in “my_app/templatetags/myfilters.py”

from django import template

register = template.Library()

@register.filter(name='addcss')
def addcss(value, arg):
    css_classes = value.field.widget.attrs.get('class', '').split(' ')
    if css_classes and arg not in css_classes:
        css_classes = '%s %s' % (css_classes, arg)
    return value.as_widget(attrs={'class': css_classes})

And then apply your filter:

{% load myfilters %}
<form action="/contact/" method="post">
    {{ form.non_field_errors }}
    <div class="fieldWrapper">
        {{ form.subject.errors }}
        <label for="id_subject">Email subject:</label>
        {{ form.subject|addcss:'MyClass' }}
    </div>
</form>

form.subjects will then be rendered with the “MyClass” css class.

Hope this help.

EDIT 1

  • Update filter according to dimyG‘s answer

  • Add django-widget-tweak link

EDIT 2

  • Update filter according to Bhyd‘s comment

回答 4

扩展指向docs.djangoproject.com的方法:

class MyForm(forms.Form): 
    comment = forms.CharField(
            widget=forms.TextInput(attrs={'size':'40'}))

我认为必须了解每个字段的本机窗口小部件类型很麻烦,并且认为仅将类名放在表单字段上就覆盖默认值很有趣。这似乎为我工作:

class MyForm(forms.Form): 
    #This instantiates the field w/ the default widget
    comment = forms.CharField()

    #We only override the part we care about
    comment.widget.attrs['size'] = '40'

对我来说,这似乎有点清洁。

Expanding on the method pointed to at docs.djangoproject.com:

class MyForm(forms.Form): 
    comment = forms.CharField(
            widget=forms.TextInput(attrs={'size':'40'}))

I thought it was troublesome to have to know the native widget type for every field, and thought it funny to override the default just to put a class name on a form field. This seems to work for me:

class MyForm(forms.Form): 
    #This instantiates the field w/ the default widget
    comment = forms.CharField()

    #We only override the part we care about
    comment.widget.attrs['size'] = '40'

This seems a little cleaner to me.


回答 5

如果您希望表单中的所有字段都继承某个类,则只需定义一个父类,该类从继承forms.ModelForm,然后从该类继承

class BaseForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(BaseForm, self).__init__(*args, **kwargs)
        for field_name, field in self.fields.items():
            field.widget.attrs['class'] = 'someClass'


class WhateverForm(BaseForm):
    class Meta:
        model = SomeModel

这帮助我将'form-control'类自动添加到应用程序所有形式的所有字段中,而无需添加代码复制。

If you want all the fields in the form to inherit a certain class, you just define a parent class, that inherits from forms.ModelForm, and then inherit from it

class BaseForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(BaseForm, self).__init__(*args, **kwargs)
        for field_name, field in self.fields.items():
            field.widget.attrs['class'] = 'someClass'


class WhateverForm(BaseForm):
    class Meta:
        model = SomeModel

This helped me to add the 'form-control' class to all of the fields on all of the forms of my application automatically, without adding replication of code.


回答 6

这是更改视图的简单方法。在将其传递到模板之前,在视图中添加以下内容。

form = MyForm(instance = instance.obj)
form.fields['email'].widget.attrs = {'class':'here_class_name'}

Here is Simple way to alter in view. add below in view just before passing it into template.

form = MyForm(instance = instance.obj)
form.fields['email'].widget.attrs = {'class':'here_class_name'}

回答 7

只需将类添加到表单中,如下所示。

class UserLoginForm(forms.Form):
    username = forms.CharField(widget=forms.TextInput(
        attrs={
        'class':'form-control',
        'placeholder':'Username'
        }
    ))
    password = forms.CharField(widget=forms.PasswordInput(
        attrs={
        'class':'form-control',
        'placeholder':'Password'
        }
    ))

Simply add the classes to your form as follows.

class UserLoginForm(forms.Form):
    username = forms.CharField(widget=forms.TextInput(
        attrs={
        'class':'form-control',
        'placeholder':'Username'
        }
    ))
    password = forms.CharField(widget=forms.PasswordInput(
        attrs={
        'class':'form-control',
        'placeholder':'Password'
        }
    ))

回答 8

这是上述内容的一种变体,它将为所有字段提供相同的类(例如,jQuery的圆角效果很好)。

  # Simple way to assign css class to every field
  def __init__(self, *args, **kwargs):
    super(TranslatedPageForm, self).__init__(*args, **kwargs)
    for myField in self.fields:
      self.fields[myField].widget.attrs['class'] = 'ui-state-default ui-corner-all'

Here is a variation on the above which will give all fields the same class (e.g. jquery nice rounded corners).

  # Simple way to assign css class to every field
  def __init__(self, *args, **kwargs):
    super(TranslatedPageForm, self).__init__(*args, **kwargs)
    for myField in self.fields:
      self.fields[myField].widget.attrs['class'] = 'ui-state-default ui-corner-all'

回答 9

你可以试试看

class SampleClass(forms.Form):
  name = forms.CharField(max_length=30)
  name.widget.attrs.update({'class': 'your-class'})
...

您可以在以下网站中查看更多信息:Django Widgets

You can try this..

class SampleClass(forms.Form):
  name = forms.CharField(max_length=30)
  name.widget.attrs.update({'class': 'your-class'})
...

You can see more information in: Django Widgets


回答 10

如果您想向模板中的表单字段(而不是view.py或form.py中)添加类,例如,要在不覆盖其第三方视图的情况下修改第三方应用程序,则可以按照以下说明过滤模板在查尔斯泰克 回答很方便。但是在此答案中,模板过滤器会覆盖该字段可能具有的所有现有类。

我尝试将其添加为编辑内容,但建议将其写为新答案。

因此,这是一个尊重字段现有类的模板标记:

from django import template

register = template.Library()


@register.filter(name='addclass')
def addclass(field, given_class):
    existing_classes = field.field.widget.attrs.get('class', None)
    if existing_classes:
        if existing_classes.find(given_class) == -1:
            # if the given class doesn't exist in the existing classes
            classes = existing_classes + ' ' + given_class
        else:
            classes = existing_classes
    else:
        classes = given_class
    return field.as_widget(attrs={"class": classes})

In case that you want to add a class to a form’s field in a template (not in view.py or form.py) for example in cases that you want to modify 3rd party apps without overriding their views, then a template filter as described in Charlesthk answer is very convenient. But in this answer the template filter overrides any existing classes that the field might has.

I tried to add this as an edit but it was suggested to be written as a new answer.

So, here is a template tag that respects the existing classes of the field:

from django import template

register = template.Library()


@register.filter(name='addclass')
def addclass(field, given_class):
    existing_classes = field.field.widget.attrs.get('class', None)
    if existing_classes:
        if existing_classes.find(given_class) == -1:
            # if the given class doesn't exist in the existing classes
            classes = existing_classes + ' ' + given_class
        else:
            classes = existing_classes
    else:
        classes = given_class
    return field.as_widget(attrs={"class": classes})

回答 11

事实证明,您可以在表单构造函数(init函数)中或在启动表单类之后执行此操作。如果您不编写自己的表单并且该表单来自其他地方,则有时需要这样做-

def some_view(request):
    add_css_to_fields = ['list','of','fields']
    if request.method == 'POST':
        form = SomeForm(request.POST)
        if form.is_valid():
            return HttpResponseRedirect('/thanks/')
    else:
        form = SomeForm()

    for key in form.fields.keys():
        if key in add_css_to_fields:
            field = form.fields[key]
            css_addition = 'css_addition '
            css = field.widget.attrs.get('class', '')
            field.widget.attrs['class'] = css_addition + css_classes

    return render(request, 'template_name.html', {'form': form})

As it turns out you can do this in form constructor (init function) or after form class was initiated. This is sometimes required if you are not writing your own form and that form is coming from somewhere else –

def some_view(request):
    add_css_to_fields = ['list','of','fields']
    if request.method == 'POST':
        form = SomeForm(request.POST)
        if form.is_valid():
            return HttpResponseRedirect('/thanks/')
    else:
        form = SomeForm()

    for key in form.fields.keys():
        if key in add_css_to_fields:
            field = form.fields[key]
            css_addition = 'css_addition '
            css = field.widget.attrs.get('class', '')
            field.widget.attrs['class'] = css_addition + css_classes

    return render(request, 'template_name.html', {'form': form})

回答 12

您还可以使用Django Crispy Forms,这是定义表单的好工具,以防您需要使用Bootstrap或Foundation这样的CSS框架。在那里为表单字段指定类很容易。

您的表单类会这样:

from django import forms

from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Div, Submit, Field
from crispy_forms.bootstrap import FormActions

class SampleClass(forms.Form):
    name = forms.CharField(max_length=30)
    age = forms.IntegerField()
    django_hacker = forms.BooleanField(required=False)

    helper = FormHelper()
    helper.form_class = 'your-form-class'
    helper.layout = Layout(
        Field('name', css_class='name-class'),
        Field('age', css_class='age-class'),
        Field('django_hacker', css-class='hacker-class'),
        FormActions(
            Submit('save_changes', 'Save changes'),
        )
    )

You could also use Django Crispy Forms, it’s a great tool to define forms in case you’d like to use some CSS framework like Bootstrap or Foundation. And it’s easy to specify classes for your form fields there.

Your form class would like this then:

from django import forms

from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Div, Submit, Field
from crispy_forms.bootstrap import FormActions

class SampleClass(forms.Form):
    name = forms.CharField(max_length=30)
    age = forms.IntegerField()
    django_hacker = forms.BooleanField(required=False)

    helper = FormHelper()
    helper.form_class = 'your-form-class'
    helper.layout = Layout(
        Field('name', css_class='name-class'),
        Field('age', css_class='age-class'),
        Field('django_hacker', css-class='hacker-class'),
        FormActions(
            Submit('save_changes', 'Save changes'),
        )
    )

Django设置默认表单值

问题:Django设置默认表单值

我有一个模型如下:

class TankJournal(models.Model):
    user = models.ForeignKey(User)
    tank = models.ForeignKey(TankProfile)
    ts = models.IntegerField(max_length=15)
    title = models.CharField(max_length=50)
    body = models.TextField()

我也有上述模型的模型形式,如下所示:

class JournalForm(ModelForm):
    tank = forms.IntegerField(widget=forms.HiddenInput()) 

    class Meta:
        model = TankJournal
        exclude = ('user','ts')

我想知道如何为该坦克隐藏字段设置默认值。这是我到目前为止显示/保存表格的功能:

def addJournal(request, id=0):
    if not request.user.is_authenticated():
        return HttpResponseRedirect('/')

    # checking if they own the tank
    from django.contrib.auth.models import User
    user = User.objects.get(pk=request.session['id'])

    if request.method == 'POST':
        form = JournalForm(request.POST)
        if form.is_valid():
            obj = form.save(commit=False)

            # setting the user and ts
            from time import time
            obj.ts = int(time())
            obj.user = user

            obj.tank = TankProfile.objects.get(pk=form.cleaned_data['tank_id'])

            # saving the test
            obj.save()

    else:
        form = JournalForm()

    try:
        tank = TankProfile.objects.get(user=user, id=id)
    except TankProfile.DoesNotExist:
        return HttpResponseRedirect('/error/')

I have a Model as follows:

class TankJournal(models.Model):
    user = models.ForeignKey(User)
    tank = models.ForeignKey(TankProfile)
    ts = models.IntegerField(max_length=15)
    title = models.CharField(max_length=50)
    body = models.TextField()

I also have a model form for the above model as follows:

class JournalForm(ModelForm):
    tank = forms.IntegerField(widget=forms.HiddenInput()) 

    class Meta:
        model = TankJournal
        exclude = ('user','ts')

I want to know how to set the default value for that tank hidden field. Here is my function to show/save the form so far:

def addJournal(request, id=0):
    if not request.user.is_authenticated():
        return HttpResponseRedirect('/')

    # checking if they own the tank
    from django.contrib.auth.models import User
    user = User.objects.get(pk=request.session['id'])

    if request.method == 'POST':
        form = JournalForm(request.POST)
        if form.is_valid():
            obj = form.save(commit=False)

            # setting the user and ts
            from time import time
            obj.ts = int(time())
            obj.user = user

            obj.tank = TankProfile.objects.get(pk=form.cleaned_data['tank_id'])

            # saving the test
            obj.save()

    else:
        form = JournalForm()

    try:
        tank = TankProfile.objects.get(user=user, id=id)
    except TankProfile.DoesNotExist:
        return HttpResponseRedirect('/error/')

回答 0

您可以使用初始被解释这里

您有两个选择,可以在调用表单构造函数时填充值:

form = JournalForm(initial={'tank': 123})

或在表单定义中设置值:

tank = forms.IntegerField(widget=forms.HiddenInput(), initial=123) 

You can use initial which is explained here

You have two options either populate the value when calling form constructor:

form = JournalForm(initial={'tank': 123})

or set the value in the form definition:

tank = forms.IntegerField(widget=forms.HiddenInput(), initial=123) 

回答 1

其他解决方案:创建表单后设置初始:

form.fields['tank'].initial = 123

Other solution: Set initial after creating the form:

form.fields['tank'].initial = 123

回答 2

如果要通过POST值创建模型形式,则可以通过以下方式分配初始值:

form = SomeModelForm(request.POST, initial={"option": "10"})

https://docs.djangoproject.com/en/1.10/topics/forms/modelforms/#providing-initial-values

If you are creating modelform from POST values initial can be assigned this way:

form = SomeModelForm(request.POST, initial={"option": "10"})

https://docs.djangoproject.com/en/1.10/topics/forms/modelforms/#providing-initial-values


回答 3

我有另一个解决方案(如果其他人正在使用该模型中的以下方法,我会发布它):

class onlyUserIsActiveField(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(onlyUserIsActiveField, self).__init__(*args, **kwargs)
        self.fields['is_active'].initial = False

    class Meta:
        model = User
        fields = ['is_active']
        labels = {'is_active': 'Is Active'}
        widgets = {
            'is_active': forms.CheckboxInput( attrs={
                            'class':          'form-control bootstrap-switch',
                            'data-size':      'mini',
                            'data-on-color':  'success',
                            'data-on-text':   'Active',
                            'data-off-color': 'danger',
                            'data-off-text':  'Inactive',
                            'name':           'is_active',

            })
        }

缩写在__init__函数上定义为self.fields['is_active'].initial = False

I had this other solution (I’m posting it in case someone else as me is using the following method from the model):

class onlyUserIsActiveField(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(onlyUserIsActiveField, self).__init__(*args, **kwargs)
        self.fields['is_active'].initial = False

    class Meta:
        model = User
        fields = ['is_active']
        labels = {'is_active': 'Is Active'}
        widgets = {
            'is_active': forms.CheckboxInput( attrs={
                            'class':          'form-control bootstrap-switch',
                            'data-size':      'mini',
                            'data-on-color':  'success',
                            'data-on-text':   'Active',
                            'data-off-color': 'danger',
                            'data-off-text':  'Inactive',
                            'name':           'is_active',

            })
        }

The initial is definded on the __init__ function as self.fields['is_active'].initial = False


回答 4

我希望这可以帮助您:

form.instance.updatedby = form.cleaned_data['updatedby'] = request.user.id

I hope this can help you:

form.instance.updatedby = form.cleaned_data['updatedby'] = request.user.id

回答 5

Django文档所述initial不是default

  • 字段的初始值打算在HTML中显示。但是,如果用户删除该值,并最终为此字段发送回空白值,则该initial值将丢失。因此,您不会获得默认行为所期望的结果。

  • 默认行为是:如果值验证过程将采取data说法不包含字段的任何值。

要实现这一点,一种简单的方法是将initial和结合起来clean_<field>()

class JournalForm(ModelForm):
    tank = forms.IntegerField(widget=forms.HiddenInput(), initial=123) 

    (...)

    def clean_tank(self):
        if not self['tank'].html_name in self.data:
            return self.fields['tank'].initial
        return self.cleaned_data['tank']

As explained in Django docs, initial is not default.

  • The initial value of a field is intended to be displayed in an HTML . But if the user delete this value, and finally send back a blank value for this field, the initial value is lost. So you do not obtain what is expected by a default behaviour.

  • The default behaviour is : the value that validation process will take if data argument do not contain any value for the field.

To implement that, a straightforward way is to combine initial and clean_<field>():

class JournalForm(ModelForm):
    tank = forms.IntegerField(widget=forms.HiddenInput(), initial=123) 

    (...)

    def clean_tank(self):
        if not self['tank'].html_name in self.data:
            return self.fields['tank'].initial
        return self.cleaned_data['tank']