【问题标题】:Django ManyToMany Validation and SaveDjango 多对多验证和保存
【发布时间】:2012-03-29 20:48:44
【问题描述】:

我正在为客户制定请假申请表。员工填写的表格允许员工选择他/她想要休假的多个日期。当员工最初查看表单时,仅显示一个日期条目。他们可以通过单击添加按钮动态添加更多日期(javascript)。

数据库设置:Form_Table、Date_Table、Form_Date_ManyToMany 表(由 Django 生成)

我对 Django 有 2 个问题。

1) 如果员工输入 3 个日期,每个日期字段将具有相同的名称。如何使用 Django 的 Form 或 ModelForm 验证每个字段?这是日期字段的示例。

<input name="dates[]" />
<!-- or -->
<input name="dates" /> <!-- I have read this is the Django way -->

2) 在我的数据库中,我与表单和日期之间存在多对多关系。我确信我需要 ManyToMany 而不仅仅是一个 ForeignKey 来跟踪更改(这不是问题)。如何使用 Django 保存多个日期(在日期表中)并与表单(在表单表中)建立多对多关系?

我对 Python 和 Django 比较陌生。我从 PHP 切换,因为 Django 是我发现的最好的框架。

编辑:我想我没有问正确的问题。这里有更多信息。

# Model
class Date(models.Model):
    date = models.DateField()
    emp_requested = models.ForeignKey(EmployeeRequested,null=True)
    hr_approved = models.ForeignKey(HumanResourcesApproved,null=True)

class Form(models.Model):
    pay_period = models.ForeignKey(PayPeriod)
    employee = models.ForeignKey(Employee)
    ack_ip = models.CharField(max_length=15, default='') 
    emp_signature = models.CharField(max_length=100)
    date_of_hire = models.DateField()
    state = models.ForeignKey(State)
    scheduler = models.ForeignKey(Scheduler)
    scheduler_form = models.ManyToManyField(SchedulerForm)
    hr_status = models.CharField(max_length=100, default='')
    created = models.DateTimeField(auto_now_add=True)
    modified = models.DateTimeField(auto_now=True)
    enabled = models.BooleanField(default=True)
    parent = models.ForeignKey('self',related_name='+')
    root  = models.ForeignKey('self',related_name='+')
    dates = models.ManyToManyField(Date)

# View - this is an ajax call 
def ajax_save_form(request):
    form = EmployeeForm(request.POST or None)
    return HttpResponse(form.is_valid())

# Form
class EmployeeForm(forms.ModelForm):
    employee_name = forms.CharField(max_length=30)
    employee_email = forms.EmailField()
    county = forms.ModelChoiceField(queryset=County.objects.all())
    job_type = forms.ModelChoiceField(queryset=JobType.objects.all())
    pay_period = forms.CharField()
    total_hours = forms.DecimalField()

    class Meta:
            model = Form
            exclude = ( 'employee', 'ack_ip', 'state', 'scheduler', 'scheduler_form', 'hr_status', 'parent', 'root', 'dates',)

# HTML (template)
<!-- Stuff -->
<div id="date-group" class="control-group date-controls">
    <label class="control-label" for="date">Date</label>
    <div class="controls">
        <div class="input-append">
            <input type="text" placeholder="Click to see Calendar"  name="dates[]" class="input-xlarge emp-dates" id="date">
            <span class="add-on"><i class="icon-calendar"></i></span> 
            &nbsp;&nbsp;
            <a id="AddDateBtn" class="btn btn-primary"><i class="icon-plus icon-white"></i> Add additional day</a>
            <br><br>
        </div>
        <div class="pull-left sub-controls">
            <h4>Employee Section</h4>
            <div class="well">
                Reason for Absence:<br>
                <select name="reasons[]" class="emp-reasons">
                    {% for reason in reasons %}
                    <option value="{{ reason.id }}">{{ reason.reason }}</option>
                    {% endfor %}
                </select>
                <span class="add-on emp-reason-help"><i class="icon-question-sign"></i></span> 
                <br><br>
                Hours: <br>
                <select name="hours[]">
                    {% for hour in hours %}
                    <option value="{{ hour }}">{{ hour }}</option>
                    {% endfor %}
                </select>
                <br><br>
                Explanation Required:<br>
                <textarea class="input-xlarge" name="explanations[]"></textarea>
            </div>
        </div>
    </div>
