QuerySet for related models

228 views
Skip to first unread message

M Hashmi

unread,
Aug 4, 2016, 11:41:54 AM8/4/16
to Django users

I know that count only can be applied for an IntegerField or FloatField but I've created a ForeignKey to another model which contains hitcounts. Now I need to filter results by max count from related model and I couldn't dot it.


models.py:


class Product(models.Model):
    title = models.CharField(max_length=120)
    description = models.TextField(blank=True, null=True)
    price = models.DecimalField(decimal_places=2, max_digits=20)
    active = models.BooleanField(default=True)
    categories = models.ManyToManyField('Category', blank=True)
    default = models.ForeignKey('Category', related_name='default_category', null=True, blank=True)
    hits = models.ForeignKey(HitCount)

    objects = ProductManager()

    class Meta:
        ordering = ["-title", '-hits']

The idea is to access Hitcount field hits to count max value and sort list by max count. Below is Hitcount model installed as third party reusable app djagno-hitcount.

 HitCount(models.Model):
    hits = models.PositiveIntegerField(default=0)
    modified = models.DateTimeField(auto_now=True)
    content_type = models.ForeignKey(ContentType, related_name="content_type_set_for_%(class)s", on_delete=models.CASCADE)
    object_pk = models.PositiveIntegerField('object ID')
    content_object = GenericForeignKey('content_type', 'object_pk')

    objects = HitCountManager()

    class Meta:
        ordering = ('-hits',)
        get_latest_by = "modified"
        verbose_name = _("hit count")
        verbose_name_plural = _("hit counts")
        unique_together = ("content_type", "object_pk")
        db_table = "hitcount_hit_count"

I need to call products in multiple apps with different list and in my mainpage views I am trying to use filter option like below:

from django.db.models import Max, Sum, Count
product1 = Product.objects.all().annotate(hits=Count('-hits__hits'))[:6]

or

product1 = Product.objects.all().order_by('-hits__hits')[:6]

and with few different filter options. I couldn't make it work so advise would be appreciated.

Constantine Covtushenko

unread,
Aug 4, 2016, 3:34:57 PM8/4/16
to django...@googlegroups.com
Hi M Hashmi,

As I see your model scheme built with meaning that 1 record of HitCount relates to many records of Product.
And in your queries you try to select all products that relate to 5 topmost HitCounts.

Am I correct?

Will be waiting for your response.
 

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users...@googlegroups.com.
To post to this group, send email to django...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/39e610bf-0558-4a8d-8491-f9324d8986f1%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

M Hashmi

unread,
Aug 4, 2016, 3:42:58 PM8/4/16
to Django users, constantine...@gmail.com
My field hits=models.ForeignKey(Hitcount) means that my Product model has a related  model with multiple fields and all the products in Product model will have one or more hit records. Instance of Product model will save a hit from end user by session/ip/user etc.

Todor Velichkov

unread,
Aug 4, 2016, 5:07:53 PM8/4/16
to Django users, constantine...@gmail.com
My field hits=models.ForeignKey(Hitcount) means that my Product model has a related  model with multiple fields and all the products in Product model will have one or more hit records. Instance of Product model will save a hit from end user by session/ip/user etc.
Honestly, I don't understand that.

The HitCount class already has a GenericForeignKey, maybe you are looking for a Reverse Generic Relation class in order to get the Hits for a product.

Constantine Covtushenko

unread,
Aug 4, 2016, 5:10:48 PM8/4/16
to django...@googlegroups.com
Please check my notes below:

On Thu, Aug 4, 2016 at 10:42 PM, M Hashmi <mhash...@gmail.com> wrote:
My field hits=models.ForeignKey(Hitcount) means that my Product model has a related  model with multiple fields and all the products in Product model will have one or more hit records.
Sorry but I do not see how Product model will have many hit records.
May be you should change it on:

hits = models.ManyToMany(Hitcount)

 
Instance of Product model will save a hit from end user by session/ip/user etc.

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users...@googlegroups.com.
To post to this group, send email to django...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.

M Hashmi

unread,
Aug 4, 2016, 10:01:52 PM8/4/16
to Django users, constantine...@gmail.com
Thanks Todor as this make sense....all I need is to get the Hitcount's hits presented as local variable to Product model so in queryset I can set order_by. I will try this and will post results.

M Hashmi

unread,
Aug 4, 2016, 10:06:46 PM8/4/16
to Django users, constantine...@gmail.com
Thank you Constantine,

I got this mistake fixed and this was really bad mistake from my side. Now with your proposed scenario I am trying to get it work with 
"trending_products = Product.objects.all().order_by('hits__hits')[:6]" but still it isn't giving me sort by max hits as I used annotate method with Max
as well. Also did count for hits. Any suggestions on this now.

Thank you for your response.

M Hashmi

unread,
Aug 4, 2016, 10:59:20 PM8/4/16
to Django users, constantine...@gmail.com
Hello Todor,

I followed your directions and used https://docs.djangoproject.com/ja/1.9/ref/contrib/contenttypes/ for reference but I got stuck at error 'GenericForeignKey' object has not attribute 'get_lookup'. I tried Product.objects.aggregate(Count('hits'))[:6]. In my models.py I got following code:

hits = GenericRelation(HitCount, content_type_field='content_object', object_id_field='object_pk',)

    class Meta:
        ordering = ["-title"]
Removed the -hits from ordering section and rest of the code is same. I searched it on google but it showed some Django based bugs.
Any suggestions?
Thanks,

Constantine Covtushenko

unread,
Aug 5, 2016, 1:44:02 AM8/5/16
to django...@googlegroups.com
Hi M Hashmi,

