由于我是Django的新手,我在这里要求对Django中进行非规范化的最佳实践提出一些建议。按照我的意见,我正在考虑做这样的事情:
我有2个型号:
类别:
name = m.CharField(max_length = 127)
文章:
name = m.CharField(max_length = 127)
category = m.ForeignKey(Category)
category_name = m.CharField(max_length = 127)
我希望这种情况发生:
当我更改任何类别的名称以反映所有文章中的更改时。现在,当我们没有一个或两个字段但大约10-20个字段保持同步时,最佳做法是什么?
感谢您的帮助(:
答案 0 :(得分:5)
如果您遇到性能问题,我建议使用关系并使用非正规化
过早优化是万恶之源。
关系数据库擅长连接,因为基本上就是它们的设计目的。在您想要的非规范化设计中,您需要复杂的JOINs
,而不是最简单的UPDATEs
。这些更新将影响许多(10-20)表中的许多行。如果受影响的表中有大量数据并且经常更改category_name,它甚至会使性能变差。
如果您真的坚持在10-20个表中使用category_name
的想法,请考虑使用database trigger。更改类别表时将执行触发器。它可以在数据库内部处理所有更新。无需更改Django项目中的任何内容,而且开销较小。
因此,如果你真的坚持在10-20个表中使用category_name
并且不能使用触发器,那么在Django中就会有一个名为signals的机制。这些是嵌入Django并在定义事件之前/之后触发的触发器。
from django.db.models import signals
from django.core.exceptions import DatabaseError
class Category(m.Model):
def __init__(self, *args, **kwargs):
super(Category, self).__init__(*args, **kwargs)
# Store the initial name
self._name = self.name
name = m.CharField(max_length = 127)
def update_category_name(sender, instance, **kwargs):
""" Callback executed when Category is about to be saved """
old_category = instance._name
new_category = instance.name
if old_category != new_category: # Name changed
# Start a transaction ?
try:
# Update the data:
# Make category_name an db_index, otherwise it will be slooooooooow
Article.objects.filter(category_name=old_category).update(category_name=new_category)
# commit transaction ?
except DatabaseError as e:
# rollback transaction ?
# prevent saving the category as database will be inconsistent
raise e
# Bind the callback to pre_save singal
signals.pre_save.connect(update_category_name, sender=Category)