I'm trying to display the difference between 2 giving dates on django, and i've managed to make it, but now i'm strugling to display only the days, without the time, is there any filter that i can use?
My html template:
<a href="{% url 'edit_contract' contract.id %}">
{% if contract.status == 'PN' %}
{{ today |sub:contract.starting_date }}
{% else %}
TODO
{% endif %}
</a>
My view:
#login_required
def contract_list(request):
contracts = Contract.objects.filter(user=request.user)
total_contracts_value = Contract.objects.filter(user=request.user).aggregate(sum=Sum('value'))['sum'] or 0
contracts_count = Contract.objects.filter(user=request.user).count()
today = date.today()
return render(request, 'list_contract.html', {'contracts': contracts,
'total_contracts_value': total_contracts_value,
'contracts_count': contracts_count, 'today':today})
My output:
I think there are a few ways to do what you want here. I'll let you decide what you think works best for you.
The timesince or timeuntil template formatting tags within Django may give you what you want immediately.
{{ today |timeuntil:contract.starting_date }}
https://docs.djangoproject.com/en/4.0/ref/templates/builtins/#timesince
https://docs.djangoproject.com/en/4.0/ref/templates/builtins/#timeuntil
Another option is to make use of the datetime module.
Here is an example showing the difference in days between datetime objects:
import datetime
now = datetime.datetime.now()
startingDate = now + datetime.timedelta(days=7)
daysRemaining = (startingDate-now).days
print(daysRemaining) # INFO: prints '7'
I don't think this is what you want, but here is another example, using strftime and timedelta to get more specific formatting:
tomorrowFormatted = datetime.datetime.strftime(datetime.datetime.now() + datetime.timedelta(days=1), "%d-%b-%Y")
Days since start is a property of your contract, so you could create an actual property in the Contract model
from datetime import date
from django.db import models
class Contract(models.Model):
...
#property
def days_since_start(self):
today = date.today()
result = today - self.start_date
return result.days
then refer to the property in your template
{% if contract.status == 'PN' %}
{{ contract.days_since_start }}
{% else %}
Related
I'm a bit lost, In my MySQL DB DateField is saved like that 2020-10-29
In my template I try to see if DateField == Now. In my models it's DateField not a DateTimeField
So I've try to do this:
{% now "Y-F-j" as current_date %}
{% if post.start_date == current_date %} Today{% else %} Ended{% endif %}
But even if it should match I got ended everywhere... Do you have any idea?
In my MySQL DB DateField is saved like that 2020-10-29.
No, that is just the formatting of how it presents it to the outside world. For a DateField, you should assume it save a date object datetime object. Not a string.
I would advice to pass the current day to the context:
from django.utils.timezone import now
def my_view(request):
# …
context = {
# …,
'today' : now().date()
}
return render(request, 'some_template.html', context)
and then compare this with the start_date of the post object:
{% if post.start_date == today %} Today{% else %} Ended{% endif %}
Note that Django has a |timesince template filter [Django-doc] to present a date(time) object in a more pleasant way.
I would like to compare a date to the current date in Django, preferably in the template, but it is also possible to do before rendering the template. If the date has already passed, I want to say "In the past" while if it is in the future, I want to give the date.
I was hoping one could do something like this:
{% if listing.date <= now %}
In the past
{% else %}
{{ listing.date|date:"d M Y" }}
{% endif %}
With now being today's date, but this does not work. I couldn't find anything about this in the Django docs. Can anyone give some advice?
Compare date in the view, and pass something like in_the_past (boolean) to the extra_context.
Or better add it to the model as a property.
from datetime import date
#property
def is_past_due(self):
return date.today() > self.date
Then in the template:
{% if listing.is_past_due %}
In the past
{% else %}
{{ listing.date|date:"d M Y" }}
{% endif %}
Basically the template is not the place for date comparison IMO.
As of Django 1.8 the following slightly distasteful construct does the job:
{% now "Y-m-d" as todays_date %}
{% if todays_date < someday|date:"Y-m-d" %}
<h1>It's not too late!</h1>
{% endif %}
Hackish, but it avoids the need for a custom tag or context processor.
I added date_now to my list of context processors.
So in the template there's a variable called "date_now" which is just datetime.datetime.now()
Make a context processor called date_now in the file context_processors.py
import datetime
def date_now(request):
return {'date_now':datetime.datetime.now()}
And in settings.py, modify CONTEXT_PROCESSORS to include it, in my case it's
app_name.context_processors.date_now
addition to #bx2 beneficial answer, if your field is a datetime field just call date() function to models datetimefield:
from datetime import date
#property
def is_past_due(self):
if date.today() > self.date.date():
return True
return False
EDIT: i think this could be shrunken to:
from datetime import date
#property
def is_past_due(self):
return date.today() > self.date.date()
I believe the easiest way to achieve this is by importing datetime in your views.py and passing today's date as context data.
context['today'] = datetime.date.today()
Then in the template tags you could do something like this.
{% if listing.date < today % }
This way if you are passing a list of objects as context, you can apply the filter to each line as you output it in the HTML template. I had a list of items that I had filtered out and was using Bootstrap to stylize as I displayed them. I wanted to make overdue dates stand out and applied the filtering only if one of my dates was less than today's date.
You can always pass datetime.datetime.now (since django models use Python's standard datetime object).
Using render_to_response, you could do something like this (after importing datetime):
return render_to_response('template.html', {'now': datetime.datetime.now()})
Now that you have access to "now" inside of the template, you can compare dates just like you did in your examples.
Furthermore, if you use RequestContext in your views - you will be able to add "now" as a context_processor if you need this in multiple files. This will add "now" to any template rendered with a RequestContext.
However, it is more realistic that you simply just get the list of records that are before now in your original queryset and avoid querying for useless data in the first place:
listing.objects.filter(date__lt=datetime.datetime.now())
You can have 2 tasks.
You must show the object using DetailView. You can solve this problem by using a function that passes a boolean value to the template. However, keep in mind that in django you cannot compare a date from a SQL database with datetime.datetime.now(), since the second option does not contain time zone information.
Use django.utils.timezone.now().
You must style the object from the ListView. Then I advise you to use a custom filter that you will call in the template.
#register.filter
def compare_date(date):
if not date:
return False
return date < timezone.now()
If you use Django, you could use the bellow code(https://stackoverflow.com/a/3798865/17050678).
In your models.py
#property
def is_past_due(self):
today = datetime.datetime.today()
return today > self.start_date
But it will take an error to you. like this:
can't compare offset-naive and offset-aware datetimes
So you should take the timezone type like the bellow.
import pytz
#property
def is_past_due(self):
today = datetime.datetime.today().astimezone(pytz.timezone('Asia/Tokyo'))
return today > self.start_date
Then you could compare it in your template.
{% if schedule.is_past_due %}
/*your code here*/
{% endif %}
I found this question and had a similar problem. I was looking to display information if it had only occurred in the past.
Using Django's "timesince" tag in the template I was able to solve my problem. I'm not saying it's efficient, but it works for me.
In Template:
{% if model_name.date_time|timesince >= "1 min" %}
<p>In the past</p>
{% else %}
<p>{{ model_name.date_time }}</p>
{% endif %}
In the signUp form I am creating, I am pre-populating the date-of-birth field to "yesterday".
But the scroll down menu for year is limited to 9 years. how can I increase the number of years to show up. It must not be limited. I have attached the image. you can see that there is an option to choose only among those nine years. Any ideas how to fix this?
signups/forms.py:
from django import forms
from signups.models import SignUp
import datetime
from django.forms.extras.widgets import SelectDateWidget
def yesterday():
yesterday = (datetime.date.today() - datetime.timedelta(1))
return yesterday
class SignUpForm(forms.ModelForm):
date_of_birth = forms.DateField(widget=SelectDateWidget(), initial=yesterday)
class Meta:
model=SignUp
signups/models.py:
from django.db import models
from django.utils.encoding import smart_unicode
from blogapp.models import Post
class SignUp(models.Model):
#null in database
first_name=models.CharField(max_length=100,null=True,blank=True)
last_name=models.CharField(max_length=100,null=True,blank=True)
#default is null=false, blank=false, email is necessary
email=models.EmailField(unique=True)
#when created make timestamp but not when updated
timeStamp=models.DateTimeField(auto_now_add=True,auto_now=False)
updated=models.DateTimeField(auto_now_add=False,auto_now=True)
is_active=models.BooleanField()
date_of_birth=models.DateTimeField()
myPosts=models.ManyToManyField(Post)
def __unicode__(self):
return smart_unicode(self.email,encoding='utf-8',strings_only=False,errors='strict')
signup/views.py:
def signup_view(request):
form=SignUpForm(request.POST or None)
if form.is_valid():
save_it=form.save(commit=False)
save_it.save()
messages.success(request, "Thank you for signing up")
return HttpResponseRedirect("/accounts/register_success")
else:
args={}
args['form']=form
return render(request,"signup.html",args)
templates/signup.html:
{% extends "base.html" %}
{% block content %}
<h2>Join Now</h2>
<form action="" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="register"/>
</form>
{% endblock %}
You can pass a years argument into SelectDateWidget as follows:
SelectDateWidget(years=range(1900, 2100))
Although this will not accept an infinite range, under most circumstances it should do.
Documentation, you can also add month restraints in the development version :)
If you wanted to dynamically change the range with time, you could do something similar to this:
from datetime import datetime
## range would be the difference between the current year,
## and the farthest year into the future or past you would want to include.
date_range = 100
this_year = datetime.now().year
### django code here ###
SelectDateWidget(years=range(this_year - date_range, this_year + date_range))
I want to hide a block in my template (base.html) if the time is not a weekday between 09:00 and 17:00.
I was thinking something like (very simplified):
{% if now is 09:00 and 17:00 on weekdays %}
#Show callback form
{% else %}
#We do not answer the phone before 09:00 and after 17:00
{% endif %}
Is it possible?
I would suggest creating a flag in your view.py
import datetime
# In view
now = datetime.datetime.now()
call_us_now = False
if 9 < now.hour < 17:
call_us_now = True
# Send 'call_us_now' to context
.
{# In template #}
{% if call_us_now %}
{# Show callback form #}
{% else %}
{# We do not answer the phone before 09:00 and after 17:00 #}
{% endif %]
I want to use this code on my base.html, so maybe a little difficult
to implement your code on every view?
Write a custom template context processor. You can use this as a starting point:
from datetime import datetime, time
from django.conf import settings
def calling_flag(request):
""" Sets the flag in the template if the current time is between CALL_HOURS """
if settings.CALL_HOURS:
now = datetime.now().time()
start_time,end_time = settings.CALL_HOURS
start_time = time(start_time[:2],start_time[-2:])
end_time = time(end_time[:2],end_time[-2:])
return {'IN_TIME': start_time <= now <= end_time}
Save it in a file inside an app. Lets say the app is called feedback, and you placed the above code in a file called custom_template_flags.py in the feedback directory. Next step, add it to your settings.py:
TEMPLATE_CONTEXT_PROCESSORS = (
# -- your other context processors
'feedback.custom_template_flags.calling_flag',
)
Finally, add your time range, again in settings.py:
CALL_HOURS = ('0900','1700')
Now, all templates will have {{ IN_TIME }} which will be either True or False.
I am new to Django and I would like to know how can I get the next and previous week links in my template using the week archive generic view. For the archive_month generic view there is a next_month and previous_month object in the template context but not for the archive_week generic view.
models.py
class Day(models.Model):
day = models.AutoField(primary_key=True)
date = models.DateField()
description = models.TextField()
def __unicode__(self):
return str(self.day)
urls.py
week_info = {
"queryset" : Day.objects.order_by('-date'),
"date_field" : "date",
}
urlpatterns = patterns('journal.views',
(r'^(?P<year>\d{4})/(?P<week>\d{2})/$', date_based.archive_week, week_info),
)
You need two links: if current week is 33, previous should read 32, next 34.
Could you possibly grab the current week from the url from within the extra_context dictionary? The dictionary is iterated over after the week variable in generic view code itself, meaning you should have access to it directly in your urls.py (my suspicion)
The url grabs only numbers, but the view works with strings (line 201 in date_based.py):
try:
tt = time.strptime(year+'-0-'+week, '%Y-%w-%U')
date = datetime.date(*tt[:3])
except ValueError:
raise Http404
time.strptime operates on strings, meaning that we need to turn them into integers, add or subtract one, and save those new values as keys in extra context. So I would add the following to your week_info dict:
"next_week" : int(week) + 1,
"prev_week" : int(week) - 1,
Since these links are meant to be args for other date based views, it's fine to leave them as integers. Then build your links from the newly passed context variables.
Hope this helps ;)
You can use the date filter to format the year and week number, and use it to get next and previous week links:
{% if previous_week %}
{% with prev_week_year|date:"Y" prev_week=previous_week|date:"W" %}
<a href="{% url <NAME_OF_YOUR_VIEW> prev_week_year prev_week %}">
See Previous Week</a>
{% endwith %}
{% endif %}
{% if previous_week and next_week %} | {% endif %}
{% if next_week %}
{% with next_week_year|date:"Y" next_week=next_week|date:"W" %}
<a href="{% url <NAME_OF_YOUR_VIEW> next_week_year next_week %}">
See Next Week</a>
{% endwith %}
{% endif %}
You'll also need to name your view.
Don't forget upgrade Django to a newer (more secure) release.