Question

Snippet taken from this question

from django.db.models import F
...
MyModel.objects.filter(id=...).update(hit_count=F(hit_count)+1)

It was suggested to put in the middleware and I read up a bit on middleware but would greatly appreciate if someone could point out what they would do in this situation. Using my Bug model as an example it has a unique slug field and the pk.

Here's my model:

class Bug( models.Model ):
    name = models.CharField( max_length=100 )
    slug = models.SlugField(unique=True)
    excerpt = models.TextField()
    excerpt_markdown = models.TextField( editable=False, blank=True )
    summary = models.TextField()
    summary_markdown = models.TextField(editable=False, blank=True)
    #workaround = models.TextField()
    #workaround_markdown = models.TextField(editable=False, blank=True)
    date_added = models.DateTimeField()
    poster = models.ForeignKey(User)
    tags_string = TagField()

    class Meta:
    ordering = ['name']

    def __unicode__(self):
    return self.name

    def get_absolute_url(self):
    return '/bugs/%s/' % self.slug

    def save( self, force_insert=False, force_update=False ):
    self.summary_markdown = markdown(  self.summary  )
    self.excerpt_markdown = markdown ( self.excerpt )
    #self.workaround_markdown = markdown(  self.workaround )
    super( Bug, self ).save( force_insert, force_update )

Links are viewed through /bugs/(slug). I've yet to add the new column but I imagine it's just hit_counter = models.IntegerField()

Was it helpful?

Solution

You have three options:

  1. Place the code in a middleware so that it is universally available in your template through the RequestContext.

  2. Place the code in a decorator (essentially just a python function that wraps another function and adds some functionality) so that you can decide where you want this "hit counting" code to be applied.

  3. Place the code in a custom template tag that will increment the counter every time a template with the tag is rendered.

Option three (template tag) is the most complicated, but the most suited to the actual purpose since it can render the counter and increment it in a single piece of code. Option 1 (middleware) is the easiest, but also the least flexible/reusable, etc.

Middleware and template tags are both well documented in Django's docs. You'll get a lot more out of working through them than you will out of getting handed a code snippet here on SO.

Decorators are a basic part of Python since v2.4, and are worth learning, but not the solution I'd choose here. They're a powerful tool and a Google search (or even a search on SO) will give you tons of information.

OTHER TIPS

It's probably worth pointing out that if you save the model each time a user views it, this is going to render most caches pointless, since the model will be fresher than any cache.

If that's important to you, you may want to consider an approach that will preserve caching -- e.g., update a separate Hits model on every view instead, then fold those hit counts back into the main model at cache-friendly intervals.

I prefer putting it within the decorator and decorating all the views that access this model

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top