如何设置模型装饰器(在Django中)以计算ManyToManyFields(以及其他可验证的条件)?
Django模型:
class Cake(models.Model):
cake_layer = models.ManyToManyField(CakeLayer, related_name="cake_layer")
cream_layer = models.ManyToManyField(CreamLayer, related_name="cream_layer")
@property
def at_least_one_cake_layer(self):
if self.cake_layer_set.count = 0:
raise AssertionError("At last one cake layer is needed to be a cake")
@property
def at_least_two_layers(self):
total_layer_count = 0
total_layer_count += self.cream_layer_set.count
total_layer_count += self.cream_layer_set.count
if total_layer_count <= 1:
raise AssertionError("A proper Cake needs two layers, even if they are just two cake layers!")
就像在模型本身中进行查询一样简单吗? (我只是在模板和视图中使用查询,并且不确定如果是另一个模型,如何正确(如果有的话)正确访问模型的属性。
请注意:如果此代码有效,请告诉我,但是您知道我来自哪里:
pythonic
还是好的架构相关课程请随意阐明我的假设:)谢谢!
答案 0 :(得分:1)
一些明显的错误和一些改进建议:
class Cake(models.Model):
# 1. change related_name to sth that makes semantic sense!
# I'd also suggest plural names for m2m fields. Makes code more readable.
cake_layers = models.ManyToManyField(CakeLayer, related_name="cakes")
cream_layers = models.ManyToManyField(CreamLayer, related_name="cakes")
def at_least_one_cake_layer(self):
# 2. no _set suffix with forward m2m rels, just use the name of the field
# 3. count is a method, needs parentheses to be actually called
# 4. "=" is an assignment, use "==" for comparisons
if self.cake_layers.count() == 0:
raise AssertionError("At last one cake layer is needed to be a cake")
# 5. a property suggests to the caller that they are accessing a simple attribute which
# imho should not raise an exception. A boolean return value seems better.
# if you want to raise an error, I'd keep it a method.
@property
def at_least_two_layers(self):
# 6. seems you mean to add both counts here, so one should be cake_layers
# minor: adding two ints should not deserve 3 lines of code
total_layer_count = self.cake_layers.count() + self.cream_layers.count()
if total_layer_count < 2:
# minor: make code match output ;)
# even if <=1 and <2 are equivalent here, it is just good practice
# and you avoid pitfalls in more complicated cases, e.g. with floats
raise AssertionError("A proper Cake needs two layers, even if they are just two cake layers!")
就装饰器而言,它们只是应用于装饰的函数/类对象的普通Python函数,并且与其他任何函数(例如,作用域)都受到相同的限制。您想对它们做什么是有意义的还是Pythonic取决于具体情况。
您可以在装饰器中执行数据库操作,但将其限制为装饰器返回的功能。当模块可能尚未加载时,装饰器函数本身(在大多数情况下,例如函数内部的类定义除外)将在模块加载时调用。您应该避免模块级代码中的数据库命中。
此外,您正在使用count()
检查是否存在。不使用实际数字时,请使用性能更高的exists()
:
if not self.cake_layers.exists():
# raise hell / return False
if not (self.cake_layers.exists() and self.cream_layers.exists()):
# raise hell / return False