python - 试图将模型表单中的非模型字段设置为模型中存在的其他字段
问题描述
我有一个表单,我需要添加一个额外的字段 - 它需要具有数据模型时间字段的初始值(称为 seg_length_time)。我没想到代码可以工作,因为我知道我需要将时间转换为模型中的字符串,但我似乎无法弄清楚如何设置字段开头。当前代码返回错误“SegmentForm”对象没有属性“pk”。我已经尝试过 id 和其他一些东西,但没有正确引用特定对象。例如 - 我试过 Segemt.object.values('seg_length_time') 但后来我得到了所有的 seg_length_time 密钥对。
请参阅下面的 forms.py 代码:
import re
from datetime import datetime,timedelta
class SegmentForm(forms.ModelForm):
str_seg_length_time = forms.CharField(max_length=8)
class Meta:
model = Segment
exclude = ('seg_length_time_delta',
#'seg_length_time',
'seg_run_time',
'seg_run_time_delta' ,
'seg_remaining_time',
'seg_remaining_time_delta',
'program_id',
'audit_user',
)
def __init__(self, *args, **kwargs):
obj = Segment.objects.get(id=self.instance.pk)
self.fields['str_seg_length_time'] = obj.seg_length_time
super().__init__(*args, **kwargs)
def clean_str_seg_length_time(self):
str_seg_time = self.cleaned_data['str_seg_length_time']
if (re.search("[^\d:]", str_seg_time) ): # check that only digits and : are in our time string
raise ValidationError("Segment Time: There are illegal characters in segment time. Valid format:[HH:MM:SS].")
if (re.search(".*:.*:.*:.*", str_seg_time) ): # check for more than two : signs
raise ValidationError("Segment Time: There are too many colons. Valid format:[HH:MM:SS].")
if ( re.search("^\d+$", str_seg_time) ): # time defaults to minutes if not specified
str_seg_time = "00:" + str_seg_time + ":00"
if ( re.search("^\d*:\d*$", str_seg_time) ): # time defaults to minutes/seconds if not specified
str_seg_time = "00:" + str_seg_time
try:
t = datetime.strptime(str_seg_time,"%H:%M:%S")
except:
raise ValidationError('Segment Time : Could not convert time to HH:MM:SS - Invalid Time')
self.seg_length_time = t
return str_seg_time
def form_valid(self, form):
form.instance.audit_user = self.request.user
return super().form_valid(form)
model.py 如下:
from django.db import models
from django.urls import reverse
from datetime import datetime, timedelta
class Program(models.Model):
air_date = models.DateField(default="0000-00-00")
air_time = models.TimeField(default="00:00:00")
service = models.CharField(max_length=10)
block_time = models.TimeField(default="00:00:00")
block_time_delta = models.DurationField(default=timedelta)
running_time = models.TimeField(default="00:00:00",blank=True)
running_time_delta = models.DurationField(default=timedelta)
remaining_time = models.TimeField(default="00:00:00",blank=True)
remaining_time_delta = models.DurationField(default=timedelta)
title = models.CharField(max_length=190)
locked_flag = models.BooleanField(default=False)
deleted_flag = models.BooleanField(default=False)
library = models.CharField(null=True,max_length=190,blank=True)
mc = models.CharField(null=True,max_length=64)
producer = models.CharField(null=True,max_length=64)
editor = models.CharField(null=True,max_length=64)
remarks = models.TextField(null=True,blank=True)
audit_time = models.DateTimeField(auto_now=True)
audit_user = models.CharField(null=True,max_length=32)
def convert_to_delta(self,time_in):
#print("Lengthof time_in = %s" % len(time_in))
hold_time = time_in.strftime("%H:%M:%S")
t = datetime.strptime(hold_time,"%H:%M:%S")
return(timedelta(hours=t.hour, minutes=t.minute, seconds=t.second))
def calculate_time(self):
block_time_delta = self.convert_to_delta(self.block_time)
total_run_time_delta = timedelta(minutes=0)
for segs in self.segments.all():
total_run_time_delta += segs.seg_length_time_delta
segs.seg_run_time_delta = total_run_time_delta
segs.seg_run_time = f"{segs.seg_run_time_delta}"
segs.seg_remaining_time_delta = block_time_delta - total_run_time_delta
segs.seg_remaining_time = f"{abs(segs.seg_remaining_time_delta)}"
super(Segment,segs).save()
self.running_time_delta = total_run_time_delta
self.running_time = f"{self.running_time_delta}"
self.remaining_time_delta = self.block_time_delta - total_run_time_delta
self.remaining_time = f"{abs(self.remaining_time_delta)}"
def calculate_sequence(self):
for index,segs in enumerate(self.segments.all(),1):
segs.sequence_number = index
super(Segment,segs).save()
def save(self, *args, **kwargs):
self.calculate_sequence()
self.calculate_time()
super().save(*args,**kwargs)
def __str__(self):
return f"{self.pk} : {self.title}"
def get_absolute_url(self):
#return reverse('program_detail', args=[str(self.id)])
return reverse('program-detail', kwargs={'pk': self.pk})
class Segment(models.Model):
class Meta:
ordering = ['sequence_number']
program_id = models.ForeignKey(Program,
on_delete=models.CASCADE,
related_name='segments', # link to Program
)
sequence_number = models.DecimalField(decimal_places=2,max_digits=6,default="0.00")
title = models.CharField(max_length=190)
bridge_flag = models.BooleanField(default=False)
seg_length_time = models.TimeField(null=True,default=None, blank=True)
seg_length_time_delta = models.DurationField(default=timedelta)
seg_run_time = models.TimeField(default="00:00:00",blank=True)
seg_run_time_delta = models.DurationField(default=timedelta)
seg_remaining_time = models.TimeField(default="00:00:00",blank=True)
seg_remaining_time_delta = models.DurationField(default=timedelta)
author = models.CharField(max_length=64,null=True,default=None,blank=True)
voice = models.CharField(max_length=64,null=True,default=None,blank=True)
library = models.CharField(max_length=190,null=True,default=None,blank=True)
summary = models.TextField()
audit_time = models.DateTimeField(auto_now=True)
audit_user = models.CharField(null=True,max_length=32)
def save(self, *args, **kwargs):
self.seg_length_time_delta =
self.program_id.convert_to_delta(self.seg_length_time)
super().save(*args,**kwargs)
self.program_id.save()
def get_absolute_url(self):
return reverse('program_detail', kwargs={'pk': self.program_id.pk} )
def save( self, *args, **kwargs):
super().save(*args,**kwargs)
self.program_id.save()
def __str__(self):
return f"{self.title}"
视图如下:
class ProgramMixView(LoginRequiredMixin,UpdateView):
model = Segment
template_name = 'program_mix_view.html'
form_class = SegmentForm
context_object_name = 'program_edit'
def get_context_data(self, **kwargs):
context = super(ProgramMixView,self).get_context_data(**kwargs)
cur_segment = Segment.objects.get(id=self.kwargs['pk'])
context['program_info'] = Program.objects.get(id=cur_segment.program_id.pk)
return context
class SegmentCreateView(LoginRequiredMixin,CreateView):
model = Program
template_name = 'segment_create_view.html'
form_class = SegmentForm
context_object_name = 'program_seg_create'
而实际的模板 program_mix_template.html
{% if program_info %}
<TABLE ID="pro-table" WIDTH="100%">
<!-- <TABLE BORDER="0" TABLE_LAYOUT="fixed" WIDTH="100%"> -->
<TR BGCOLOR="#15C1B5">
<TD ALIGN="Right">Program Title:</TD><TD ALIGN="Left">{{ program_info.title|truncatechars:30 }}</TD>
<TD ALIGN="Right">Library:</TD><TD ALIGN="Left"> {{ program_info.library }}</TD>
<TD ALIGN="Right">Service Bureau:</TD><TD ALIGN="Left"> {{ program_info.service }}</TD>
</TR>
<TR BGCOLOR="#15C1B5">
<TD ALIGN="Right">Program Id:</TD><TD ALIGN="Left"> {{ program_info.pk }}</TD>
<TD ALIGN="Right">Air Date:</TD><TD ALIGN="Left"> {{ program_info.air_date }}</TD>
<TD ALIGN="Right">Air Time</TD><TD ALIGN="Left"> {{ program_info.air_time|time:"H:i:s" }}</TD>
</TR>
<TR BGCOLOR="#15C1B5">
<TD ALIGN="Right">Producer:</TD><TD ALIGN="Left"> {{ program_info.producer }}</TD>
<TD ALIGN="Right">Editor:</TD><TD ALIGN="Left"> {{ program_info.editor }}</TD>
<TD ALIGN="Right">MC:</TD><TD ALIGN="Left"> {{ program_info.mc }}</TD>
</TR>
<TR BGCOLOR="#15C1B5">
<TD BGCOLOR="#99CCFF" ALIGN="Right">Duration:</TD>
<TD BGCOLOR="#99CCFF" ALIGN="Left"> {{ program_info.block_time|time:"H:i:s" }}</TD>
<TD BGCOLOR="#8DF1BF" ALIGN="Right">Rem. Time:</TD>
<TD BGCOLOR="#8DF1BF" ALIGN="Left"> {{ program_info.remaining_time|time:"H:i:s" }}</TD>
<TD BGCOLOR="#CC99CC" ALIGN="Right">Run Time:</TD>
<TD BGCOLOR="#CC99CC" ALIGN="Left"> {{ program_info.running_time|time:"H:i:s" }}</TD>
</TR>
<TR BGCOLOR="#15C1B5">
<TD ALIGN="Right">Remarks:</TD><TD ALIGN="Left" COLSPAN="5"><PRE>{{ program_info.remarks|truncatechars:180 }}</TD>
</PRE></TD>
</TR>
</TABLE>
{% if program_info.segments.all %}
<TABLE BORDER="0" TABLE_LAYOUT="fixed" WIDTH="100%">
<TR BGCOLOR="#B0B0FF">
<TD ALIGN="Center"> #</TD>
<TD ALIGN="Center">Segment Title</TD>
<TD ALIGN="Center">Summary</TD>
<TD ALIGN="Center">Library</TD>
<TD ALIGN="Center">Author</TD>
<TD ALIGN="Center">Voice</TD>
<TD ALIGN="Center">Segment time</TD>
<TD BGCOLOR="#CC99CC" ALIGN="Center">Run time</TD>
<TD BGCOLOR="#8DF1BF" ALIGN="Center">Rem. time</TD>
</TR>
{% for segments in program_info.segments.all %}
{% if program_edit.pk == segments.id %}
<form method="post" action="">
{% csrf_token %}
<TR BGCOLOR="#B0B0FF">
<TD ALIGN="Left" VALIGN="Top" WIDTH="35">{{ form.sequence_number }}</TD>
<TD ALIGN="Left" VALIGN="Top">{{ form.title }}</TD>
<TD ALIGN="Left" VALIGN="Top"><PRE>{{ form.summary }}</PRE></TD>
<TD ALIGN="Left" VALIGN="Top">{{ form.library }}</TD>
<TD ALIGN="Left" VALIGN="Top">{{ form.author }}</TD>
<TD ALIGN="Left" VALIGN="Top">{{ form.voice }}</TD>
<TD ALIGN="CENTER" VALIGN="Top" WIDTH="10">{{ form.str_seg_length_time }}</TD>
</TR>
<TR>
<td><input type="submit" Value="Update"></td>
</tr>
</form>
{% if form.errors %}
<!-- Error messaging -->
<div id="errors">
<div class="inner">
<p>There were some errors in the information you entered. Please correct the following:</p>
<ul>
{% for field in form %}
{% if field.errors %}
<li> {{ field.errors|striptags }}</li><br>
{% endif %}
{% endfor %}
</ul>
</div>
</div>
{% endif %}
{% else %}
<tr BGCOLOR="#B0B0FF">
<TD ALIGN="Left" VALIGN="Top" WIDTH="35">{{ segments.sequence_number }}</TD>
<TD ALIGN="Left" VALIGN="Top">{{ segments.title }}</TD>
<TD ALIGN="Left" VALIGN="Top"><PRE>{{ segments.summary|truncatechars:40 }}</PRE></TD>
<TD ALIGN="Left" VALIGN="Top">{{ segments.library }}</TD>
<TD ALIGN="Left" VALIGN="Top">{{ segments.author }}</TD>
<TD ALIGN="Left" VALIGN="Top">{{ segments.voice }}</TD>
<TD ALIGN="CENTER" VALIGN="Top" WIDTH="10">{{ segments.seg_length_time|time:"H:i:s" }}</TD>
<TD BGCOLOR="#CC99CC" ALIGN="CENTER" VALIGN="Top" WIDTH="10">{{ segments.seg_run_time|time:"H:i:s" }}</TD>
<TD BGCOLOR="#8DF1BF" ALIGN="CENTER" VALIGN="Top" WIDTH="10">{{ segments.seg_remaining_time|time:"H:i:s" }}</TD>
</TR>
{% endif %}
{% endfor %}
</TABLE>
{% else %}
No Segments
{% endif %}
{% endif %}
如果我不执行某种初始代码从模型中设置它,则字段 (str_seg_length_time) 在表单上显示为空(空白)。我可以通过 id 获取对象,还是在初始化时我已经在表单中没有对象?我假设我需要进行某种 strfdatetime() 调用才能将其转换为字符串,但我不知道如何从模型中获取 seg_length_time 以开始...
谢谢。(PS 我不只是将模型中的字段放入表单中,因为我正在尝试更改处理输入的默认时间的方式(默认为 HH:MM - 我需要默认为 mm:ss 或 Minutes),即 05 :00 应该是 5 分钟,而不是 5 小时)...
解决方案
您的 forms__init__
方法写为:
def __init__(self, *args, **kwargs):
obj = Segment.objects.get(id=self.instance.pk)
self.fields['str_seg_length_time'] = obj.seg_length_time
super().__init__(*args, **kwargs)
让我们注意这里的问题。首先obj = Segment.objects.get(id=self.instance.pk)
,我可以看到您在 a 中使用了相同的形式CreateView
,显然,当尚未创建实例时,它将没有主键,从而给您一个错误。其次self.fields['str_seg_length_time']
,这会给你一个错误,因为你在调用 this之前调用thissuper().__init__
是什么是初始化self.fields
的。第三= obj.seg_length_time
,你到底想在这里做什么?是否要设置字段的初始值?因为当前您将声明的字段替换为此值。
解决办法是什么?看来您只是想为该字段提供一个初始值,您不需要为了这个简单的目的而覆盖__init__
。更进一步,您只想要自定义格式的输入?无需为此做所有这些,您只需将input_formats
[Django docs] kwarg 传递给该字段即可。将按顺序尝试此列表中的格式,并使用第一个匹配的格式:
class SegmentForm(forms.ModelForm):
seg_length_time = forms.TimeField(input_formats=['%H:%M:%S', '%M:%S', '%M']) # Set custom formats here
class Meta:
model = Segment
exclude = ('seg_length_time_delta',
# 'seg_length_time',
'seg_run_time',
'seg_run_time_delta' ,
'seg_remaining_time',
'seg_remaining_time_delta',
'program_id',
'audit_user',
)
如果您想在默认情况下为所有时间字段使用一些自定义格式怎么办?只需在以下位置TIME_INPUT_FORMATS
设置设置 [Django docs]settings.py
:
TIME_INPUT_FORMATS = [
'%H:%M:%S',
'%M:%S',
'%M'
]
推荐阅读
- c# - 以记忆友好的方式旋转图像
- azure - Azure 中的 CloudQueueMessage QueueTrigger 与本地实例
- powershell - ADGroup 中具有直接下属的用户
- python - 如何获取更多数据
- azure - 用于多个 Web 应用的 Azure 流量管理器
- myeclipse - 无法修改 MyEclipse 中的某些设置
- github - Taiga webhook 在 Github 中返回了无效的 Json,但它似乎有效?
- javascript - 如果它在函数内部,则无法存储在 Firebase 内部
- javascript - 点击需要click elementbyid
- html - 如何创建具有正确缩进的自定义 HTML li 点