ashby
ashby

Reputation: 79

Code optimization in a Django when populating field based by a foreign key

I'm searching for some advice on the optimization problem. In this case, I'll use a simple example, I've got these classes:

class Genere(models.Model):
    genere_name = models.CharField(max_length=100)
    short = models.CharField(max_length=2)

class Book(models.Model):
    name = models.CharField(max_length=100)
    genere_name  = models.ForeignKey(Genere,
                                     on_delete=models.SET_NULL,
                                     null=True)
    book_system_id = models.CharField(max_length=100)

My field book_system_id describe id number based on genre, for example (in a simplified way):

id|name              |genere_name|book_system_id 
 1|Dune              |sci-fi     |sf001
 2|Invisible Man     |novel      |n001
 3|Kindred           |sci-fi     |sf002
 4|Neuromancer       |sci-fi     |sf003
 5|IThings Fall Apart|novel      |n002

Now, to populate the field book_system_id in views I use queryset to count elements based by genre, and I'm updating this object (genere_id I'm passing in URL to view function when I create new book object), bellow this is the code snippet:

book.save()
book.book_system_id = genere.short + str(Book.objects.filter(book_system_id=genere_id).count())
book.save()

I'm knowing that this is probably the worst way to do this. That will be really slow when I have a big amount of objects stored in this table. I am wondering how to improvise to do this in the best way; I can add an extra field to store number current order, and when a new object is saved we can get the last number from DB. The second idea was that I can create a new table when I store the current counters. The third option is that I can create new classes based on genre (e.g. scifi_book, novel_book, etc), but the problem will be when I add a new genre. Have you guys any tips to "solve" this problem? I'll be grateful for any tips.

Upvotes: 1

Views: 64

Answers (1)

Alvi15
Alvi15

Reputation: 335

I would choose 2nd option, have a Model that FK to Genre and have a counter number field. Ex:

class ModelName(models.Model):
    genere  = models.ForeignKey(Genere,"insert condition here")
    counter = models.IntegerField("insert condition here")

Override Genre model save(), and check whether if it's already created or not. If it hasn't been created, then give default value (0 or 1), else just ignore. Something like this.

def save(self, *args, **kwargs):
    if not self.pk:
        # Insert default value logic here
    super(Genere, self).save(*args, **kwargs)

then just override Book save() again to fetch the counter before saving. Depending on your default value (0 or 1) you want to add the counter either before or after you save it on Book class Ex:

def save(self, *args, **kwargs):
        genere = ModelName.objects.get(genere=self.genere_name)
        self.book_system_id = genere.counter
        genere.counter += 1
        genere.counter.save()
        super(Book, self).save(*args, **kwargs)

Upvotes: 1

Related Questions