Management commands in Django are those which are recognized by
manage.py
and django-admin.py
, e.g. syncdb
, shell
, runserver
, etc. It's not difficult to inject your own custom commands for your app. We'll need one that will be set as a scheduled task to check the current weather.To create a management command, you have to create directories
management/commands/
inside of your climate_change
directory and create empty files __init__.py
in each of them.
mkdir -p climate_change/management/commands
touch climate_change/management/__init__.py
touch climate_change/management/commands/__init__.py
Now I'll create a file
climate_change/management/commands/check_weather.py
which will aggregate the data from the feed. Just looking at the examples of Django core commands, you can find, that management-command modules should have a class Command
with an overridden method handle_norargs
which will have all the logic of the command. I found an example of importing weather from Yahoo! and will be using it here.
# -*- coding: UTF-8 -*-
import urllib
from xml.dom import minidom
from pprint import pprint
from datetime import datetime
from django.db import models
from django.core.management.base import NoArgsCommand
Location = models.get_model("climate_change", "Location")
WeatherLog = models.get_model("climate_change", "WeatherLog")
SILENT, NORMAL, VERBOSE = 0, 1, 2
WEATHER_URL = 'http://xml.weather.yahoo.com/forecastrss?p=%s&u=c'
WEATHER_NS = 'http://xml.weather.yahoo.com/ns/rss/1.0'
def weather_for_location(location_id):
# taken from http://developer.yahoo.com/python/python-xml.html
# and modified a little
url = WEATHER_URL % location_id
dom = minidom.parse(urllib.urlopen(url))
forecasts = []
for node in dom.getElementsByTagNameNS(WEATHER_NS, 'forecast'):
forecasts.append({
'date': node.getAttribute('date'),
'low': node.getAttribute('low'),
'high': node.getAttribute('high'),
'condition': node.getAttribute('text')
})
ycondition = dom.getElementsByTagNameNS(WEATHER_NS, 'condition')[0]
ywind = dom.getElementsByTagNameNS(WEATHER_NS, 'wind')[0]
yatmosphere = dom.getElementsByTagNameNS(WEATHER_NS, 'atmosphere')[0]
return {
'current_condition': ycondition.getAttribute('text'),
'current_temp': ycondition.getAttribute('temp'),
'current_humidity': yatmosphere.getAttribute('humidity'),
'current_visibility': yatmosphere.getAttribute('visibility'),
'current_wind_speed': ywind.getAttribute('speed'),
'forecasts': forecasts,
'title': dom.getElementsByTagName('title')[0].firstChild.data,
'guid': dom.getElementsByTagName('guid')[0].firstChild.data,
}
class Command(NoArgsCommand):
help = "Aggregates data from weather feed"
def handle_noargs(self, **options):
verbosity = int(options.get('verbosity', NORMAL))
created_count = 0
for l in Location.objects.all():
weather = weather_for_location(l.location_id)
if verbosity > NORMAL:
pprint(weather)
timestamp_parts = map(int, weather['guid'].split("_")[1:-1])
timestamp = datetime(*timestamp_parts)
log, created = WeatherLog.objects.get_or_create(
location=l,
timestamp=timestamp,
defaults={
'temperature': weather['current_temp'],
'humidity': weather['current_humidity'],
'wind_speed': weather['current_wind_speed'],
'visibility': weather['current_visibility'],
}
)
if created:
created_count += 1
if verbosity > NORMAL:
print "New weather logs: %d" % created_count
Now we can try running the command from the project directory using the following:
python manage.py check_weather --verbosity=2
I get this result:
{'current_condition': u'Mostly Cloudy',
'current_humidity': u'94',
'current_temp': u'10',
'current_visibility': u'9.99',
'current_wind_speed': u'16.09',
'forecasts': [{'condition': u'Partly Cloudy',
'date': u'6 Oct 2009',
'high': u'19',
'low': u'14'},
{'condition': u'PM Light Rain',
'date': u'7 Oct 2009',
'high': u'23',
'low': u'14'}],
'guid': u'GMXX0008_2009_10_06_10_20_CEST',
'title': u'Yahoo! Weather - Berlin/Schonefeld, GM'}
New weather logs: 1
To define this task as a cron job running hourly, you can either type
echo 0 * * * * cd /path/to/climate_change_env/ && source bin/activate && cd blog_action_day_2009 && python manage.py check_weather && deactivate > crontab.txt
crontab crontab.txt
del crontab.txt
.. or use django-poormanscron app and set the check_weather
command there.OK. Cool. The next thing to do is the template tag which displays the details of recent weather.
No comments:
Post a Comment