Django : Custom save method with queryset

django model save
django model methods
django model manager
django model update
django model fields
django model property
django model validation before save
django update model field

I'm trying to create a custom save method in my model and I would like to get your help in order to improve this one.

I'm generating a unique code based on some variables in my form. I generate the code and I make a research before to save it. If another document already gets this code, I generate another one, else I save the object.

This is my save() method in my models.py file :

def save(self, *args, **kwargs):
    import random
    self.code = f"{self.publication.pub_id}-{self.language.upper()}-{self.format.upper()}-{random.randint(1,10001)}"
    document = Document.objects.filter(code=self.code)
    if document:
        self.code = f"{self.publication.pub_id}-{self.language.upper()}-{self.format.upper()}-{random.randint(1,10001)}"
    super(Document, self).save(*args, **kwargs)

I think it could me improved, by while instead of if condition.

What do you think about it ?

Thank you

I use a while to check if my code is unique, it's quite self explanary and i modified for your code purpose :

def _get_unique_code(self):
    """

    To be used only once in the save method. It creates the unique code.

    """
    import random
    self.code = f"{self.publication.pub_id}-{self.language.upper()}-{self.format.upper()}-{random.randint(1,10001)}"
    while Document.objects.filter(code=self.code).exists():
        self.code = f"{self.publication.pub_id}-{self.language.upper()}-{self.format.upper()}-{random.randint(1,10001)}"
    return self.code

def save(self, *args, **kwargs):
    if not self.code:
        self.code = self._get_unique_code()
    super(Document, self).save()

#7447 (QuerySet.update() bypasses custom Model.save() methods , This is symmetrical to #6915 (and therefore should be handled simmilar). Options​: iterate the queryset, update and save() each instance individually. Because  I have a custom django queryset class, which I use together with custom manager to easly filter objects with chaining. I wanted to add custom method to this class to save its result as a file.

I am assuming save() method is of model Document and I think self.code will always be unique(because of pub_id and randomint) so if/while looks unnecessary to me.

Model instance reference | Django documentation, The from_db() method can be used to customize model instance creation when _loaded_values = dict(zip(field_names, values)) return instance def save(self, by QuerySet.get() when an object is not found for the given query parameters. Alternatively, add a new method, similar to update (let's call it "queryset.save_data()" for example), and guarantee that that iterates no matter what, and leave the update() method alone. Then, clearly document the fact that update() bypasses custom saves and is fast, save_data() uses custom saves but is slow.

The probability at which you'll get matching codes already existing in your database would be one in a million to say the least.

Having said that, this is the while you might have been looking for.

import random
def get_code(self):
    self.code = f"{self.publication.pub_id}-{self.language.upper()}-{self.format.upper()}-{random.randint(1,10001)}"
    while Document.objects.filter(code=self.code).exists():
        self.code = f"{self.publication.pub_id}-{self.language.upper()}-{self.format.upper()}-{random.randint(1,10001)}"
    return self.code

def save(self, *args, **kwargs):
    if not self.code:
        self.code = self.get_code()
    super(Document, self).save()

Managers | Django documentation, A custom Manager method can return anything you want. It doesn't have to return a QuerySet . For  This is because it isn’t possible to save many-to-many data for an instance until the instance exists in the database. To work around this problem, every time you save a form using commit=False, Django adds a save_m2m() method to your ModelForm subclass.

Creating forms from models | Django documentation, As stated earlier, you can override the default queryset used by the 'title')) if request.method == "POST": formset = AuthorFormSet( request. if formset.​is_valid(): formset.save() # Do something. else:  The new save() method starts on Line 10. In the overridden save() method, we’re first assigning the staff member with the username “abbyb” to the manager field of the model instance (Line 11), and then we call the default save() method with the super() function to save the model instance to the database (Line 12).

Making queries | Django documentation, To create and save an object in a single step, use the create() method. The Manager is the main source of QuerySets for a model. For example  Django : Custom save method with queryset I'm trying to create a custom save method in my model and I would like to get your help in order to improve this one. I'm generating a unique code based on some variables in my form .

Common Issues, As of Django Simple History 2.2.0, we can use the utility function Thus, we tell you that queryset updates will not save history (since no post_save for a model that has a custom ``save()`` method, loop over them and call ``save()``, like this:. I tried creating a custom field that would store a string that was a list of pks, then return that as a queryset. (yes, I could probably have done it using a many2many field, but I was (am) trying to reduce the number of db queries for this.

Comments
  • How can a while loop be more efficient than a single if condition?
  • Because if self.code in the if statement already exists in my database ? I need to loop until I get a unique self.code. Maybe it's not a while loop and I have to improve my if ?
  • Okay that isn't efficient code. That is correct code. What you're doing here is incorrect actually.
  • Yes to my mind it works fine ! Thank you very much :)