Django model instance specific code

一世执手 提交于 2020-01-01 19:09:22

问题


in one of my Django models I have to add specific code for each model instance. Now, I wonder what would be a good way to implement this. My current attempt results in a big, hard to read if statement.

Consider the following model:

class Foo(models.Model):
    name = models.CharField(max_length=255)

    def do_instance_specific_stuff(self, arg):
        if self.id == 1:
            do_X(arg)
        elif self.id == 2:
            do_Y(arg)
        else:
            do_Z()

Right now, there is custom code for around 20 model instances and it will stay in this magnitude. Any ideas or patterns how this can be implemented in a clean, readable way?

Thanks for any help.


回答1:


I would add another field to your model, vendor. Then add per-vendor methods to your model, and invoke them with getattr:

class Foo(models.Model):
    name = models.CharField(max_length=255)
    vendor = models.CharField(max_length=50)

    def vendor_fedex(self, arg):
        blah blah

    def vendor_ups(self, arg):
        blah blah

    def vendor_usps(self, arg):
        blah blah

    def do_instance_specific_stuff(self, arg):
        fn = getattr(self, "vendor_"+self.vendor, None)
        if not fn:
            raise Exception("Uh-oh, bad vendor")
        fn(arg)

Depending on particular values of id seems very fragile. In your data model, each vendor string will appear only once, but it will be readable and malleable. You can decide what you want to do if the getattr can't find the vendor code.




回答2:


The common pattern is to use a dict:

stuff_per_id = {1 : do_X, 2 : do_Y, ...}
def do_instance_specific_stuff(arg):
    try:
        stuff_per_id[self.id](arg)
    except KeyError:
        do_Z()

Though you really shouldn't be doing this. It's much better to put an extra field in your model that signifies what code should be run on arg for this instance. The dict pattern may then still be of use.

Edit: if any of your instance-specific functions may raise KeyError, the above executes do_Z. If you don't want that, add an unused argument to do_Z and use the following:

def do_instance_specific_stuff(arg):
    try:
        f = stuff_per_id[self.id]
    except KeyError:
        f = do_Z
    f(arg)


来源:https://stackoverflow.com/questions/3975909/django-model-instance-specific-code

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!