I believe that you are looking a way to use aggregation on related model.
You should try the following snitppet:
`trending_products = Product.objects.aggregate(hit=Max('hits__hits'))[:6]` (see more info here)

This will give you list of products where each product will have 'hit' is the MAX value of all hits set for this product.

Also I do not see any reason to use 'ContentType' relation from your HitCount model at all.
If your origin intent was to have hits with any Model in your system(project) then you should built 'joins with aggregation' queries based on Reverse Generic Relation as said Todor. But in this case Product hits field becomes unnecessary as it duplicates relations.

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users...@googlegroups.com.
To post to this group, send email to django...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.

M Hashmi

unread,
Aug 5, 2016, 2:11:17 AM8/5/16
to Django users, constantine...@gmail.com
Thanks for reply and I tried this before same exact code but I got stuck at "unhashable type" error.
I searched it thoroughly but then I gave up on it to have some guidance from kind people like you.

If you believe this is how it should work then please provide me some quick ref for the error. I also changed it like:
trending_products = list(Product.objects.aggregate(hit=Max('hits__hits')))
It didn't work.

Thanks again.

Todor Velichkov

unread,
Aug 5, 2016, 4:04:12 AM8/5/16
to Django users, constantine...@gmail.com
Constantine Covtushenko,

HitCount
is a model from a 3rd party app, so the OP can't change it.

However the way HitCount is implemented I don't think one there is a way for one product to have more than one `HitCount` objects.
So I don't think any aggregations are needed.

Lets the Product class look like this:

class Product(models.Model):
   
#im changing this on purpose, because it points to HitCount class.
    hitcounts
= GenericRelation(HitCount, content_type_field='content_object', object_id_field='object_pk',)

Now `HitCount` has a separate `Hit` class  which hold all individual hits for a `product`.

The app model structure is here.

So to get top products by overall hits you can use `HitCount.hits` field, without any `aggregations`, `annotations` or whatsoever.

top_products_by_total_hits = Product.objects.order_by('hitcounts__hits')[:6]

Now if you want to get the number of hits for a product for some period of range (lets say a week). Then we need to use the `Hit` model.

top_products_by_last_week_hits = Product.objects.filter(
        hitcounts__hit__created__gte
=today-timedelta(days=7)
   
).annotate(
        last_week_hits
=Count('hitcounts__hit')
   
).order_by('-last_week_hits')[:6]

Hope this helps and things get clear now.

M Hashmi

unread,
Aug 5, 2016, 6:42:48 AM8/5/16
to django...@googlegroups.com, constantine...@gmail.com
I did the same thing while working with the contenttype except I did used default filters .all(), .filter(), .get(), annotations and aggregations etc. Todor each product shows multiple hits if I log out and hit it and login back to hit it shows more than one hits. Hits are being recoreded for each session. It shows the same error as it is showing now after implementing GenericRelations:

AttributeError at / 'GenericForeignKey' object has not attribute 'get_lookup'.

If I mix it with .aggregate(Max, Count, Avg or Sum) queryset options it will pop up "unhashable type". 

I am working on joins methods in django with hope that it will make it work. I really appreciate your help guys. You both rock and I've learned a lot with your directions. Still if you have ideas please let me know I will try those too. 

Regards, 
Mudassar

To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.

To post to this group, send email to django...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.

Todor Velichkov

unread,
Aug 5, 2016, 6:54:26 AM8/5/16
to Django users, constantine...@gmail.com
Whats your Django version?

M Hashmi

unread,
Aug 5, 2016, 7:20:25 AM8/5/16
to django...@googlegroups.com, constantine...@gmail.com
1.8.13 as its LTS.

To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.

To post to this group, send email to django...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.

Todor Velichkov

unread,
Aug 5, 2016, 9:06:39 AM8/5/16
to Django users, constantine...@gmail.com
Honestly, now Idea why you get this error, can you paste some more code? And maybe some stack trace?
1.8.13 as its LTS.

M Hashmi

unread,
Aug 5, 2016, 1:23:54 PM8/5/16
to django...@googlegroups.com, constantine...@gmail.com
Todor,

You have access to my complete repo but still I will post answer here for others to learn.

Regards,
Mudassar

To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.

To post to this group, send email to django...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.

M Hashmi

unread,
Aug 6, 2016, 2:55:28 AM8/6/16
to django...@googlegroups.com
Thanks Todor/Constantine for your help,

I've added a field in my Product models with generic relations like:
hitcounts = GenericRelation(HitCount, content_type_field='content_type', object_id_field='object_pk',)

In my view:
object_list = Product.objects.order_by('-hitcounts__hits')[:6]

In my template:

<div class="row">
    <h3>Trending Now!</h3>
        {% load hitcount_tags %}
{% for product in object_list %}
    <div class="thumbnail col-sm-2 col-xs-3 .col-sm-2 ">
           <a href="{{ product.get_absolute_url }}"><h5><b>{{ product.title }}</b><br /></h5></a>
            {% if product.get_image_url %}
                <a href="{{ product.get_absolute_url }}"><img class="img-responsive" src="{{ product.get_image_url }}"/></a><br/>
            {% endif %}
        <p class="view" datahits="{% get_hit_count for product %}" dataid="{{ product.pk }}">Views:{% get_hit_count for product %}</p>
         {% if price == 'True' %}
        {{ product.variation_set.first.get_html_price|safe }}
        {% endif %}
        </div>
{% endfor %}
</div>

It worked for me.

I did it with joins as well but Django joins are perhaps not the best way instead Django encourages object based approach to keep it simple and rapid.

Regards,
Mudassar
Reply all
Reply to author
Forward
0 new messages