在django中使用观察者模式的问题

发布于 2024-09-18 09:20:31 字数 1387 浏览 3 评论 0原文

我正在一个销售产品的网站上工作(一类销售,一类产品)。每当我销售产品时,我都想将该操作保存在历史表中,并且我决定使用观察者模式来执行此操作。

也就是说:我的 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

柒七 2024-09-25 09:20:31

这可能不是一个可接受的答案,因为它与架构更多相关,但是您是否考虑过使用信号来通知系统更改?看来您正在尝试完全按照信号的设计目的进行操作。 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/

你在看孤独的风景 2024-09-25 09:20:31

我认为这是因为 _observers = [] 的作用类似于静态共享字段。因此 Subject 的每个实例都会更改 _observers 实例,并且会产生不需要的副作用。

在构造函数中初始化该变量:

class Subject:

    def __init__(self):
        self._observers = []

I think this is because _observers = [] acts like static shared field. So every instance of Subject changes the _observers instance and it has unwanted side effect.

Initialize this variable in constructor:

class Subject:

    def __init__(self):
        self._observers = []
一直在等你来 2024-09-25 09:20:31

@Andrew Sledgeanswer 指出了解决此问题的好方法。我想建议一种替代方法。

我遇到了类似的问题并开始使用信号。它们工作得很好,但我发现我的单元测试变得更慢,因为每次我使用固定装置加载关联类的实例时都会调用信号。这使测试运行增加了数十秒。有一个解决办法,但我发现它很笨拙。我定义了一个自定义测试运行程序,并在加载夹具之前断开了我的函数与信号的连接。后来我重新连接了它们。

最后,我决定完全放弃信号并覆盖模型的适当 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 an Order is changed a row is automatically created in and OrderHistory table, among other things. In order to do this I added a function to create an instance of OrderHistory and called it from within the Order.save() method. this also made it possible to test the save() 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.

心碎的声音 2024-09-25 09:20:31

谢谢大家的回答,阅读有关信号的内容给了我另一个视角,但由于学习目的我不想使用它们(我想在网络开发中使用观察者模式:P)最后,我解决了做这样的事情:

class Sales(models.Model,Subject):
    ...
    def __init__(self):
        self._observers = []  #reset observers
        self.attach(History()) #attach a History Observer
    ...
    def save(self):
        super(Sales,self).save()
        self.notify() # notify all observers

现在每次我调用 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:

class Sales(models.Model,Subject):
    ...
    def __init__(self):
        self._observers = []  #reset observers
        self.attach(History()) #attach a History Observer
    ...
    def save(self):
        super(Sales,self).save()
        self.notify() # notify all observers

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?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文