</div>
<!-- Stuff -->

员工可以拥有任意数量的 HTML 块。使用 JavaScript,我动态地“复制”了上面显示的 html。这允许员工提交多个日期(日期[]、小时[]、原因[]、解释[])。我需要在日期模型中保存每个日期组(日期[i]、小时[i]、原因[i]、解释[i])。然后我需要与表单模型和所有提交的日期建立多对多关系。如何使用 ModelForm 做到这一点。

我在网上看到一些代码表明可以这样做:

form = EmployeeForm()
if form.is_valid():
    # do relationships here

我也不知道如何使用 Django 获取日期 []、小时 []、原因 [] 和解释 [] 中的值。

【问题讨论】:

    标签: python django many-to-many forms django-validation


    【解决方案1】:

    如果您确实需要将这些日期存储在具有 ManyToMany 关系的单独表中,那么您应该稍微扩展您的 ModelForm。
    首先,为你的 dates 字段指定类,它应该继承自 django.forms.ModelMultipleChoiceField。在其中,覆盖 clean 函数,并在那里创建所有 Date 对象。该函数应返回已创建对象的 id 列表(或考虑返回 parent 的 clean 函数的结果,将这个 id 列表传递给它)。然后在您的 ModelForm 中,您只需指定该字段属于您的新类,然后所有验证和保存都将起作用。
    希望它会有所帮助;如果我不清楚,请询问更多:)

    【讨论】:

    • 这听起来是个不错的解决方案。在深入研究代码之前,对于需要保存的每个日期,我还有一个单独的小时输入字段 (name="hours[]"),它将与日期保存在同一个表中。我可以访问扩展 ModelMultipleChoiceField 的日期类中的小时字段吗?
    • 这改变了它。如果您需要访问从浏览器传递的其他信息,您最好定义方法 clean_dates (或模型中命名的任何日期字段),并在其中保存日期对象。到那时,您将拥有 self.cleaned_data 中的所有值。因此,您创建对象,将cleaned_data['dates'] 设置为它们的ID 列表并返回整个cleaned_data。我现在没有时间尝试,但是如果 html 中的日期字段的名称与模型中的名称相同,您可能会收到错误 - 然后如果将调用该字段的 clean 方法,它可能是错误,
    • 我不确定。如果是这样,只需重命名 html 字段 - 您仍然在 clean_dates 方法中组装日期对象。是的,我忘了提,该方法应该在您的表单类中。然后你就不需要该字段的特殊类了。
    • 我尝试了您的建议,但没有成功。我在编辑中添加了我的代码。它可能会帮助您更好地理解我在做什么(对或错)。
    • 我看不出你到底尝试了什么,但无论如何。长话短说,最简单的方法就是重写 EmployeeForm 的整个 clean 方法。首先,调用父方法:cleaned_data = super(EmployeeForm, self).clean()。然后创建日期对象,保存它们并分配 cleaned_data['dates'] id 列表。最后,返回cleaned_data。从视图传递的所有信息都在 self.data 中可用。如果你做得对,这肯定会奏效。请注意,m2m 关系只有在您保存表单对象后才会真正设置。
    猜你喜欢
    • 1970-01-01
    • 2011-12-20
    • 2018-07-11
    • 2015-07-02
    • 1970-01-01
    • 2011-04-15
    • 2014-02-26
    • 2012-07-01
    • 2017-12-16
    相关资源
    最近更新 更多