Django connect temporary pre_save signal

此生再无相见时 提交于 2019-12-25 01:55:28

问题


I've been struggling with a Django signal issue for a few days now and would appreciate your thoughts.

Scenario:

I wish to use a black box method (it's actually the LayerMapping loader in geodjango, but that's not important here) that generates and saves model instances. For some reason, it cannot set one of the fields in my model. Unfortunately, that field cannot be null, so the black box method fails with an IntegrityError. Example code:

models.py

class MyModel(models.Model):
    field1 = models.IntegerField()
    field2 = models.IntegerField()
    field3 = models.IntegerField() # This one is the problem

call_black_box.py

from some_app import black_box
from models import MyModel

def call_it():
    black_box(MyModel, some_other_args) # Fails

The black box routine tries to create some instances of MyModel, but will fail with the error: IntegrityError: null value in column "field3" violates not-null constraint

My solution:

I have generated a pre_save callback dynamically, attached it to MyModel, then disconnected it at the end (because I don't necessarily always want this behaviour):

call_black_box.py

from some_app import black_box
from models import MyModel
from django.db.models.signals import pre_save

def call_it():
    def pre_save_callback(sender, instance, *args, **kwargs):
        instance.field3 = 1
    pre_save.connect(pre_save_callback, sender=MyModel)
    try:
        black_box(MyModel, some_other_args) # OK
    finally:
        pre_save.disconnect(pre_save_callback, sender=MyModel)

It works, but is there a nicer way? I'm guessing this could go wrong if some other actions were executed at the same time as this function. Not a problem for me as I currently do everything sequentially, but not ideal?

Thanks!

edit:

I didn't give enough detail. The value assigned to field3 will be different for a second function:

def call_it_differently():
    def pre_save_callback(sender, instance, *args, **kwargs):
        instance.field3 = some_other_value
    pre_save.connect(pre_save_callback, sender=MyModel)
    try:
        black_box(MyModel, some_other_args) # OK
    finally:
        pre_save.disconnect(pre_save_callback, sender=MyModel)

So I can't give a default value, or override the save method - because these options only allow me to specify a single value, whereas I need the flexibility to apply an arbitrary one.


回答1:


If I understood your question correctly, you can define the default value for the third field in your model

class MyModel(models.Model):
    field1 = models.IntegerField()
    field2 = models.IntegerField()
    field3 = models.IntegerField(default=1) # This one is the problem

So if the value is not specified then Django will take 1 as default




回答2:


Django signals are mostly used as a hook point. Say you are writing a third party app which will be used by other people and you want to provide them with some hook points to manipulate your code, then signals would be used.

In your scenario, I would rather override the save() method of Model than use a signal.

class MyModel(models.Model):
    field1 = models.IntegerField()
    ///
    field3 = models.IntegerField()

    def save(self, *args, **kwargs):
        self.field3 = 1
        super(MyModel, self).save(*args, **kwargs)


来源:https://stackoverflow.com/questions/22324752/django-connect-temporary-pre-save-signal

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