Django template counting days from now to specific date - django

I have a model with DateField:
end_date = models.DateField(default=datetime.date.today)
In the template I need to calculate how many days there is to the end_date from now.
I tried:
{% now "d m Y"|timeuntil:placement.end_date|date:"d m Y" %}
but it doesn't work. How can I get number of days until that date?

There is a limitation to using Django functionality in Templates. You could solve this by combining the timesince and timuntil methods to calculate the difference between two dates. However you would benefit more from doing this in a python view and then pass the result to the template.
This way you can truly use the power of Datetime. So in your views.py and the specific function that renders the template, include this:
d0 = datetime.now().date()
d1 = placement.end_date
delta = d0 - d1
print delta.days
You can read more about the Datetime documentation here. Now you can pass that variable along in a context, or by itself to be rendered by the template

Option 1: Create a custom filter
Create a custom filter function which grabs the current date and calculates the days.
In your template you simply use:
{{ placement.end_date | days_until }}
To define and register the filter, include this code in a python file:
from datetime import datetime
from django import template
register = template.Library()
#register.filter
def days_until(date):
delta = datetime.date(date) - datetime.now().date()
return delta.days
More about Django custom template tags and filters here.
Option 2: Calculate the days in your view and store it in the context
This is straightforward for one date. You calculate the days and store the information in the context:
from datetime import datetime
delta = placement.end_date - datetime.now().date()
context['days_left'] = delta.days
In your template you access it directly:
{{ days_left }}
But, if you want to pass a list of "placements" to the template, you will have to "attach" this new information to every placement. This is a different topic and the implementation depends on the project... you can create a wrapper over placement... or store the days_left in a different dictionary...

Because I like Django built-in filters
timesince
Formats a date as the time since that date (e.g., “4 days, 6 hours”).
Takes an optional argument that is a variable containing the date to
use as the comparison point (without the argument, the comparison
point is now). For example, if blog_date is a date instance
representing midnight on 1 June 2006, and comment_date is a date
instance for 08:00 on 1 June 2006, then the following would return “8
hours”:
{{ blog_date|timesince:comment_date }}
Comparing offset-naive and offset-aware datetimes will return an empty
string.
Minutes is the smallest unit used, and “0 minutes” will be returned
for any date that is in the future relative to the comparison point.

Related

Django - HTML Template get month name from number

I have a number represented month and I want to replace it with month name. The date filter not working, as it works with datetime, and I have the field as integer. For sure the value will be between 1 and 12.
{{ monthnumber|date:"M" }}
Please help.
From what I read I assume you are just passing an integer. You have to pass a value that is a datetime object, ie in your views context, monthname must be a datetime object.
If you would still like to work with an integer from 1 to 12, you could write your own filter with something along the lines:
#register.filter
def monthtextual(value):
return datetime.date(2020, value, 1).strftime('%B')
See https://docs.djangoproject.com/en/3.0/howto/custom-template-tags/ for more details.
Thanks all for the valuable solutions.
Instead of using custom filter or any 3rd party code.. I tend to add an additional field for Month Name along with Month Number in the queryset itself.. and in HTML template i used that additional field for Month Name for display purpose. This seems to be fast.

How do I calculate the time difference in a Django template

I have a model with two TimeFields. I want to show the time difference in a template (ie, 27 minutes). I see the filter timesince, but it isn't working; I think it only accepts datetimes but my models have stored times only.
Response to #HAL:
'datetime.time' object has no attribute 'year'
Exception Location: C:\Python27\lib\site-packages\django\utils\timesince.py in timesince, line 32
You can use timesince template tag.
You can only compare two time stamps if you know their corresponding dates and timezones.. The datetime.time class contains only the time. I strongly advise you to consider using a DateTimeField (which uses datetime.datetime) in this case.
If you are sure that both datetime.time objects are having the same date and timezone, then you can add method to your model like this:
import datetime
from django.utils.timesince import timesince
class MyModel(models.Model):
...
def get_time_diff(self):
dummydate = datetime.date(2000,1,1) # Needed to convert time to a datetime object
dt1 = datetime.combine(dummydate,self.t1)
dt2 = datetime.combine(dummydate,self.t2)
return timesince(dt1, dt2) # Assuming dt2 is the more recent time
Here the time values are upgraded to a datetime value using an arbitrary date. You can invoke this from the template as {{ obj.get_time_diff }}.

Django queryset dates: aggregate and format months as name strings

