Class Based View MySQL DateTimeField received a naive datetime - django

I am very new to Django and at the end of my rope and really need some help.
I do not know how to use a "class based view" and change the incoming datetimefield from my MySQL database into a Time Zone Supported entry that it seems to need. The database stores it in UTC and my system is on PST.
I am getting this error:
DateTimeField received a naive datetime (2012-09-01 00:00:00) while time zone support is active
On my MonthArchiveView, DayArchiveView, DateDetailView 's only. For some reason my ArchiveIndexView, YearArchiveView class based views work ok.
Here is my model:
class blogpost(models.Model):
blog_title = models.CharField(max_length=200)
blog_slug = models.SlugField(unique_for_date='blog_pub_date', max_length=200)
blog_content = models.TextField()
blog_pub_date = models.DateTimeField(default=datetime.now())
blog_category = models.ForeignKey('blogcategory')
Here is one of my Views:
class ThoughtsDetailView(DateDetailView):
template_name='thoughts/thoughts_detail.html'
queryset = blogpost.objects.all()
date_field = 'blog_pub_date'
slug_field = 'blog_slug'
context_object_name = 'thoughts_detail'
month_format = '%m'
allow_future = 'true'
Here is an example template:
{% block content-inner-left %}
<h1>{{ thoughts_detail.blog_title }}</h1>
<div id="blogpost">
<p class="blogsmalldate">[ Posted on {{ thoughts_detail.blog_pub_date|date:"l, F dS, Y" }}, {{ thoughts_detail.blog_pub_time|date:"g:i a" }} ]</p>
<br />
<p>{{ thoughts_detail.blog_content|safe|linebreaks }}</p>
</div>
{% endblock content-inner-left %}
Can someone help me understand how to fix my Day Detail View so that it stays as a Class Based View and then I can probably figure out the others. I even tried to use PYTZ but don't understand enough how to change the class based view to use it. Thank you....

The problem is not in the view, but in the fact that the dates are stored in the database without a timezone information, while Django is set up to support timezones. If you don't need timezone support, simply set USE_TZ = False in the settings.py; if you do, make sure that the database stores the dates with the timezone information. More details on that can be found at https://docs.djangoproject.com/en/1.4/topics/i18n/timezones/#naive-and-aware-datetime-objects

Related

Django Templating Language objects comparison

I'm fairly new to Django. I have a database with Events. I want to display the name of the Organisation where org_id is the foreign key in the events model. My approach was to load in all the objects and then do some iterating through them but I get no output on the website. I feel like its got to do something with the templating language
models.py
class Organisation(models.Model):
org_id=AutoSlugField(unique=True)
name = models.CharField(max_length=200)
email=models.EmailField(max_length = 250)
class Event(models.Model):
event_id = AutoSlugField(unique=True)
name = models.CharField(max_length=100)
date = models.DateField()
event_category = models.CharField(max_length=50)
duration= models.IntegerField()
org_id = models.ForeignKey(Organisation,on_delete=models.CASCADE)
maxparticipants= models.IntegerField()
teacher_id=models.ForeignKey(User,on_delete=models.CASCADE)
relevant snippet from event_details.html
<h3>Hosting Body</h3>
{% for org in orgs%}
{%if org.org_id == event.org_id %}
<p>{{org.name}}</p>
{%endif%}
{%endfor%}
<h3>Date</h3>
<p>{{event.date}}</p>
views.py
def event_details(request,pk):
event=Event.objects.get(event_id=pk)
orgs=Organisation.objects.all()
context={'event':event,'orgs':orgs}
return render(request,'event_details.html',context)
You can render the relevant organization with:
<h3>Hosting Body</h3>
<p>{{ event.org_id.name }}</p>
<h3>Date</h3>
<p>{{ event.date }}</p>
You can boost efficiency by fetching the Event and Organisation data in the same query with:
from django.shortcuts import get_object_or_404
def event_details(request, pk):
event = get_object_or_404(Event.objects.select_related('org_id'), event_id=pk)
context = {'event':event}
Note: It is often better to use get_object_or_404(…) [Django-doc],
then to use .get(…) [Django-doc] directly. In case the object does not exists,
for example because the user altered the URL themselves, the get_object_or_404(…) will result in returning a HTTP 404 Not Found response, whereas using
.get(…) will result in a HTTP 500 Server Error.
Note: Normally one does not add a suffix _id to a ForeignKey field, since Django
will automatically add a "twin" field with an _id suffix. Therefore it should
be org, instead of org_id.
in your template change it to:
<h3>Hosting Body</h3>
{% for org in orgs%}
{%if org.org_id == event.org_id.org_id %}
<p>{{org.name}}</p>
{%endif%}
{%endfor%}
<h3>Date</h3>
<p>{{event.date}}</p>

