假设我在Django中有两个Models
:
图书:
class Book(models.Model):
title = models.CharField(max_length=100, blank=False)
number_of_readers = models.PositiveIntegerField(default=0)
阅读器:
class Reader(models.Model):
book = models.ForeignKey(Book)
name_of_reader = models.CharField(max_length=100, blank=False)
每次我向数据库添加新的Reader
时,我希望将number_of_readers
模型中的Book
增加1.我不想动态计算行数{{1}出于性能原因,与特定Reader
相关的行。
哪里是增加Book
字段的最佳位置?在number_of_readers
或Serializer
?我应该使用什么方法?我应该覆盖Model
中的.save
吗?或Model
中的其他内容?
如果有人可以提供关于如何在发布新Serializer
的帖子时修改Book
表格的完整示例,那就更好了。
感谢。
答案 0 :(得分:4)
我不会在 REST API级别上执行此操作,我会在模型级别上执行此操作,因为此时+1增加将会总是发生,无论它发生在哪里(不仅在你点击特定的REST视图/序列化器时)
每当我向数据库添加一个新的Reader时,我想将Book模型中的number_of_readers增加1
我实施了一个post_save
信号,该信号在创建模型(Reader)时触发
该信号有一个名为created
的参数,在创建模型时为True
,这比Model.save()
覆盖
示例大纲
from django.db.models.signals import post_save
def my_callback(sender, instance, created, **kwargs):
if created:
reader = instance
book = reader.book
book.number_of_readers += 1 # prone to race condition, more on that below
book.save(update_fields='number_of_readers') # save the counter field only
post_save.connect(my_callback, sender=your.models.Reader)
https://docs.djangoproject.com/en/1.8/ref/signals/#django.db.models.signals.post_save
竞争条件
在上面的代码片段中,如果您想避免竞争条件(当许多线程更新同一个计数器时可能会发生这种情况),您也可以使用F表达式替换book.number_of_readers += 1
部分{{ 1}},它使数据库级别的读/写而不是Python,
F('number_of_readers') + 1
此处更多内容:https://docs.djangoproject.com/en/1.8/ref/models/expressions/#avoiding-race-conditions-using-f
如果您想要支持" unreading"还有一个book.number_of_readers = F('number_of_readers') + 1
book.save(update_fields='number_of_readers')
信号来反转计数器。一本书:)
如果您希望批量导入读者,或者需要定期更新(或"重排")读者计数(例如每周一次),您可以在上述之外,实现一个重新计算读者并更新post_delete
答案 1 :(得分:1)
这取决于您的应用程序的设计,特别是您将重用此逻辑的位置。
例如,如果您想在应用中的任何位置添加Reader
相同的逻辑,请在信号中执行,如bakkal建议或save
。如果它取决于API端点,您可能希望在视图中执行此操作。
这也取决于您是否正在批量插入读者:如果您在save
或pre_
/ post_save
中执行此操作,则无法进行批量更新,因此它会最好在QuerySet
create
和bulk_create
方法等中执行此操作。
从性能的角度来看,无论您在何处执行此操作,都可能需要使用F表达式:
book.number_of_readers = F('number_of_readers') + added_readers_count