问题
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