Divide option in django model query - python

This is my model:
class DailyObj(models.Model):
RedDate = models.DateField('RecDate')
Name= models.CharField(Name,max_length=100,default=None)
Total_Rec = models.DecimalField('Total Rec',max_digits=18,decimal_places=2,default=None)
top10records = DailyObj.objects.filter(RedDate__gte = fromdate,RedDate__lte = todate,Total_Rec__gt=0).order_by('-Total_Rec')[:10]
Here fromdate and todate are variables having proper date values.
The above query works fine and returns the records which satisfy the given criteria.
However I want each value of Total_Rec to be divided by 10,000,000 (i.e. I would like to convert whole amount in crores). Just to pass this modified values to template. I don't want to update actual table values.

You could use a method like this:
class DailyObj(models.Model):
...
def total_crores(self):
return self.Total_Rec / 10000000
It won't be stored in the database, but will be accessible in the template with something like this:
{{ daily_obj.total_crores }}
Or, in keeping with your query, something like this (assuming that top10records gets added to the view's context):
<ul>
{% for record in top10records %}
<li>{{ forloop.counter }}: {{ record.total_crores }}</li>
{% endfor %}
</ul>

Related

DJANGO: Sorting sets of sets

I have this models (simplified):
#models.py
class Expression(models.Model):
text = models.CharField(max_length=254)
class Country(models.Model):
name = models.CharField(max_length=100)
class Definition(models.Model):
expression = models.ForeignKey(Expression)
country = models.ForeignKey(Country)
text = models.CharField(max_length=254)
class Vote(models.Model):
definition = models.ForeignKey(Definition)
And this view
#views.py
def index(request):
expressions = Expression.objects.all()
return render(request, 'expression_index.html', { 'expressions':expressions)
So it will show the last 10 created expressions.
Then in the template I have this:
#index.html
{% for expression in expressions %}
{{ expression }}
{% for definition in expression.definition_set.all %}
<ul>
<li>{{ definition }}</li>
</ul>
{% endfor %}
{% endfor %}
Every definition has several votes.
Every vote is a single row so we can do:
definition.votes_set.count()
How can I achieve to display them like this:
The top definition of every country alphabetically. Each country appears only with one definition.
Lets say Germany has two definitions for expression "A" and Denmark has three definitions for the same expression it will show only two definitions: the one with the most votes.
I hope I'm making sense.
Thanks
I think something like this should work (untested)
from django.db.models import Count
{{ expression.definition_set.annotate(Count('votes_set')) }}
{% for definition in expression.definition_set.order_by('country','votes_set__count') %}
This queryset will sort alphabetically by country, then each country from it's top voted definition to least.
expression = Expression.objects.get(text__exact="A")
definitions = Definition.objects.filter(expression=expression).annotate(num_votes=Count('vote')).order_by("country__name", "-num_votes")
If i try to keep only the top definition of each country as you wanted, and set .distinct("country") at the end of the queryset, it will throw this error:
NotImplementedError at annotate() + distinct(fields) is not implemented.
So another solution would be:
import operator
expression = Expression.objects.get(text__exact="A")
# Get top definitions sorted by num of votes and convert the values to list.
top_definitions = list(Definition.objects.filter(expression=expression).annotate(num_votes=Count('vote')).order_by("num_votes").values("id", "country", "country__name", "expression", "text", "num_votes"))
# Remove dublicate countries and leave the only the top voted definition.
definitions = list({v['country']: v for v in top_definitions}.values())
# Sort alphabetically by country.
definitions.sort(key=operator.itemgetter('country__name'))
return render(request, 'expression_index.html', {'definitions': definitions, 'expression': expression})
template:
<h1>{{ expression.text }}</h1>
<ul>
{% for definition in definitions %}
<li>{{ definition.country__name }} - {{ definition.text }} - {{ definition.num_votes }}</li>
{% endfor %}
</ul>

Querying a list

objects = object.objects.values('column name')
In HTML, this prints as
['column name':"[item1, item2, item3']"}]
Is it possible to access just the elements so rather than the item showing the above in HTML it just shows
item1 item2 item3
?
Your queryset returns a list, so you need to iterate over the objects within the list, and also specify which field to print.
{% for object in objects %}
{{ object.column_name }}
{% endfor %}
Additionally, in your model, you can specify a value to return if you just call {{ object }}.
class testResult(models.Model):
# define your model fields here
def __str__(self): # assuming python 3
return self.column_name
... in which case the first example could be achieved by doing:
{% for object in objects %}
{{ object }}
{% endfor %}

GetStream (Django) - Cannot Enrich Notification Feed

I am using the GetStream Django package to interact with getstream.io. I have had success using the Enricher() class to enrich my activity feed with Django model information for the feed_manager.get_user_feed(), but cannot get similar results with feed_manager.get_notification_feed()
Here is a shortened version of my model.
class Task(models.Model, Activity):
title = models.CharField()
assigned_to = models.ForeignKey(User)
created_at = models.DateTimeField(auto_now_add=True)
created_by = models.ForeignKey(User)
#property
def activity_object_attr(self):
return self
#property
def activity_actor_attr(self):
return self.assigned_to
#property
def activity_notify(self):
return [feed_manager.get_notification_feed(self.assigned_to.id),]
If my view grabs the user feed:
enricher = Enrich()
feed = feed_manager.get_user_feed(request.user.id)
# feed = feed_manager.get_notification_feed(request.user.id)
activities = feed.get(limit=25)['results']
enriched_activities = enricher.enrich_activities(activities)
My output works as expected, and each of these gets populated with the proper data in my template:
Actor: {{ activity.actor }}<br>
Title: {{ activity.title }}<br>
Time: {{ activity.time|timesince }}<br>
However, if I switch to the notification feed (note the change in commenting out of lines):
enricher = Enrich()
# feed = feed_manager.get_user_feed(request.user.id)
feed = feed_manager.get_notification_feed(request.user.id)
activities = feed.get(limit=25)['results']
enriched_activities = enricher.enrich_activities(activities)
Then, the only field I can get data from is activity.created_at.
The output of activity.keys shows the following:
[u'activities', u'group', u'activity_count', u'created_at', u'updated_at', u'actor_count', u'verb', u'is_seen', u'id', u'is_read']
It seems like perhaps for the notification feed, the actor and object are NOT being reported back to GetStream:
But, it is for the user feed:
I am stumped as to why. What am I missing?
Okay ... so I figured out my mistake. I was operating under the assumption all along that the notification_feed was a flat feed. Whoops, by bad. It is actually aggregated. Therefore, I was able to make fixes as follows:
Instead of:
activities = enricher.enrich_activities(activities)
I used:
enriched_activities = enricher.enrich_aggregated_activities(activities)
Then, in my base template:
{% for enriched_activity in enriched_activities %}
{% render_activity enriched_activity %}
{% endfor %}
Which looks in /activity/aggregated/task.html
{% for activity in enriched_activity.activities %}
{% render_activity activity %}
{% endfor %}
And finally inside /activity/task.html I see the output as expected from these items.
Actor: {{ activity.actor.first_name }}<br>
Title: {{ activity.object.title }}<br>
Time: {{ activity.time|timesince }}<br>

Django - why is this hitting the database twice

I have a property in my model:
def _get_image(self):
return Media.objects.get_for_object(self)
image = property(_get_image)
It calls the following function on my Media model:
def get_for_object(self, obj):
ctype = ContentType.objects.get_for_model(obj)
return self.filter(items__content_type__pk=ctype.pk, items__object_id=obj.pk)
Then in my template I am iterating through the results like so:
{% if entry.image %}
<h2>Current image:</h2>
{% for m in entry.image %}
{{ m }}
{% endfor %}
{% endif %}
For some reason, my SQL readout shows these two queries, right next to each other:
0.40 SELECT
EXPLAIN
Toggle Stacktrace
SELECT `media_media`.`id`, `media_media`.`file`, `media_media`.`content_type`, `media_media`.`created` FROM `media_media` INNER JOIN `media_mediaattachment` ON (`media_media`.`id` = `media_mediaattachment`.`media_id`) WHERE (`media_mediaattachment`.`content_type_id` = 12 AND `media_mediaattachment`.`object_id` = 20 )
0.38 SELECT
EXPLAIN
Toggle Stacktrace
SELECT `media_media`.`id`, `media_media`.`file`, `media_media`.`content_type`, `media_media`.`created` FROM `media_media` INNER JOIN `media_mediaattachment` ON (`media_media`.`id` = `media_mediaattachment`.`media_id`) WHERE (`media_mediaattachment`.`content_type_id` = 12 AND `media_mediaattachment`.`object_id` = 20 )
So whenever I access entry.image, the database is getting hit. Surely it should store the results or something?
"or something"?
Why should it store the results? You've explicitly written the _get_image function so that it queries the database each time. If you want it to store the results, you need to tell it to do it.
Probably the simplest way would be to just get it once in the template:
{% with entry.image as images %}
{% if images %}
<h2>Current image:</h2>
{% for m in images %}
{{ m }}
{% endfor %}
{% endif %}
{% endwith %}
Here's how you write a caching property without explicitly setting the cache to None in the __init__ method:
def _get_image(self):
if not hasattr(self, '_image'):
self._image = Media.objects.get_for_object(self)
return self._image
image = property(_get_image)
or in more modern syntax
#property
def image(self):
if not hasattr(self, '_image'):
self._image = Media.objects.get_for_object(self)
return self._image

Listing blog entries by year,month

I want to do something like this:
Entries.objects.values('date.year','date.month')
but this line is not valid. How can I list blog entries by year,month and display them in template?
Thanks!
If you set
entry_list = Entry.objects.order_by('pub_date')
in your view, you can display the months and years in the template using the ifchanged template tag.
{% for entry in entry_list %}
{% ifchanged %}<h3>{{entry.pub_date|date:"Y"}}</h3>{% endifchanged %}
{% ifchanged %}<h4>{{entry.pub_date|date:"F"}}</h4>{% endifchanged %}
<p>{{entry.title}}</p>
{% endfor %}
Another useful Django queryset method for blog archives is dates.
For example
entry_months = Entry.objects.dates('pub_date','month','DESC')
returns a DateQuerySet of datetime.datetime objects for each month that has Blog Entries. You can use this queryset in the template to create links to monthly archive pages.
You can try with the built-in regroup tag.
In your view:
archives = Entries.objects.all()
In your template:
{% regroup archives by date.month as entries_by_month %}
{% for entries in entries_by_month %}
<h1>{{ entries.list.0.date|date:"F Y" }}</h1>
<ul>
{% for entry in entries.list %}
<li>{{ entry.title }}</li>
{% endfor %}
</ul>
{% endfor %}
Here is some code snipped from my blog where I list all of the blog entries within a certain year:
Entries.objects.filter(draft=drafts).filter(posted_date__year=year).order_by(order_by)
In the above:
drafts is a boolean which specifies whether to show completed items or not.
year is the selected year
order_by is some ordering column name.
You should be able to easily modify this example to also include the month.
The above shows that you can combine multiple filters in a row.
Ok, let's try to do heavy lifting in data structure, instead of templates.
Let's create a utility.
import itertools
def group_by_values(posts, key):
groups = {}
for k, g in itertools.groupby(posts, key):
if groups.get(k) is not None:
groups[k].extend(list(g))
else:
groups[k] = list(g)
return groups
Let's use the utility here.
entries = Entry.objects.all().order_by('date')
yearly_entries = group_by_values(entries, key=lambda x: x.date.year)
monthly_yearly_entries = {}
for k, v in yearly_entries.items():
monthly_yearly_entries[k] = group_by_values(v, key=lambda x: x.date.month)
return monthly_yearly_entries
The result is nice dictionary with years and months as keys like this:
monthly_yearly_entries = {2013: {9: [Entry1, Entry2], 10: [Entry4, Entry5]}}
which you can show nicely in templates

Categories