0

I am working on a little django application where the model contains a TextField and a PositiveIntegerField.

I need the PositiveInegerField to be populated with the number of words in the TextField.

This could be done via custom javascript code that count the number of words in the TextField's text area and put the value to the word count field text box before submitting the form but I do not want to play with custom javascript in the admin.

How to assign a value to a PositiveIntegerField programmatically?

Fanooos
  • 2,718
  • 5
  • 31
  • 55
  • What are you actually trying to do? Show the number of words so far as the user enters them? If you need the word count afterwards, why store it separately rather than calculate it from the text? – jonrsharpe Jun 28 '15 at 11:15
  • I need to store the number of words to display it in the listing page in the admin. That is all what I need, so, I created another field (word_count) that should be populated before saving the model's object. – Fanooos Jun 28 '15 at 11:19
  • Why not use a property, rather then store an additional field? – jonrsharpe Jun 28 '15 at 11:38
  • @jonrsharpe, I think you are correct. I tried it and it works fine. Sorry, I was not aware of this feature. – Fanooos Jun 28 '15 at 11:43

2 Answers2

3

This can be achieved using a pre_save Signal.

Create a signal-function like this:

def calculate_wordcount(sender, instance, **kwargs):
    # count the words...
    instance.word_count = # your count from line above

Then attach this function to your model. The preferred way since Django 1.7 is the application configuration (see doc).

You can attach your function in the AppConfig ready() - method

def ready(self):
    pre_save.connect(calculate_wordcount,
                     sender= ,# your model
                     weak=False,
                     dispatch_uid='models.your_model.wordcount')

I'll leave all necessary imports up to you, please comment, if you need further direction!

Mischback
  • 843
  • 5
  • 18
1

While in general I think save signals are a reasonable idea, in this particular case you can also override .save() yourself

class MyClass(models.Model):

    [stuff]

    def save(self, *args, **kwargs):
        self.wordcount = #something that calculates wordcount
        super(self.myClass, self).save(*args, **kwargs) #Call django's save!

(as a rule of thumb, I'll overwrite save() if I'm just doing things to one model, but use a signal if I'm using one model to affect another. The idea is to keep all things affecting a model near it in the code. But this gets into personal philosophy)

Also WARNING: No matter which version you use, the signal or overwriting save(), bulk_create and bulk_delete will not send a signal or call your specific save function. See the documentation here: https://docs.djangoproject.com/en/1.8/topics/db/models/#overriding-predefined-model-methods

NightShadeQueen
  • 3,284
  • 3
  • 24
  • 37
  • +1 for the warning. Let me add, there are some caveats with fixtures aswell, see [this post](http://stackoverflow.com/questions/3499791/how-do-i-prevent-fixtures-from-conflicting-with-django-post-save-signal-code). Personally I would *not* touch the `save()` unless I absolutely have to, but I think this is personal preference... – Mischback Jun 28 '15 at 14:54