[英]Redundant code in Django models.py. How do I improve it?
I am trying to create a task list with each task having a datetime attribute. 我试图创建一个任务列表,每个任务都有一个datetime属性。 The tasks needs to be in order with
t_created
being the first and t_paid
being last. 该任务必须以与
t_created
是第一和t_paid
是最后一次。 The order is shown in step_datetime
. 订单显示在
step_datetime
。 The description for each tasks is in STEPS
. 每个任务的描述在
STEPS
。
I currently have two methods all_steps
and next_step
that shows the task list information. 我目前有两种显示任务列表信息的方法
all_steps
和next_step
。 The two methods also need to display the name of the user_created
, but that variable won't be defined until the methods are called. 这两个方法还需要显示
user_created
的名称,但是在调用这些方法之前,不会定义该变量。 That's why I am doing a string replace
method. 这就是为什么我要执行字符串
replace
方法。
I feel like I am repeating my code a lot, and I want to follow the DRY principle of Django. 我觉得我在重复很多代码,我想遵循Django的DRY原则。 Is there any way I could improve this code?
有什么办法可以改善此代码?
Here is my full code: 这是我的完整代码:
class Order( models.Model ) :
def __unicode__( self ) :
return unicode( self.id )
def comments_count( self ) :
return OrderComment.objects.filter( order = self.id ).count()
def all_steps( self ) :
user = self.user_created.first_name
steps = []
step_datetime = [
self.t_created,
self.t_action,
self.t_followup_one,
self.t_vendor_appt_one,
self.t_vendor_appt_two,
self.t_work_done,
self.t_followup_two,
self.t_paid,
]
for ( i, step ) in enumerate( self.STEPS ) :
steps.append( ( step_datetime[ i ], step.replace( '<user_created>', user ), ) )
return steps
def next_step( self ) :
user = self.user_created.first_name
step = 0
if self.t_action is None :
step = 0
elif self.t_followup_one is None :
step = 1
elif self.t_vendor_appt_one is None :
step = 2
elif self.t_vendor_appt_two is None :
step = 3
elif self.t_work_done is None :
step = 4
elif self.t_followup_two is None :
step = 5
elif self.paid is None :
step = 6
return str( step ) + ": " + self.STEPS[ step ].replace( '<user_created>', user )
STEPS = [
"Review, then either approve or reject the order.",
"Follow up with <user_created>",
"Contact the vendor to get a quote and arrange an appointment for <user_created>.",
"Review the quote, (get owner approval), then arrange a second appointment for the repairs.",
"Confirm the finished repairs and pay the vendor.",
"Follow up again with <user_created>",
"Confirm payment and close the order.",
]
ACTION_CHOICES = (
( 'p', 'pending' ),
( 'a', 'approved' ),
( 'r', 'rejected' ),
( 'c', 'closed' ),
)
user_created = models.ForeignKey( User, related_name = 'user_created', verbose_name = 'created by' )
user_action = models.ForeignKey( User, related_name = 'user_status' , verbose_name = 'action by' , null = True, blank = True )
t_created = models.DateTimeField( auto_now_add = True, verbose_name = 'created' )
t_action = models.DateTimeField( null = True, blank = True, verbose_name = 'action' )
t_followup_one = models.DateTimeField( null = True, blank = True, verbose_name = 'first follow-up' )
t_vendor_appt_one = models.DateTimeField( null = True, blank = True, verbose_name = 'first appointment' )
t_vendor_appt_two = models.DateTimeField( null = True, blank = True, verbose_name = 'second appointment' )
t_work_done = models.DateTimeField( null = True, blank = True, verbose_name = 'work done' )
t_followup_two = models.DateTimeField( null = True, blank = True, verbose_name = 'second follow-up' )
t_paid = models.DateTimeField( null = True, blank = True, verbose_name = 'paid' )
action = models.CharField( max_length = 1, choices = ACTION_CHOICES, default = 'p' )
quote = models.DecimalField( max_digits = 8, decimal_places = 2, null = True, blank = True )
payment = models.DecimalField( max_digits = 8, decimal_places = 2, null = True, blank = True )
items = models.ManyToManyField( Item, null = True, blank = True )
t_modified = models.DateTimeField( auto_now = True, verbose_name = 'modified' )
After accepting @Dougal's answer . 接受@Dougal的回答后 。 I changed some of the variables around and came up with this:
我更改了一些变量,并提出了以下建议:
def all_steps( self ) :
user = self.user_created.first_name
return [
( getattr( self, attr ), task.format( user = user ) )
for ( attr, task ) in self.TASKS
]
def next_step( self ) :
user = self.user_created.first_name
task_num = next(
( i for ( i, ( attr, task ) ) in enumerate( self.TASKS ) if getattr( self, attr ) is None ),
None
)
if task_num == None :
return "Done!"
else:
return "{number}: {task}".format(
number = str( task_num + 1 ),
task = self.TASKS[ task_num ][ 1 ].format( user = user )
)
TASKS = (
( "t_action" , "Review, then either approve or reject the order." ),
( "t_followup_one" , "Follow up with {user}." ),
( "t_vendor_appt_one", "Contact the vendor to get a quote and arrange an appointment for {user}." ),
( "t_vendor_appt_two", "Review the quote, (get owner approval), then arrange a second appointment for the repairs." ),
( "t_work_done" , "Confirm the finished repairs and pay the vendor." ),
( "t_followup_two" , "Follow up again with {user}." ),
( "t_paid" , "Confirm payment and close the order." ),
)
You can do things like: 您可以执行以下操作:
for prop in ("t_created", "t_created2" ... ):
val = getattr(self, prop)
# some logic that works with that, maybe uses setattr
Adding on to @Marcin's answer : 添加到@Marcin的答案 :
You could make a tuple of the property names (say _STEP_NAMES
at the module level; you could also make it at the class level, like STEPS
, or even just combine the two into a tuple of pairs of attributes and names; that might be a little cleaner). 您可以对属性名称进行元组化(例如,在模块级别使用
_STEP_NAMES
;也可以在类级进行配置,例如STEPS
,甚至可以将二者组合成由属性和名称对组成的元组;这可能是一个小一点的清洁剂)。 Also, STEPS
should probably be a tuple, since it shouldn't be modifiable at runtime. 此外,
STEPS
可能应该是一个元组,因为它不应在运行时进行修改。
Then you can reduce your code to: 然后,您可以将代码简化为:
def all_steps(self):
user = self.user_created.first_name
return [(getattr(self, attr), step.replace('<user_created>', user))
for attr, step in zip(_STEP_NAMES, self.STEPS)]
def next_step(self):
user = self.user_created.first_name
step = next((i for i, attr in enumerate(_STEP_NAMES)
if getattr(self, attr) is None),
None) # assumes Python 2.6+
if step == None:
return "Done!"
else:
return str(step) + ": " + self.STEPS[step].replace('<user_created>', user)
If you need Python 2.4/2.5 compatability, the next
line can be replaced by 如果您需要Python 2.4 / 2.5兼容性,则
next
行可以替换为
try:
step = (i for i, attr in enumerate(_STEP_NAMES) if getattr(self, attr) is None).next()
except StopIteration:
return "Done!"
return str(step) + ": " + self.STEPS[step].replace('<user_created>', user)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.