I've got a simple blog application which I'm porting to Django. One stumbling block I've come across is the aggregation of article entries by month, and displaying that as a list. Each article in the db has a simple datetime field. The HTML output should be something like:
2010
January (3 entries)
February (2 entries)
March (3 entries)
etc.
I'm currently using a {% foreach %} block in the template to loop through all the months returned from the query.
Going with dates('datestamp','month') seems to be the right direction, but how do I get article counts in the results, and how would I format the month integers to be name strings in the template?
You can use django-cube for this. With the following code in your views.py (and then connect entry_count in your urls), you should get what you need :
# cube declaration
from cube.models import Cube, Dimension
class EntryCube(Cube):
#replace <your_date_field> by the field name
month = Dimension('<your_date_field>__month')
year = Dimension('<your_date_field>__year')
#staticmethod
def aggregation(queryset):
return queryset.count()
# views declaration
from .models import <YourModel> #replace by your model
from cube.views import table_from_cube
def entry_count(request):
cube = EntryCube(<YourModel>.objects.all())
return table_from_cube(request, cube, ['year', 'month'], template='table.html')
#template 'table.html' is in 'example/template' folder, copy it in your template folder, and modify it to your wish.
EDIT :
If you want to customize the way dimensions are displayed, you can just subclass Dimension (see this snippet):
class MonthDimension(Dimension):
#property
def pretty_constraint(self):
#just return the month name according to the month number that you can get in "self.constraint", e.g. self.constraint = 1 -> return 'january'
return month_name
(I plan to provide subclasses of dimensions to allow different formats like what you need. So if you do use django-cube, and write a good subclass of Dimension to format dates, I would be happy to take a look at it !)
Ok ... it is overkill for what you want. However, if you decide after that you want more statistics on your entries (for example number of entries/author/month/year/tag, etc ...), you simply add a dimension to the cube. If you decide to use this, and need more help, please ask !

Django Templates: How to show the time differences between a Datastore time and current time?

I am working on a django- Google app engine project. A user inserts some value and the datetime field is auto filled using google app engine DateTimeProperty(auto_now_add=True) property. Now, I have to display on the template the difference of this time and the current time when the user is viewing the result.
For e.g. if the inserted time was 5:00 and the user is viewing the post at 6:00, the result should be 1 hour. Is there any builtin filter available with the Django templates to perform the same? I tried timesince as:
{{ topic.creation_date| timesince: now }}
where creation_date is a datetime field. But its not working.
Please suggest.
Thanks in advance.
Do you have a variable called "now" in your context? If not, that will fail.
However, you don't actually need one, because if you call the timesince filter without an argument, it will use the current time. So just do:
{{ topic.creation_date|timesince }}
why don't you use time.time()? And for creation date you first have to insert given row into database. That means you can read it.
from datetime import timedelta
yourmodel.save()
cdate= yourmodel.creation_date
seconds = time.time() - time.mktime(cdate.timetuple())
timediff = str(timedelta(seconds=seconds))

Is there a way to customize how the value for a custom Model Field is displayed in a template?

I am storing dates as an integer field in the format YYYYMMDD, where month or day is optional.
I have the following function for formatting the number:
def flexibledateformat(value):
import datetime, re
try:
value = str(int(value))
except:
return None
match = re.match(r'(\d{4})(\d\d)(\d\d)$',str(value))
if match:
year_val, month_val, day_val = [int(v) for v in match.groups()]
if day_val:
return datetime.datetime.strftime(datetime.date(year_val,month_val,day_val),'%b %e, %Y')
elif month_val:
return datetime.datetime.strftime(datetime.date(year_val,month_val,1),'%B %Y')
else:
return str(year_val)
Which results in the following outputs:
>>> flexibledateformat(20100415)
'Apr 15, 2010'
>>> flexibledateformat(20100400)
'April 2010'
>>> flexibledateformat(20100000)
'2010'
So I'm wondering if there's a function I can add under the model field class that would automatically call flexibledateformat.
So if there's a record
r = DataRecord(name='foo',date=20100400)
when processed in the form the value would be 20100400 but when output in a template using {{ r.date }} it shows up as "April 2010".
Further clarification
I do normally use datetime for storing date/time values. In this specific case, I need to record non-specific dates: "x happened in 2009", "y happened sometime in June 1996".
The easiest way to do this while still preserving most of the functionality of a date field, including sorting and filtering, is by using an integer in the format of yyyymmdd. That is why I am using an IntegerField instead of a DateTimeField.
This is what I would like to happen:
I store what I call a "Flexible
Date" in a FlexibleDateField as an
integer with the format yyyymmdd.
I render a form that includes a
FlexibleDateField, and the value
remains an integer so that functions
necessary for validating it and
rendering it in widgets work
correctly.
I call it in a template,
as in {{ object.flexibledate }} and
it is formatted according to the
flexibledateformat rules: 20100416
-> April 16, 2010; 20100400 -> April 2010; 20100000 -> 2010. This
also applies when I'm not calling it
directly, such as when it's used as
a header in admin
(http://example.org/admin/app_name/model_name/).
I'm not aware if these specific things are possible.
Also
I have already written a template filter that can perform this function --
({{object.flexibledate|flexibledateformat}}) --
but I'd rather not have to call the filter every time I want to output one of these values. Except when outputting the form, I pretty much never want to see the number.
I think the most djangoish way of accomplishing a similar effect would be to define a custom method on a model:
class Model(models.Model):
date = models.IntegerField()
...
def flexibledate(self):
return flexibledateformat(self.date)
You can use it in a template like this:
{{ r.flexibledate }}
I also wonder why are you using an IntegerField instead of a native DateTimeField.
Update: You can still use the custom method as an option for list_display in Django Admin. If you want the column header to say something else then simply the method's name use the "short_description" option, like this:
class Model(models.Model):
date = models.IntegerField()
...
def flexibledate(self):
return flexibledateformat(self.date)
flexibledate.short_description = 'Date'
and then you just use it the same way you would use an ordinary field:
class YourModelAdmin(admin.ModelAdmin):
list_display = ('title', 'flexibledate')
admin.site.register(YourModel, YourModelAdmin)
That is not necesary, read about humanize and filtertag time