0

The following contains a syntax error:

date = datetime.now()-timedelta(minutes=30)
articles = Article.objects.filter(published=True).extra(select = {
  "views" : """
  SELECT COUNT(*)
  FROM myapp_readership
    JOIN myapp_article on myapp_readership.which_article_id = myapp_article.id
  WHERE myapp_readership.reader_id = myapp_user.id
  AND myapp_readership.what_time > %s """ % date,
}).order_by("-views")

The error being: syntax error at or near "01" (where "01" was the datetime object inside extra). It's not much to go on. Can someone point out what's going on?


Background: The models relating to the above code are:

class Article(models.Model):
    author = models.ForeignKey(User)
    published = models.BooleanField(default=False)

class Readership(models.Model):
    reader = models.ForeignKey(User)
    which_article = models.ForeignKey(Article)
    what_time = models.DateTimeField(auto_now_add=True)

I wrote the above code because I was trying to get all published articles, sorted by unique readership each article experienced in the last 30 mins. I.e. counting how many distinct (unique) views each published article got in the last half an hour, and then producing a list of articles sorted by these distinct views. My code is missing handling the 'distinct' part of the requirement - I don't know how to accomplish that here.

1
  • Try wrapping %s in quotes (so that is myapp_readership.what_time > '%s'). If that helps, consider some other way of building queries - string formatting is the worst (practical) one Commented Nov 19, 2015 at 9:27

1 Answer 1

3

You should never ever use string substitution in an SQL query, whether that is part of an extra call or not. You've discovered one reason why not - because values are not quoted properly - but the more important reason is that it leaves you open to SQL injection.

Instead, use the facilities that the db api gives you: in this case, use select_params:

.extra(
  select={
    "views" : """
      SELECT COUNT(*)
      FROM myapp_readership
        JOIN myapp_article on myapp_readership.which_article_id = myapp_article.id
      WHERE myapp_readership.reader_id = myapp_user.id
      AND myapp_readership.what_time > %s """
    },
    select_params=(date,),
)

Also see the note in the docs; the extra method is deprecated, and the query can certainly be expressed using other ORM methods.

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

Comments

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.