Template variables based on calculations using fields from Django Model

I am using Django 1.10.7 and Python 3.6.1. First my code, then my questions.
My model looks like this:
class Thing(models.Model):
user = models.ForeignKey('auth.User')
title = models.CharField(max_length=200)
start_date = models.DateTimeField(
default=timezone.now)
cost_per_day = models.DecimalField(max_digits=6, decimal_places=2)
Here are my views:
def something_list(request):
things =Thing.objects.filter(start_date__lte=timezone.now()).order_by('start_date')
return render(request, 'myApp/something_list.html', {'things': things})
def thing_detail(request, pk):
thing = get_object_or_404(Thing, pk=pk)
return render(request, 'myApp/thing_detail.html', {'thing': thing})
I have two template blocks for each of these views, where I am using template tags to display variables. For example:
<h2 class="title">{{ thing.title }}</h2>
<p>User: {{ thing.user }}</p>
<div class="date">
<p>Start Date: {{ thing.start_date }}</p>
</div>
<p>Cost per day: ${{ thing.cost_per_day }}</p>
So what is happening here?
Web users can enter what I am calling any number of "Things" with 4 fields: User, Title, Start Date, and Cost per Day. I have TWO calculations that I would like to make, and render them in the template.
Problem 1) The user needs to see how many days have elapsed since they originally entered a Start Date. The calculation will be a subtraction of the current time/date (Now) and the Start Date. I was able to accomplish this by using the Django timesince feature shown here:
<button type="button" class="btn btn-info">{{ thing.quit_date|timesince }}</button>
This renders how many days and hours have elapsed - lets call it 'time elapsed' - perfectly. The problem lies in my next calculation.
Problem 2) I need to display a calculation of 'time elapsed' (shown above) multiplied by the Cost per Day variable in the current Model instance. Just for clarity, let's say the start date was 30.5 days ago, and the cost per day is $5.00. I need to multiply 30.5 by $5.00. I would love to simply multiply template tags but I understand that's not how it works. For example:
{{ thing.quit_date|timesince }} * {{ thing.cost_per_day }}
Is there a way to capture the result of this timesince calculation... {{ thing.quit_date|timesince }}... as a variable? I may not be able to use the timesince feature for this calculation.
Once again, what I ultimately need to do here is to multiply the "time elapsed" by the cost per day, like this: (Time Now - Start Date) * (Cost Per Day).
I don't know how to do this in models.py or views.py. I'm looking for the best practice way to do this using Django and Python 3.6. I'm a newbie and I have searched all day for an answer to my particular problem.
Thanks in advance and please let me know if I need to provide more information!
UPDATE
Here is my updated model based on suggestions, albeit not working (the timesince property needs work):
from django.db import models
from django.utils import timezone
from datetime import datetime
class Thing(models.Model):
quitter = models.ForeignKey('auth.User')
title = models.CharField(max_length=200)
quit_date = models.DateTimeField(default=timezone.now)
cost_per_day = models.DecimalField(max_digits=6, decimal_places=2)
notes = models.TextField()
#property
def timesince(self):
"Time since quit date"
now = datetime.now()
then = self.quit_date
return (now - then)
#property
def savings(self):
"Savings since quitting"
return self.timesince * self.cost_per_day
Here is my updated template:
<h4>Here are some calculations for this information...</h4>
<p>Days since you quit:</p>
<button type="button" class="btn btn-info">{{ thing.timesince }}</button>
<hr>
<p>How much money you have saved:</p>
<button type="button" class="btn btn-info">{{ thing.savings }}</button>
I'm certain the problem lies in the subtraction of the dates. Any insight into that would be very helpful. The template variables {{ }} are working, but there is a missing piece in the model.
By the way, when I concatenated "days" to any datetime variable, it game me errors saying .days it gave me errors. Perhaps there is an issue using both a DateTimeField and a datetime.now() instance?
I would recommend creating a property on the model itself to calculate this. Subtracting the quit date from the current date will give you a timedelta object. From there we can get the days and take it times the cost.
from django.utils import timezone
class Thing(models.Model):
...
#property
def cost(self):
days = (timezone.now().date() - self.quit_date).days
return days * self.cost_per_day
Then your template becomes very simple.
{{ thing.cost }}
This really isn't what template tags are for, at all. They're meant to display variables and call it a day, with some minor functional utility bolted on.
For your equations, best practice would be to implement them in the model.
from datetime import datetime
class Thing(models.Model):
quit_date = models.DateTimeField()
cost_per_day = models.FloatField() ???
#property
def timesince(self):
# Time since last whatever
elapsed = datetime.now() - self.quit_date
return elapsed.days
#property
def calculate_cost(self):
return self.timesince * self.cost_per_day
Then you can just display each of the values using {{ thing.timesince }} and {{ thing.calculate_cost }} in the template.
Here is an answer that works. I think the problem was that I was using "datetime.now()" instead of "timezone.now()". This might not be the best way of approaching this in Django/Python. I'd appreciate comments on how to make it "best practice". I really appreciate the assistance on this one!
#property
def timesince(self):
"Time since quit date"
now = timezone.now()
then = self.quit_date
return (now - then).days
#property
def savings(self):
"Savings since quitting"
return self.timesince * self.cost_per_day

