I have a problem comparing dates in Django. I followed the hint How to compare dates in Django but it does not work. Maybe you can help me.
My code:
modelys.py
class Customer(models.Model):
last_updated = models.DateTimeField(auto_now_add=True)
views.py
#property
def is_past_due(self):
return (date.today() - self.date)> timedelta(1)
home.html
{% if customer.last_updated.is_past_due %}
<td class="table-danger">{{ customer.last_updated }}</td>
{% else %}
<td class="align-middle">{{ customer.last_updated }}</td>
{% endif %}
I am using Bootstrap, so when the difference between two dates has a more than one day I want a tablefield to become 'danger'-ous ;-), but nothing changes.
Thanks in advance.
PS: edited the typo in def timdedelta to timedelta.
you can use days property of datetime to get the exact gap between days.
(datetime.today()- self.last_updated).days > 1
where self.last_updated is field name of "Customer" Model
Here the final code as sumup of the posts:
models.py
from datetime import datetime
class Customer(models.Model):
last_updated = models.DateTimeField(auto_now_add=True)
#...some more code...
#property
def is_past_due(self):
return (datetime.now(timezone.utc) - self.last_updated).days>1
home.html
{% if customer.is_past_due %}
<td class="align-middle table-danger">{{ customer.last_updated.date}}</td>
{% else %}
<td class="align-middle">{{ customer.last_updated}}</td>
{% endif %}
Related
I'm new to Django, so maybe my attempts are pure heresy ;)
I'm trying to make a view which lists disponible conference rooms with its attributs, availability included.
I have 2 models: Room and Reservation. I'd like in the view to have a column saying if the room is available the day the page is displayed.
My models.py:
from django.utils import timezone
from django.db import models
class Room(models.Model):
name = models.CharField(max_length=255, unique=True)
capacity = models.IntegerField()
projector = models.BooleanField()
class Reservation(models.Model):
room = models.ForeignKey(Room, on_delete=models.CASCADE)
date = models.DateField()
comment = models.CharField(max_length=255)
class Meta:
unique_together = ('room', 'date',)
my views.py:
class ShowRoom(View):
def get(self, request):
rooms = Room.objects.all()
time_now = timezone.now().date()
context = {
'rooms': rooms,
'time_now': time_now
}
return render(request, 'rooms/list_rooms.html', context)
My template:
{% extends 'rooms/base.html' %}
{% block block_title %} Home {% endblock %}
{% block block_content %}
{% if rooms %}
<table class="table">
<thead>
<td> Name </td>
<td> Capacity </td>
<td> Available </td>
<td> Projector </td>
</thead>
<tbody>
{% for room in rooms|dictsort:'capacity' %}
<tr>
<td> {{ room.name }} </td>
<td> {{ room.capacity }} </td>
<td> Available? </td>
<td> {{ room.projector|yesno:'yes,no' }} </td>
</tbody>
{% endfor %}
</table>
{% else %}
<h1> You have no registered rooms yet. </h1>
{% endif %}
{% endblock %}
Everything works fine, I need just to replace this <td> Available? </td> line with a code, which would display "free" or "occupied" according to existing room reservations.
I've found out that maybe I should write a custom filter.
Here is my filter:
from django import template
from rooms.models import Room, Reservation
register = template.Library()
#register.filter
def check_reservation(queryset, now):
return queryset.filter(date=now)
(I wanted first to make it working, and after make it display this "free" or "occupied".)
I've added to the template {% load my_extras %} and replaced the line I want to change with
<td> {{ room.reservation_set.all|check_reservation:'time_now' }} </td>
The output is:
ValidationError at /room/ ["'time_now' value has an invalid date
format. It must be in YYYY-MM-DD format."]
Before adding the filter, I was trying this solution in the shell and it was working.
I don't know if there is something wrong with the filter, or I try to approach the issue from wrong side.
Thanks in advance for any tips.
Try adding another field to the the Room class:
occupied = model.BooleanField(default=False)
In the views you can check the date associated with the reservation and today's date.
if reservation.date == time_now:
room.occupied = true
You can then filter with rooms that are available and which are not.
rooms_occupied = room.objects.filter(occupied=True)
rooms_available = room.object.filter(occupied=False)
In the template:
{% if rooms_occupied %}
Available
{% endif %}
I have two Django models that record time. Model one records time during the morning and Model two records time during the evening. I want to present both of these times along with the difference between the times within an HTML table but am confused about how to do it. I am new to Django and would really appreciate some advice.
This is what I have so far:
models.py:
class Alltime(models.Model):
id= models.ForeignKey(User, on_delete = models.CASCADE)
mtime = models.DateTimeField()
etime = models.DateTimeField()
views.py:
def panel(request):
time_data = User.objects.filter(pk__gt=1) #I need all data except for the default Super User account
get_time = Alltime.objects.all()
return render(request, 'users/interface.html', {'data': time_data, "get_time": get_time})
panel.html:
<form>
{% csrf_token %}
<table>
<tr>
<th>Name</th>
<th>Morning timeE</th>
<th>Evening time</th>
<th>Difference in hours</th>
</tr>
{% for data in data %}
<tr>
<td>{{data.username}}</td>
{% endfor %}
{% if get_time %}
{% for m in get_time %}
<td>{{m.mtime}}</td>
<td>{{m.etime}}</td>
{% endfor %}
{% else %}
<td> Not available </td>
{% endif %}
</tr>
</table>
</form>
How can I get the difference between the times and place them within the HTML table?
If I understand correctly what you want to do, then you can/need to structure your data differently. An easy way is to prepare the data in your view:
def panel(request):
time_data = User.objects.filter(pk__gt=1)
time_table=[]
for user in time_data:
morning_time = Morning.objects.filter(user=user)
evening_time = Evening.objects.filter(user=user)
diff = morning_time - evening_time
time_table.append((user.name, morning_time, evening_time, diff))
return render(request, 'users/interface.html', {'data': time_table})
And in the template:
<table>
<tr>
<th>Name</th>
<th>Morning timeE</th>
<th>Evening time</th>
<th>Difference in hours</th>
</tr>
{% for line in data %}
<tr>
<td>{{line.0}}</td>
<td>{{line.1}}</td>
<td>{{line.2}}</td>
<td>{{line.3}}</td>
</tr>
{% endfor %}
</table>
You need to add the handling of not existing data in the view code.
Some remarks:
The whole thing does not really make sense to me. I guess you will need to filter for dates too. But you should get the idea from this. And why is it in a form?
You can add a property to the Alltime model that returns the difference between the morning and evening time
#property
def diff(self):
return self.etime - self.mtime
Then in your template you can use this property
{% for m in get_time %}
<td>{{m.mtime}}</td>
<td>{{m.etime}}</td>
<td>{{m.diff}}</td>
{% endfor %}
I have a Django app that tracks publications. Publications have a M2M relationship to authors. Using MySQL.
Simple.
class Publication(models.Model):
slug = models.SlugField(unique=True, max_length=128)
author = models.ManyToManyField(Author, blank=True, null=True, through='Authorship')
title = models.CharField(max_length=128)
def __unicode__(self):
return unicode(self.title)
I have a ListView to show them:
class PubList(ListView):
model = Publication
Most of these are research papers, with several authors. On my template I want to show a list of authors. So I did something like this:
{% for obj in publication_list %}
<tr>
<td>{{ obj.title }}</td>
<td>
{% for a in obj.authorship_set.all %}
{{ a.author.last_name }}, {{ a.author.first_name }}
{% if not forloop.last %}; {% endif %}
{% endfor %}
</td>
</tr>
{% endfor %}
Well, you might guess what my issue is. As the number of Publications grows, the DB calls skyrocket. 119 publications is 500+ queries.
I solved it like so:
In my PubList(ListView) I override get_context_data and set the output of this function to context['authors']:
def get_authors_by_pub():
from django.db import connection
sql = """SELECT p.id,
(
SELECT GROUP_CONCAT(CONCAT(a.last_name, ', ', a.first_name) SEPARATOR '; ')
FROM publication_authorship ap
LEFT JOIN publication_author a ON a.id = ap.author_id
WHERE ap.publication_id = p.id
)
FROM publication_publication p"""
cursor = connection.cursor()
cursor.execute(sql)
rows = cursor.fetchall() or ()
authors = {}
for r in rows:
if r[1]:
authors[r[0]] = r[1]
return authors
Now I have an authors Dictionary like:
{1: 'Tesla, Nikola; Clarke, Aurthur; Hooper, Grace', 2: 'Hopper, Grace; Simpson, Marge'}
Then, on the template, since I can't access a dict by key, I loop through authors to find the ones with the key that is the publication.id:
<td>
{% for key, value in authors.items %}
{% if key == obj.id %}
{{ value }}
{% endif %}
{% endfor %}
</td>
This works, just 2 queries. Even though the authors query is brutal, with nested SELECTs, it's orders of magnitude faster than before.
But I'm wondering if there's a better way. I feel kind of icky looping through the whole dict for each publication on the template. I would love to be able to go authors[obj.id] on the template.
What do you think?
Django covers related queries and lazy loading quite extensively in it's Documentation...Why would you code all of this when django offers:
Publication.objects.prefetch_related('authors').all()
https://docs.djangoproject.com/en/1.6/topics/db/queries/#related-objects
https://docs.djangoproject.com/en/1.6/ref/models/querysets/#prefetch-related
You can use the above queryset inside your ListView:
class PublList(ListView):
queryset = Publication.objects.prefetch_related('authors')
well it's quiet simple.
2 models with ManyToMany relation:
class Artist(models.Model):
name = models.CharField(max_length=100, unique=True)
slug = models.SlugField(max_length=100, unique=True,
help_text='Uniq value for artist page URL, created from name')
birth_name = models.CharField(max_length=100, blank=True)
class Song(models.Model):
title = models.CharField(max_length=255)
slug = models.SlugField(max_length=255, unique=True,
help_text='Unique value for product page URL, create from name.')
youtube_link = models.URLField(blank=False)
artists = models.ManyToManyField(Artist)
my view suppose to display latest 5 songs:
def songs(request, template_name="artists/songs.html"):
song_list = Song.objects.all().order_by('-created_at')[:5]
return render_to_response(template_name, locals(),
context_instance=RequestContext(request))
and the problem is in the template... i want to display the artist name
but just dont realy know how to do it, i tried:
{% for song in song_list %}
{{ artists__name }} - {{ song.title }}
{% endfor %}
would appreciate any help !
Try changing your template code to:
{% for song in song_list %}
{% for artist in song.artists.all %}
{{ artist.name }} - {{ song.title }}
{% endfor %}
{% endfor %}
artists is another type of manager, so you have to iterate through artists.all and print the name attribute of each element.
Well, I worked on above solution of Mr #Dominic Rodger, but because am using Django version 3.2 it did not worked for me. Therefore, the problem may remain the same but according to how Django version changes, the way to solve them sometimes become different. If you're using Django 3.x use below solution.
In views.py
def songs(request):
song_list = Song.objects.all().order_by('-created_at')[:5]
song_list = {'song_list':song_list}
return render(request, 'artists/songs.html', song_list)
In your HTML Template use code below
<div class="table-responsive">
<table class="table table-bordered" id="dataTable" width="100%" cellspacing="0">
<thead>
<tr>
<th>Artist - Song Title</th>
</tr>
</thead>
<tbody>
{% for song in song_list %}
</tr>
<td>{{ song.artist.name }} - {{ song.title }}</td>
<tr>
{% endfor %}
</tbody>
</table>
In urls.py
path('songs/', views.songs, name='songs'),
If you're running source code from localhost, then type on your browser http://127.0.0.1:8000/songs/
Thank you ....
I am trying to set up links to a view that allows to edit objects, in previous view.
Model:
class List(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=200)
type = models.PositiveIntegerField(choices=TYPE_DICT)
def __unicode__(self):
return self.name
#models.permalink
def get_absolute_url(self):
return ('EditList', None, {'list_id':self.id} )
View:
lists = List.objects.filter(user=request.user)
array = []
for list in lists:
ListDict = {'Name':list.name, 'type':types[str(list.type)], 'edit':list }
array.append(ListDict)
context = { 'array':array,}
Template:
{% for dict in array %}
<tr>
{% for key,value in dict.items %}
{% ifequal key 'edit' %}
<td>{{ key }}</td><td>{{ value.name }}</td>
{% else %}
<td>{{ key }}: </td><td>{{ value }}</td>
{% endifequal %}
{% endfor %}
</tr>
{% endfor %}
and urls conf:
urlpatterns = patterns('tst.list.views',
(r'^$', 'list'),
(r'^edit/(?P<list_id>\d+)/$', 'EditList')
,
What this line with link gives me is http://localhost/list/ as url, not http://localhost/list/edit/[objectid]/
Can anyone please tell me what am i doing wrong?
Alan
If you had wanted to do it for an unnamed urlconf, you just needed to pass the whole import string:
#models.permalink
def get_absolute_url(self):
return ('yourproject.yourapp.views.EditList', None, {'list_id':self.id} )
I also suggest you follow the PEP8 naming conventions for functions.
Ok. I got it working. What i needed to do ,was to give name to this view. When i changed my urlconf to this:
url(r'^edit/(?P<list_id>\d+)/$', 'EditList', name = 'EditList'),
Then everything started working.