Fre*_*son 42 python django django-forms
我正在为一支乐队的出勤报名表工作.我的想法是让表格的一部分输入表演或排练的事件信息.这是事件表的模型:
class Event(models.Model):
event_id = models.AutoField(primary_key=True)
date = models.DateField()
event_type = models.ForeignKey(EventType)
description = models.TextField()
Run Code Online (Sandbox Code Playgroud)
然后我想要一个内联FormSet,将乐队成员链接到事件并记录它们是否存在,缺席或原谅:
class Attendance(models.Model):
attendance_id = models.AutoField(primary_key=True)
event_id = models.ForeignKey(Event)
member_id = models.ForeignKey(Member)
attendance_type = models.ForeignKey(AttendanceType)
comment = models.TextField(blank=True)
Run Code Online (Sandbox Code Playgroud)
现在,我想做的是预先填充此内联FormSet,其中包含所有当前成员的条目,并默认它们存在(大约60个成员).不幸的是,Django 在这种情况下不允许初始值.
有什么建议?
Jam*_*ett 32
所以,你不会喜欢这个答案,部分是因为我还没有写完代码,部分原因是因为这是很多工作.
正如我自己遇到的那样,你需要做的是:
BaseInlineFormSet和接受initial.这里的真正棘手的一点是,你必须重写__init__(),你必须确保它可以调出来BaseFormSet.__init__(),而不是使用直接的父母或祖父母__init__()(因为这些是BaseInlineFormSet和BaseModelFormSet,分别和他们都没有能够处理原始数据).TabularInline),并覆盖其get_formset方法以返回inlineformset_factory()使用自定义formset类的结果.ModelAdmin具有内联,覆盖add_view和模拟change_view大多数代码的模型的实际子类上,但有一个重大变化:构建formset所需的初始数据,并将其传递给您的自定义formset(将由您返回ModelAdmin的get_formsets()方法).我与Brian和Joseph就未来的Django版本进行了一些有关改进的讨论.目前,模型表单的工作方式只会使它比通常值得更麻烦,但是通过一些API清理,我认为它可以变得非常简单.
Eri*_*ulf 20
我花了相当多的时间尝试提出一个可以跨站点重用的解决方案.詹姆斯的帖子包含了扩展BaseInlineFormSet但战略性地援引呼叫的关键智慧BaseFormSet.
下面的解决方案分为两部分:a AdminInline和a BaseInlineFormSet.
InlineAdmin动态地生成基于暴露的请求对象的初始值.BaseInlineFormSet传递给构造函数的自定义关键字参数.BaseInlineFormSet构造弹出关闭的关键字参数和结构正常列表中的初始值.BaseFormSet._construct_form和BaseFormSet._construct_forms方法来覆盖表单构造过程以下是使用OP类的一些具体代码段.我已经针对Django 1.2.3进行了测试.我强烈建议在开发时保留formset和admin文档.
admin.py
from django.utils.functional import curry
from django.contrib import admin
from example_app.forms import *
from example_app.models import *
class AttendanceInline(admin.TabularInline):
model = Attendance
formset = AttendanceFormSet
extra = 5
def get_formset(self, request, obj=None, **kwargs):
"""
Pre-populating formset using GET params
"""
initial = []
if request.method == "GET":
#
# Populate initial based on request
#
initial.append({
'foo': 'bar',
})
formset = super(AttendanceInline, self).get_formset(request, obj, **kwargs)
formset.__init__ = curry(formset.__init__, initial=initial)
return formset
Run Code Online (Sandbox Code Playgroud)
forms.py
from django.forms import formsets
from django.forms.models import BaseInlineFormSet
class BaseAttendanceFormSet(BaseInlineFormSet):
def __init__(self, *args, **kwargs):
"""
Grabs the curried initial values and stores them into a 'private'
variable. Note: the use of self.__initial is important, using
self.initial or self._initial will be erased by a parent class
"""
self.__initial = kwargs.pop('initial', [])
super(BaseAttendanceFormSet, self).__init__(*args, **kwargs)
def total_form_count(self):
return len(self.__initial) + self.extra
def _construct_forms(self):
return formsets.BaseFormSet._construct_forms(self)
def _construct_form(self, i, **kwargs):
if self.__initial:
try:
kwargs['initial'] = self.__initial[i]
except IndexError:
pass
return formsets.BaseFormSet._construct_form(self, i, **kwargs)
AttendanceFormSet = formsets.formset_factory(AttendanceForm, formset=BaseAttendanceFormSet)
Run Code Online (Sandbox Code Playgroud)
rui*_*eal 16
Django 1.4及更高版本支持提供初始值.
就原始问题而言,以下内容可行:
class AttendanceFormSet(models.BaseInlineFormSet):
def __init__(self, *args, **kwargs):
super(AttendanceFormSet, self).__init__(*args, **kwargs)
# Check that the data doesn't already exist
if not kwargs['instance'].member_id_set.filter(# some criteria):
initial = []
initial.append({}) # Fill in with some data
self.initial = initial
# Make enough extra formsets to hold initial forms
self.extra += len(initial)
Run Code Online (Sandbox Code Playgroud)
如果您发现表单正在填充但未保存,那么您可能需要自定义模型表单.一种简单的方法是在初始数据中传递标记并以init形式查找它:
class AttendanceForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(AttendanceForm, self).__init__(*args, **kwargs)
# If the form was prepopulated from default data (and has the
# appropriate tag set), then manually set the changed data
# so later model saving code is activated when calling
# has_changed().
initial = kwargs.get('initial')
if initial:
self._changed_data = initial.copy()
class Meta:
model = Attendance
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
18178 次 |
| 最近记录: |