Django - HTML Template get month name from number - django

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.

Related

Django template counting days from now to specific date

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.

Group objects by dates

clicks = SellerClick.objects.extra({'date' : "date(timestamp)"}).values('date').annotate(count=Count('timestamp'))
The model has a datetime field called timestamp that was are using. I first, convert the datetime field to just a date field. Then the rest is guessing. I need to group by, and then count how many objects are of each date.
So the desired result would be a date, then a count, based on how many objects have that date in the timestamp field.
I prefer to use annotate over extra
from django.db.models.expressions import RawSQL
SellerClick.objects.annotate(
date=RawSQL('date(date_joined)',[]),
).values('date').annotate(count=Count('date')))
You've got everything but an initial queryset there. The extra sql you're passing doesn't include a select so you need to give it something to act on.
clicks = SellerClick.objects.all()
.extra({'date' : "date(timestamp)"})
.values('date')
.annotate(count=Count('timestamp'))
Ref: StackOverflow: Count number of records by date in Django

Add an IntegerField to a Datefield in a Django template

I'm trying to display the expiry date of a bonus from within a Django template. At the moment the opening_date is stored as a datefield and we store the bonus term as an integerfield. Unfortunately just trying to add the bonus term to the opening date fails and the furthest I have got so far is:
{{product_form.instance.opening_date|add:product_form.instance.bonus_term}}
I have tried just adding it to the month but unfortunately I need the whole date returned to display.
For a better idea of what I want is say the opening date was 01/01/2012 and the bonus term was 12, I want to display the expiry date of 01/01/2013. I realise this is probably better off being in the database but due to the way it has been previously set up there is a large amount of existing data that wouldn't have it.
Thanks.
I think that, for your scenario, the most elegant solution is to create a model method in your model that calcule expire date, then call the method in template:
In model:
class product(models.Model):
opening_date = ...
bonus_term = ...
def expire_date( self ):
return self.opening_date + timedelta( days = self.bonus_term )
In template:
{{product_form.instance.expire_date}}
I'm sure that you will call this method in more other lines of your code.

Django object filter - price behaving strangely, eg 170 treated as 17 etc

I have a simple object filter that uses price__lt and price__gt. This works on a property on my product model called price, which is a CharField [string] (decimal saw the same errors, and caused trouble with aggregation so reverted to string).
It seems that when passing in these values to the filter, they are treated in a strange way, eg 10 is treated as 100. for example:
/products/price/10-200/ returns products priced 100-200. the filters are being passed in as filterargs: FILTER ARGS: {'price__lt': '200', 'price__gt': '10'} . This also breaks in the sense that price/0-170 will NOT return products priced at 18.50; it is treating the 170 as 'less than 18' for some reason.
any idea what would cause this, and how to fix it? Thanks!
The problem, as Jeff suggests, is that price is a CharField and thus is being compared using character-by-character string comparison logic, i.e. any string of any length starting with 1 will be less than any string of any length starting with 2, etc.
I'm curious what problems you were having with having price be an IntegerField, as that would seem to be the straightforward solution, but if you need to keep price as a CharField, here's a (hacky) way to make the query work:
lt = 200
gt = 10
qs = Product.objects.extra(select={'int_price': 'cast(price as int)'},
where=['int_price < %s', 'int_price > %s'],
params=[lt, gt])
qs.all() # the result
This uses the extra method of Django's QuerySet class, which you can read about in the docs here. In a nutshell, it computes an integer version of the string price using SQL's cast expression and then filters with integers based on that.

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