Reputation: 19190
I'm using Django and Python 3.7. I have the following two models in my models.py file ...
class Article(models.Model):
created_on = models.DateTimeField(default=datetime.now)
...
class ArticleStat(models.Model):
article = models.ForeignKey(Article, on_delete=models.CASCADE, )
elapsed_time_in_seconds = models.IntegerField(default=0, null=False)
I would like to write a Django ORM query where I select articles have a stat that's at least 5 minutes (300 seconds) old. However, I don't know how to reference the ArticleStat object from the Article object. Unsurprisingly, this
Article.objects.filter(articlestat.elapsed_time_in_seconds.lte==300)
produces a
NameError: name 'articlestat' is not defined
error.
Edit: Per the answer, I changed my ArticleStat model to
class ArticleStat(models.Model):
article = models.ForeignKey(Article, on_delete=models.CASCADE, related_name='articlestats')
and then I ran the below query getting the error displayed
Article.objects.filter(articlestat_set__elapsed_time_in_seconds__lte==300)
Traceback (most recent call last):
File "<input>", line 1, in <module>
NameError: name 'articlestat_set__elapsed_time_in_seconds__lte' is not defined
Thought maybe there was an instance with plurality, so I tried an "s", but got an error ..
Article.objects.filter(articlestats_set__elapsed_time_in_seconds__lte==300)
Traceback (most recent call last):
File "<input>", line 1, in <module>
NameError: name 'articlestats_set__elapsed_time_in_seconds__lte' is not defined
Upvotes: 9
Views: 12757
Reputation: 1418
The core issue here is the NameError
for articlestat
so I will address that first.
As explained in the django documentation your backward relation name by default is defined as FOO_set
which in your case means articlestat_set
.
If a model has a
ForeignKey
, instances of the foreign-key model will have access to aManager
that returns all instances of the first model. By default, thisManager
is named FOO_set, where FOO is the source model name, lowercased.
If you prefer a different name you can do so by specifying a related_name
in your ForeignKey
definition e.g.
class ArticleStat(models.Model):
article = models.ForeignKey(Article, on_delete=models.CASCADE, related_name='articlestats')
elapsed_time_in_seconds = models.IntegerField(default=0, null=False)
The second issue is how to properly follow relations which is explained quite extensively here which is why I will not go into detail about it in this answer. The gist is that instead of the .
operator you want to use __
(double underscore). The same goes for field lookups
which you need for comparison in this query.
With both these issues fixed your query should look like this:
Article.objects.filter(articlestat_set__elapsed_time_in_seconds__lte=300)
or with a custom related_name
e.g. related_name='articlestats'
:
Article.objects.filter(articlestats__elapsed_time_in_seconds__lte=300)
Upvotes: 11
Reputation: 15104
Try something like:
Article.objects.filter(articlestat__elapsed_time_in_seconds__lte=300)
Please notice that Django queries work like keywords (kwargs) (i.e you can only pass a filter_string=something
to the filter function).
You were passing an expression which python could not resolve (i.e python tried to find the articlestat
variable name and then get its elapsed_time_in_seconds
attribute etc)
Take a look at this for more https://docs.djangoproject.com/en/2.1/topics/db/queries/#retrieving-specific-objects-with-filters
Upvotes: 1