Django: retrieving ManyToManyField objects with minimum set of queries

My code looks like this:
models.py
class Tag(models.Model):
name = models.CharField(max_length=42)
class Post(models.Model):
user = models.ForeignKey(User, related_name='post')
#...various fields...
tags = models.ManyToManyField(Tag, null=True)
views.py
posts = Post.objects.all().values('id', 'user', 'title')
tags_dict = {}
for post in posts: # Iteration? Why?
p = Post.objects.get(pk=[post['id']]) # one extra query? Why?
tags_dict[post['id']] = p.tags.all()
How am I supposed to create a dictionary with tags for each Post object with minimum set of queries? Is it possible to avoid iterating, too?
Yes you will need a loop. But you can save one extra query in each iteration, you don't need to get post object to get all its tags. You can directly query on Tag model to get tags related to post id:
for post in posts:
tags_dict[post['id']] = Tag.objects.filter(post__id=post['id'])
Or use Dict Comprehension for efficiency:
tags_dict = {post['id']: Tag.objects.filter(post__id=post['id']) for post in posts}
If you have Django version >= 1.4 and don't really need a dictionary, but need to cut down the count of queries, you can use this method like this:
posts = Post.objects.all().only('id', 'user', 'title').prefetch_related('tags')
It seems to execute only 2 queries (one for Post and another for Tag with INNER JOIN).
And then you can access post.tags.all without extra queries, because tags was already prefetched.
{% for post in posts %}
{% for tag in post.tags.all %}
{{ tag.name }}
{% endfor %}
{% endfor %}

Django: using aggregates to show vote counts for basic polls app

