0

How to rewrite the Django model save method?

class Message(models.Model):
    """
    message
    """
    message_num = models.CharField(default=getMessageNum, max_length=16)  

    title = models.CharField(max_length=64)
    content = models.CharField(max_length=1024)

    def save(self, force_insert=False, force_update=False, using=None,
         update_fields=None):
        # I want send email there
        pass

I mean, in the Django model, if I create instance success, I want to call a function, such as send a email in the function.

I find in the Django model have a save method. I am not sure whether should write other code, because there are so many params.

I mean whether I only should care about my send email logic?

3 Answers 3

6

When you override the save method, you still have to make sure that the it actually saves the instance. You can do that by simply calling the parent class' save via super:

class Message(models.Model): 
    # ...
    def save(self, *args, **kwargs):
        # this will take care of the saving
        super(Message, self).save(*args, **kwargs)
        # do email stuff  
        # better handle ecxeptions well or the saving might be rolled back

You can also connect the mail sending to the post_save (or pre_save, depending on your logic) signal. Whether you want to separate one orm the other in that way depends on how closely the two actions are linked and a bit on your taste.

Overriding save gives you the option to intervene in the saving process, e.g. you can change the value of fields based on whether the mail sending was successful or not save the instance at all.

Sign up to request clarification or add additional context in comments.

Comments

4

The solution to what you want to do is to use Django Signals. By using Signals you can hook code to when a model is created and saved without having to rewrite the save method, that keep the separation of code and logic in a much nicer way, obviously the model does not need to know about the emails for example.

An example of how to use Signals would be to simply do the following:

from django.db.models.signals import pre_save
from django.dispatch import receiver
from myapp.models import MyModel

@receiver(pre_save, sender=MyModel)
def my_handler(sender, **kwargs):
    # Code to execute whenever MyModel is saved...

If you still want to override the save() method you can use the Python super() method to do so (docs).

class MyModel(models.Model):
    def save(self, *args, **kwargs):
        # This will call the parent method that you are overriding
        # so it will save your instance with the default behavior.
        super(MyModel, self).save(*args, **kwargs)

        # Then we add whatever extra code we want, e.g. send email...
        Messenger.send_email()

4 Comments

The signals are the way to go in this case. This should be the accepted answer.
@MarcusLind Do you mean create a single py file to write Signals ? and the my_handler method will execute automatically when saved the instance?
@1243916142 Well you can keep the signal method wherever you want. It could be in a separate file or within the model itself. Depends what makes sense in your use case. But yes, the point is that the method will execute whenever you save the instance. Note that there are many types of signals, like post_save and pre_save that execute after, or before a save.
@MarcusLind thank you, bro. how about the dispatch_uid? can I set the dispatch_uid same when other place I want to write a signal ?
2

You need to activate signal once your message is saved. That means, when your message is saved, django will issue signal as follows:

from django.db.models.signals import post_save
from django.dispatch import receiver

class Message(models.Model):
    # fields...

# method for sending email
@receiver(post_save, sender=Message, dispatch_uid="send_email")
def send_email(sender, instance, **kwargs):
    # your email send logic here..

You can put your signals in signals.py file inside your app folder and make sure to import that in your application config file as follows:

message/apps.py

from django.apps import AppConfig

class MyAppConfig(AppConfig):
    name = 'message'

    def ready(self):
        import message.signals

And update init file as follows:

message/__init__.py

default_app_config = 'message.apps.MyAppConfig'

3 Comments

I see you put the receivered method in the Model file, can it be put to a single .py file ? does it need additional operate if I put the method to a single file?
Yes. You can put that on different file. Just need to import your Model (Message) and post_save signal in that file.
@1243916142 I have made the changes in the code above for your reference.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.