在django中使用观察者模式的问题
我正在一个销售产品的网站上工作(一类销售,一类产品)。每当我销售产品时,我都想将该操作保存在历史表中,并且我决定使用观察者模式来执行此操作。
也就是说:我的 Sales 类是主题,History 类是观察者,每当我调用 Sales 类的 save_sale() 方法时,我都会通知观察者。 (我决定使用这种模式,因为稍后我还会发送电子邮件,通知管理员等)
这是我的主题类(销售类由此扩展)
class Subject:
_observers = []
def attach(self, observer):
if not observer in self._observers:
self._observers.append(observer)
def detach(self, observer):
try:
self._observers.remove(observer)
except ValueError:
pass
def notify(self,**kargs):
for observer in self._observers:
observer.update(self,**kargs)
在视图上我做了这样的事情
sale = Sale()
sale.user = request.user
sale.product = product
h = History() #here I create the observer
sale.attach(h) #here I add the observer to the subject class
sale.save_sale() #inside this class I will call the notify() method
这是历史记录的更新方法
def update(self,subject,**kargs):
self.action = "sale"
self.username = subject.user.username
self.total = subject.product.total
self.save(force_insert=True)
第一次工作正常,但是当我尝试进行另一次销售时,我收到一条错误消息,说由于主键约束,我无法插入历史记录。
我的猜测是,当我第二次调用视图时,第一个观察者仍在主题类中,现在我有两个历史观察者正在监听销售,但我不确定这是否是问题所在(天哪,我错过了来自 php 的 print_r)。
我做错了什么?我什么时候必须“附加”观察者?或者有更好的方法吗?
顺便说一句:我使用的是 Django 1.1,我无权安装任何插件。
I'm working on a website where I sell products (one class Sale, one class Product). Whenever I sell a product, I want to save that action in a History table and I have decided to use the observer pattern to do this.
That is: my class Sales is the subject and the History class is the observer, whenever I call the save_sale() method of the Sales class I will notify the observers. (I've decided to use this pattern because later I'll also send an email, notify the admin, etc.)
This is my subject class (the Sales class extends from this)
class Subject:
_observers = []
def attach(self, observer):
if not observer in self._observers:
self._observers.append(observer)
def detach(self, observer):
try:
self._observers.remove(observer)
except ValueError:
pass
def notify(self,**kargs):
for observer in self._observers:
observer.update(self,**kargs)
on the view I do something like this
sale = Sale()
sale.user = request.user
sale.product = product
h = History() #here I create the observer
sale.attach(h) #here I add the observer to the subject class
sale.save_sale() #inside this class I will call the notify() method
This is the update method on History
def update(self,subject,**kargs):
self.action = "sale"
self.username = subject.user.username
self.total = subject.product.total
self.save(force_insert=True)
It works fine the first time, but when I try to make another sale, I get an error saying I can't insert into History because of a primary key constraint.
My guess is that when I call the view the second time, the first observer is still in the Subject class, and now I have two history observers listening to the Sales, but I'm not sure if that's the problem (gosh I miss the print_r from php).
What am I doing wrong? When do I have to "attach" the observer? Or is there a better way of doing this?
BTW: I'm using Django 1.1 and I don't have access to install any plugins.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
这可能不是一个可接受的答案,因为它与架构更多相关,但是您是否考虑过使用信号来通知系统更改?看来您正在尝试完全按照信号的设计目的进行操作。 Django 信号具有与观察者模式相同的最终结果功能。
http://docs.djangoproject.com/en/1.1/topics/signals/
This may not be an acceptable answer since it's more architecture related, but have you considered using signals to notify the system of the change? It seems that you are trying to do exactly what signals were designed to do. Django signals have the same end-result functionality as Observer patterns.
http://docs.djangoproject.com/en/1.1/topics/signals/
我认为这是因为
_observers = []
的作用类似于静态共享字段。因此Subject
的每个实例都会更改 _observers 实例,并且会产生不需要的副作用。在构造函数中初始化该变量:
I think this is because
_observers = []
acts like static shared field. So every instance ofSubject
changes the _observers instance and it has unwanted side effect.Initialize this variable in constructor:
@Andrew Sledge 的 answer 指出了解决此问题的好方法。我想建议一种替代方法。
我遇到了类似的问题并开始使用信号。它们工作得很好,但我发现我的单元测试变得更慢,因为每次我使用固定装置加载关联类的实例时都会调用信号。这使测试运行增加了数十秒。有一个解决办法,但我发现它很笨拙。我定义了一个自定义测试运行程序,并在加载夹具之前断开了我的函数与信号的连接。后来我重新连接了它们。
最后,我决定完全放弃信号并覆盖模型的适当
save()
方法。就我而言,每当Order
发生更改时,都会在OrderHistory
表中自动创建一行。为此,我添加了一个函数来创建OrderHistory
实例,并从Order.save()
方法中调用它。这也使得单独测试save()
和函数成为可能。看看这个SO问题。它讨论了何时重写 save() 以及何时使用信号。
@Andrew Sledge's answer indicates a good way of tackling this problem. I would like to suggest an alternate approach.
I had a similar problem and started out using signals. They worked well but I found that my unit tests had become slower as the signals were called each time I loaded an instance of the associated class using a fixture. This added tens of seconds to the test run. There is a work around but I found it clumsy. I defined a custom test runner and disconnected my functions from the signals before loading fixtures. I reconnected them afterwards.
Finally I decided to ditch signals altogether and overrode the appropriate
save()
methods of models instead. In my case whenever anOrder
is changed a row is automatically created in andOrderHistory
table, among other things. In order to do this I added a function to create an instance ofOrderHistory
and called it from within theOrder.save()
method. this also made it possible to test thesave()
and the function separately.Take a look at this SO question. It has a discussion about when to override
save()
versus when to use signals.谢谢大家的回答,阅读有关信号的内容给了我另一个视角,但由于学习目的我不想使用它们(我想在网络开发中使用观察者模式:P)最后,我解决了做这样的事情:
现在每次我调用 save() 时,观察者都会收到通知,如果我需要它,我可以添加或删除观察者,
你觉得怎么样?这是解决问题的好方法吗?
Thank you all for your answers, reading about signals gave me another perspective but i dont want to use them because of learning purposes (i wanted to use the observer pattern in web development :P) In the end, i solved doing something like this:
now every time i call the save(), the observers will be notified and if i need it, i could add or delete an observer
what do you think? is this a good way to solve it?