I'm making a very basic poll app. It's similar to the one in the Django tutorial but I chose to break out the vote counting aspect into its own model (the tutorial just adds a vote count field alongside each answer). Here's my models:
class PollQuestion(models.Model):
question = models.CharField(max_length=75)
class PollAnswer(models.Model):
poll = models.ForeignKey('PollQuestion')
answer = models.CharField(max_length=75)
class PollVote(models.Model):
poll = models.ForeignKey('PollQuestion')
answer = models.ForeignKey('PollAnswer')
date_voted = models.DateTimeField(auto_now_add=True)
user_ip = models.CharField(max_length=75)
I'm trying to show all of the vote counts for a given poll. Here's my view code:
from django.db.models import Count
poll_votes = PollVote.objects.select_related('PollAnswer').filter(poll=poll_id).annotate(num_votes=Count('answer__id'))
When I output the results of this query I just get a single row per vote (eg I see about 40 'answers' for my poll, each one representing a vote for one of the 5 actual PollAnswers). If I look at the queries Django makes, it runs something like this for every vote in the poll:
SELECT `poll_answers`.`id`, `poll_answers`.`poll_id`, `poll_answers`.`answer`
FROM `poll_answers`
WHERE `poll_answers`.`id` = 101
Can anyone poke me in the right direction here? I get the feeling this should be easy.
EDIT: here's my template code, for completeness.
<ul>
{% for vote in votes %}
{{ vote.answer }} ({{ votes.num_votes }})<br />
{% endfor %}
</ul>
Try:
poll_votes = PollVote.objects.filter(poll=poll_id).annotate(num_votes=Count('answer__id'))
or:
poll_votes = PollVote.objects.values('poll', 'answer__answer').filter(poll=poll_id).annotate(num_votes=Count('answer__id'))
Relevant docs:
Django offical docs
Never mind, fixed it myself after finding a tutorial which uses the same sort of models as me.
Essentially the fix was in the view:
p = get_object_or_404(PollQuestion, pk=poll_id)
choices = p.pollanswer_set.all()
And in the template:
{% for choice in choices %}
<p class="resultsList">{{choice.answer}} - {{choice.pollvote_set.count}}</p>
{% endfor %}

Query with Django ORM (joining models?)

I have the following models:
class Thread(models.Model):
name = models.CharField(max_length=50)
category = models.ForeignKey(Category)
class Post(models.Model):
thread = models.ForeignKey(Thread)
datetime = models.DateTimeField(auto_now_add=True)
author = models.ForeignKey(User)
This is for my forum system.
I need to fetch all the Threads of category X and I need to have a few custom attributes like datetime and pk of the last post to the thread, for example:
threads = Thread.objects.filter(category=x)
last_post = Post.objects.filter(thread=threads[0]).order_by('-pk')[0]
Then I want to transfer everything to the template so that I get:
{{ t.pk }} as thread_pk
{{ t.last_post_pk }} as last_post_pk
And so on.
To get last post for every thread you should use aggregation:
Post.objects.filter(thread__in=threads).values('thread').annotate(last_id=Max('id')).order_by()
This will get you last_id from every thread in threads.
Since Django doesn't do joining like you would expect with SQL joins (see my comment for further explanation), I would solve it in the view (or perhaps a method added to the Thread class). Consider the following example view:
def index(request):
res = []
for t in Thread.objects.filter(category__name='x'):
res.append((t, Post.objects.filter(thread=t).order_by('-datetime')[0]))
# Optionally sort by datetime here:
# res.sort(key=lambda x: x[1].datetime, reverse=True)
return render_to_response('index.html', {'result': res})
You could then use it in the template as follows:
{% for r in res %}
Thread {{ r.0.name }}, last post by {{ r.1.author.name }} on {{ r.1.datetime }}.
{% endfor %}
# This would give something like this:
# Thread mythread, last post by john on Oct. 21, 2011, 1:52 a.m..
By creating a tuple of Threads and Posts, you don't really join them, but do make them easily available in the template.