Index: trunk/tools/editor_trends/wikilytics/api/views.py |
— | — | @@ -1 +1,68 @@ |
2 | | -# Create your views here.
|
| 2 | +import datetime |
| 3 | +import time |
| 4 | +import json |
| 5 | + |
| 6 | +from django.shortcuts import render_to_response |
| 7 | +from django.http import HttpResponseRedirect, HttpResponse |
| 8 | +from django.core.urlresolvers import reverse |
| 9 | +from django.conf import settings |
| 10 | +from django.core import serializers |
| 11 | + |
| 12 | + |
| 13 | +from wikilytics.api.forms import SearchForm |
| 14 | +from wikilytics.api.models import Editor, Dataset, Job, Dump |
| 15 | +import wikilytics.api.helpers as helpers |
| 16 | + |
| 17 | + |
| 18 | +def search(request): |
| 19 | + #print request |
| 20 | + if request.GET: |
| 21 | + #form = SearchForm(request.GET) |
| 22 | + #print form |
| 23 | + project = request.GET.get('project', '') |
| 24 | + language = request.GET.get('language', '') |
| 25 | + #year = request.GET.get('date_year', '') |
| 26 | + #month = request.GET.get('date_month', '') |
| 27 | + return HttpResponseRedirect(reverse('dataset_dispatcher', args=[project, language])) |
| 28 | + else: |
| 29 | + form = SearchForm() |
| 30 | + |
| 31 | + return render_to_response('search.html', {'form': form}) |
| 32 | + |
| 33 | + |
| 34 | +def dataset_dispatcher(request, project, language): |
| 35 | + dbname = '%s%s' % (language, project) |
| 36 | + editors = Editor.objects.count() |
| 37 | + if editors == 0: |
| 38 | + #Dataset has not yet been made, put job in queue to create the dataset |
| 39 | + hash = helpers.create_hash(project, language) |
| 40 | + job, created = Job.objects.get_or_create(hash=hash, defaults={'project':project, 'language_code': language, 'hash':hash}) |
| 41 | + print job.hash |
| 42 | + if created: |
| 43 | + job.save() |
| 44 | + jobs = Job.objects.filter(jobtype='dataset', finished=False, in_progress=True) |
| 45 | + return render_to_response('queue.html', {'jobs': jobs}) |
| 46 | + else: |
| 47 | + ds = Dataset.objects.filter(project=project, language_code=language) |
| 48 | + print ds |
| 49 | + return render_to_response('datasets_available.html', {'datasets': ds}) |
| 50 | + |
| 51 | + |
| 52 | +def chart_dispatcher(request, project, language): |
| 53 | + #project = '%s%s' % (project, language) |
| 54 | + analyses = Job.objects.filter(jobtype='chart') |
| 55 | + print analyses |
| 56 | + return render_to_response('analyses_available.html', {'analyses': analyses}) |
| 57 | + |
| 58 | + |
| 59 | +def chart_generator(request, project, language, chart): |
| 60 | + xhr = request.GET.has_key('json') |
| 61 | + print xhr |
| 62 | + ds = Dataset.objects.using('enwiki').get(project=project, language_code=language, name=chart) |
| 63 | + if xhr: |
| 64 | + dthandler = lambda obj:'new Date("%s")' % datetime.date.ctime(obj) if isinstance(obj, datetime.datetime) else obj |
| 65 | + data = helpers.transform_to_stacked_bar_json(ds) |
| 66 | + return HttpResponse(json.dumps(data, default=dthandler), mimetype='application/json') |
| 67 | + else: |
| 68 | + url = ds.get_absolute_url() |
| 69 | + return render_to_response('chart.html', {'url': url}) |
Property changes on: trunk/tools/editor_trends/wikilytics/api/views.py |
___________________________________________________________________ |
Added: svn:eol-style |
3 | 70 | + native |
Property changes on: trunk/tools/editor_trends/wikilytics/api/__init__.py |
___________________________________________________________________ |
Added: svn:eol-style |
4 | 71 | + native |
Index: trunk/tools/editor_trends/wikilytics/api/helpers.py |
— | — | @@ -1,17 +1,72 @@ |
2 | | -def init_database(dbname):
|
3 | | - if dbname not in settings.DATABASES:
|
4 | | - settings.DATABASES[dbname] = {
|
5 | | - 'ENGINE': 'django_mongodb_engine',
|
6 | | - 'NAME': '%s' % dbname,
|
7 | | - 'USER': '',
|
8 | | - 'PASSWORD': '',
|
9 | | - 'HOST': 'localhost',
|
10 | | - 'PORT': '27017',
|
11 | | - }
|
12 | | -
|
13 | | -
|
14 | | -def create_hash(project, language):
|
15 | | - today = datetime.datetime.today()
|
16 | | - datum = datetime.date(today.year, today.month, 1)
|
17 | | - secs = time.mktime(datum.timetuple())
|
18 | | - return hash('%s%s' % (project, language)) + hash(secs)
|
| 2 | +import datetime |
| 3 | +import time |
| 4 | + |
| 5 | + |
| 6 | +from editor_trends.utils import data_converter |
| 7 | + |
| 8 | + |
| 9 | +def transform_to_stacked_bar_json(ds): |
| 10 | + ''' |
| 11 | + This function outputs data in a format that is understood by jquery |
| 12 | + flot plugin. Example JSON object: |
| 13 | + var data = [ |
| 14 | + {label: 'foo', data: [[1, 300], [2, 300], [3, 300], [4, 300], [5, 300]]}, |
| 15 | + {label: 'bar', data: [[1, 800], [2, 600], [3, 400], [4, 200], [5, 0]]}, |
| 16 | + {label: 'baz', data: [[1, 100], [2, 200], [3, 300], [4, 400], [5, 500]]}, |
| 17 | + ]; |
| 18 | + var options = { |
| 19 | + series: {stack: 0, |
| 20 | + lines: {show: false, steps: false }, |
| 21 | + bars: {show: true, barWidth: 0.9, align: 'center', }, }, |
| 22 | + xaxis: {ticks: [[1, 'One'], [2, 'Two'], [3, 'Three'], [4, 'Four'], [5, 'Five']]}, |
| 23 | + }; |
| 24 | + ''' |
| 25 | + options = {} |
| 26 | + options['xaxis'] = {} |
| 27 | + options['xaxis']['ticks'] = [] |
| 28 | + options['series'] = {} |
| 29 | + options['series']['stack'] = 0 |
| 30 | + options['series']['lines'] = {} |
| 31 | + options['series']['lines']['show'] = False |
| 32 | + options['series']['lines']['steps'] = False |
| 33 | + options['series']['bars'] = {} |
| 34 | + options['series']['bars']['show'] = True |
| 35 | + options['series']['bars']['barWidth'] = 0.9 |
| 36 | + options['series']['bars']['align'] = 'center' |
| 37 | + |
| 38 | + data = [] |
| 39 | + obs, all_keys = data_converter.convert_dataset_to_lists(ds, 'django') |
| 40 | + |
| 41 | + for ob in obs: |
| 42 | + d = {} |
| 43 | + d['label'] = str(ob[0].year) |
| 44 | + d['data'] = [] |
| 45 | + ob = ob[1:] |
| 46 | + for x, o in enumerate(ob): |
| 47 | + d['data'].append([x, o]) |
| 48 | + data.append(d) |
| 49 | + for x, date in enumerate(obs): |
| 50 | + options['xaxis']['ticks'].append([x, date[0].year]) |
| 51 | + |
| 52 | + d = {} |
| 53 | + d['data'] = data |
| 54 | + d['options'] = options |
| 55 | + return d |
| 56 | + |
| 57 | +def create_hash(project, language): |
| 58 | + today = datetime.datetime.today() |
| 59 | + datum = datetime.date(today.year, today.month, 1) |
| 60 | + secs = time.mktime(datum.timetuple()) |
| 61 | + return hash('%s%s' % (project, language)) + hash(secs) |
| 62 | + |
| 63 | + |
| 64 | +#def init_database(dbname): |
| 65 | +# if dbname not in settings.DATABASES: |
| 66 | +# settings.DATABASES[dbname] = { |
| 67 | +# 'ENGINE': 'django_mongodb_engine', |
| 68 | +# 'NAME': '%s' % dbname, |
| 69 | +# 'USER': '', |
| 70 | +# 'PASSWORD': '', |
| 71 | +# 'HOST': 'localhost', |
| 72 | +# 'PORT': '27017', |
| 73 | +# } |
Property changes on: trunk/tools/editor_trends/wikilytics/api/helpers.py |
___________________________________________________________________ |
Added: svn:eol-style |
19 | 74 | + native |
Index: trunk/tools/editor_trends/wikilytics/api/tests.py |
— | — | @@ -1,23 +1,23 @@ |
2 | | -"""
|
3 | | -This file demonstrates two different styles of tests (one doctest and one
|
4 | | -unittest). These will both pass when you run "manage.py test".
|
5 | | -
|
6 | | -Replace these with more appropriate tests for your application.
|
7 | | -"""
|
8 | | -
|
9 | | -from django.test import TestCase
|
10 | | -
|
11 | | -class SimpleTest(TestCase):
|
12 | | - def test_basic_addition(self):
|
13 | | - """
|
14 | | - Tests that 1 + 1 always equals 2.
|
15 | | - """
|
16 | | - self.failUnlessEqual(1 + 1, 2)
|
17 | | -
|
18 | | -__test__ = {"doctest": """
|
19 | | -Another way to test that 1 + 1 is equal to 2.
|
20 | | -
|
21 | | ->>> 1 + 1 == 2
|
22 | | -True
|
23 | | -"""}
|
24 | | -
|
| 2 | +""" |
| 3 | +This file demonstrates two different styles of tests (one doctest and one |
| 4 | +unittest). These will both pass when you run "manage.py test". |
| 5 | + |
| 6 | +Replace these with more appropriate tests for your application. |
| 7 | +""" |
| 8 | + |
| 9 | +from django.test import TestCase |
| 10 | + |
| 11 | +class SimpleTest(TestCase): |
| 12 | + def test_basic_addition(self): |
| 13 | + """ |
| 14 | + Tests that 1 + 1 always equals 2. |
| 15 | + """ |
| 16 | + self.failUnlessEqual(1 + 1, 2) |
| 17 | + |
| 18 | +__test__ = {"doctest": """ |
| 19 | +Another way to test that 1 + 1 is equal to 2. |
| 20 | + |
| 21 | +>>> 1 + 1 == 2 |
| 22 | +True |
| 23 | +"""} |
| 24 | + |
Property changes on: trunk/tools/editor_trends/wikilytics/api/tests.py |
___________________________________________________________________ |
Added: svn:eol-style |
25 | 25 | + native |
Index: trunk/tools/editor_trends/wikilytics/api/models.py |
— | — | @@ -1,30 +1,102 @@ |
2 | | -from django.db import models
|
3 | | -from django.contrib import databrowse
|
4 | | -from django.contrib import admin
|
5 | | -from djangotoolbox.fields import DictField, ListField
|
6 | | -
|
7 | | -
|
8 | | -class Editor(models.Model):
|
9 | | - username = models.CharField(max_length=64)
|
10 | | - editor = models.IntegerField()
|
11 | | - first_edit = models.DateField()
|
12 | | - final_edit = models.DateField()
|
13 | | - new_wikipedian = models.DateField()
|
14 | | - monthly_edits = DictField()
|
15 | | - edit_count = models.IntegerField()
|
16 | | - articles_by_year = DictField()
|
17 | | - edits_by_year = DictField()
|
18 | | - edits = ListField()
|
19 | | -
|
20 | | - class Meta:
|
21 | | - db_table = 'editors_dataset'
|
22 | | -
|
23 | | - def __unicode__(self):
|
24 | | - return u'%s, total edits: %s' % (self.username, self.edit_count)
|
25 | | -
|
26 | | -
|
27 | | -class EditorAdmin(admin.ModelAdmin):
|
28 | | - pass
|
29 | | -
|
30 | | -admin.site.register(Editor, EditorAdmin)
|
31 | | -databrowse.site.register(Editor)
|
| 2 | +from django.db import models |
| 3 | +from django.contrib import databrowse |
| 4 | +from django.contrib import admin |
| 5 | +from django.core.urlresolvers import reverse |
| 6 | +from django.db.models import permalink |
| 7 | + |
| 8 | +from djangotoolbox.fields import DictField, ListField |
| 9 | + |
| 10 | + |
| 11 | +class Dataset(models.Model): |
| 12 | + name = models.CharField(max_length=128) |
| 13 | + project = models.CharField(max_length=48) |
| 14 | + collection = models.CharField(max_length=48) |
| 15 | + format = models.CharField(max_length=12) |
| 16 | + _type = models.CharField(max_length=15) |
| 17 | + filename = models.CharField(max_length=48) |
| 18 | + created = models.DateField() |
| 19 | + language_code = models.CharField(max_length=15) |
| 20 | + variables = DictField() |
| 21 | + |
| 22 | + class Meta: |
| 23 | + db_table = 'enwiki_charts' |
| 24 | + |
| 25 | + def __iter__(self): |
| 26 | + for key, value in self.variables.items(): |
| 27 | + #print 'KEY: %s; ValUE: %s' % (key, value) |
| 28 | + if isinstance(value, dict): |
| 29 | + print value |
| 30 | + for k, v in value.items(): |
| 31 | + print k, v |
| 32 | + yield k, v |
| 33 | + |
| 34 | + def get_absolute_url(self): |
| 35 | + return reverse('chart_generator', args=[self.project, self.language_code, self.name]) |
| 36 | + |
| 37 | + |
| 38 | +class Editor(models.Model): |
| 39 | + username = models.CharField(max_length=64) |
| 40 | + editor = models.IntegerField() |
| 41 | + first_edit = models.DateField() |
| 42 | + final_edit = models.DateField() |
| 43 | + new_wikipedian = models.DateField() |
| 44 | + monthly_edits = DictField() |
| 45 | + edit_count = models.IntegerField() |
| 46 | + articles_by_year = DictField() |
| 47 | + edits_by_year = DictField() |
| 48 | + edits = ListField() |
| 49 | + |
| 50 | + class Meta: |
| 51 | + db_table = 'editors_dataset' |
| 52 | + |
| 53 | + def __unicode__(self): |
| 54 | + return u'%s, total edits: %s' % (self.username, self.edit_count) |
| 55 | + |
| 56 | +class EditorAdmin(admin.ModelAdmin): |
| 57 | + pass |
| 58 | + |
| 59 | + |
| 60 | +class Job(models.Model): |
| 61 | + hash = models.CharField(max_length=48) |
| 62 | + project = models.CharField(max_length=15) |
| 63 | + language_code = models.CharField(max_length=15) |
| 64 | + created = models.DateField(auto_now_add=True) |
| 65 | + finished = models.BooleanField(default=False) |
| 66 | + in_progress = models.BooleanField(default=False) |
| 67 | + jobtype = models.CharField(max_length=15, default='dataset') |
| 68 | + |
| 69 | + def __unicode__(self): |
| 70 | + return u'%s%s' % (self.language_code, self.project) |
| 71 | + |
| 72 | + |
| 73 | + @permalink |
| 74 | + def get_absolute_url(self): |
| 75 | + if self.jobtype == 'chart': |
| 76 | + print reverse('chart_generator', args=[self.project, self.language_code, self.hash]) |
| 77 | + return ('chart_generator', (), |
| 78 | + {'project': self.project, |
| 79 | + 'language': self.language_code, |
| 80 | + 'chart': self.hash}) |
| 81 | + elif self.jobtype == 'dataset': |
| 82 | + return ('dataset_dispatcher', (), |
| 83 | + {'project': self.project, |
| 84 | + 'language': self.language_code, |
| 85 | + 'dataset': self.hash}) |
| 86 | + class Meta: |
| 87 | + db_table = 'jobs' |
| 88 | + |
| 89 | +class JobAdmin(admin.ModelAdmin): |
| 90 | + pass |
| 91 | + |
| 92 | + |
| 93 | + |
| 94 | +class Dump(models.Model): |
| 95 | + project = models.CharField(max_length=15) |
| 96 | + dumps = DictField() |
| 97 | + |
| 98 | + class Meta: |
| 99 | + db_table = 'available_dumps' |
| 100 | +#admin.site.register(Editor, EditorAdmin) |
| 101 | +#admin.site.register(Job, JobAdmin) |
| 102 | +#databrowse.site.register(Editor) |
| 103 | +#databrowse.site.register(Job) |
Property changes on: trunk/tools/editor_trends/wikilytics/api/models.py |
___________________________________________________________________ |
Added: svn:eol-style |
32 | 104 | + native |
Index: trunk/tools/editor_trends/wikilytics/api/tasks.py |
— | — | @@ -1,57 +1,57 @@ |
2 | | -from multiprocessing import Process
|
3 | | -
|
4 | | -from celery.decorators import task
|
5 | | -from celery.registry import tasks
|
6 | | -
|
7 | | -from editor_trends.utils import wikiprojects
|
8 | | -from editor_trends import manage as manager
|
9 | | -
|
10 | | -from wikilytics.api.models import Job
|
11 | | -
|
12 | | -@task
|
13 | | -def launcher():
|
14 | | - jobs = Job.objects.filter(finished=False)
|
15 | | - n = len(jobs)
|
16 | | - if n > 0:
|
17 | | -
|
18 | | - job = jobs[0]
|
19 | | - job.in_progress = True
|
20 | | - job.save()
|
21 | | - print 'Launching %s task' % job.type
|
22 | | - if job.type == 'dataset':
|
23 | | - res = launch_editor_trends_toolkit(job.project, job.language)
|
24 | | - elif job.type == 'chart':
|
25 | | - res = launch_chart(job.project, job.language)
|
26 | | - else:
|
27 | | - print 'Unknown job type, no handler has been configured.'
|
28 | | -
|
29 | | - if res == True:
|
30 | | - job.finished = True
|
31 | | - job.in_progress = False
|
32 | | - job.save()
|
33 | | -
|
34 | | -
|
35 | | -def launch_editor_trends_toolkit(project, language):
|
36 | | - '''
|
37 | | - This function should only be called from within Django Wikilytics.
|
38 | | - '''
|
39 | | - res = False
|
40 | | - parser, settings, wiki = manager.init_args_parser()
|
41 | | - args = parser.parse_args(['dummy'])
|
42 | | - args.language = language
|
43 | | - args.project = project
|
44 | | - print args
|
45 | | - wiki = wikiprojects.Wiki(settings, args)
|
46 | | - p = Process(target=manager.all_launcher, args=(wiki, settings, None))
|
47 | | - p.start()
|
48 | | - #res = manager.all_launcher(wiki, settings, None)
|
49 | | - return res
|
50 | | -
|
51 | | -def launch_chart(project, language):
|
52 | | - res = False
|
53 | | -
|
54 | | -
|
55 | | - return False
|
56 | | -
|
57 | | -
|
58 | | -tasks.register(launcher)
|
| 2 | +from multiprocessing import Process |
| 3 | + |
| 4 | +from celery.decorators import task |
| 5 | +from celery.registry import tasks |
| 6 | + |
| 7 | +from editor_trends.classes import wikiprojects |
| 8 | +from editor_trends import manage as manager |
| 9 | + |
| 10 | +from wikilytics.api.models import Job |
| 11 | + |
| 12 | +@task |
| 13 | +def launcher(): |
| 14 | + jobs = Job.objects.filter(finished=False) |
| 15 | + n = len(jobs) |
| 16 | + if n > 0: |
| 17 | + |
| 18 | + job = jobs[0] |
| 19 | + job.in_progress = True |
| 20 | + job.save() |
| 21 | + print 'Launching %s task' % job.type |
| 22 | + if job.type == 'dataset': |
| 23 | + res = launch_editor_trends_toolkit(job.project, job.language) |
| 24 | + elif job.type == 'chart': |
| 25 | + res = launch_chart(job.project, job.language) |
| 26 | + else: |
| 27 | + print 'Unknown job type, no handler has been configured.' |
| 28 | + |
| 29 | + if res == True: |
| 30 | + job.finished = True |
| 31 | + job.in_progress = False |
| 32 | + job.save() |
| 33 | + |
| 34 | + |
| 35 | +def launch_editor_trends_toolkit(project, language): |
| 36 | + ''' |
| 37 | + This function should only be called from within Django Wikilytics. |
| 38 | + ''' |
| 39 | + res = False |
| 40 | + parser, settings, wiki = manager.init_args_parser() |
| 41 | + args = parser.parse_args(['dummy']) |
| 42 | + args.language = language |
| 43 | + args.project = project |
| 44 | + print args |
| 45 | + wiki = wikiprojects.Wiki(settings, args) |
| 46 | + p = Process(target=manager.all_launcher, args=(wiki, settings, None)) |
| 47 | + p.start() |
| 48 | + #res = manager.all_launcher(wiki, settings, None) |
| 49 | + return res |
| 50 | + |
| 51 | +def launch_chart(project, language): |
| 52 | + res = False |
| 53 | + |
| 54 | + |
| 55 | + return False |
| 56 | + |
| 57 | + |
| 58 | +tasks.register(launcher) |
Property changes on: trunk/tools/editor_trends/wikilytics/api/tasks.py |
___________________________________________________________________ |
Added: svn:eol-style |
59 | 59 | + native |
Index: trunk/tools/editor_trends/wikilytics/api/forms.py |
— | — | @@ -1,23 +1,23 @@ |
2 | | -import datetime
|
3 | | -from django import forms
|
4 | | -
|
5 | | -from wikilytics.api.widgets import MonthYearWidget
|
6 | | -from editor_trends.utils import wikiprojects
|
7 | | -
|
8 | | -
|
9 | | -wiki = wikiprojects.Wiki('settings')
|
10 | | -
|
11 | | -
|
12 | | -years = [year for year in xrange(2001, datetime.date.today().year + 1)]
|
13 | | -#print wiki.supported_languages()
|
14 | | -#print wiki.supported_projects()
|
15 | | -
|
16 | | -class SearchForm(forms.Form):
|
17 | | - project = forms.CharField(initial='wiki',
|
18 | | - widget=forms.Select(choices=wiki.supported_projects()))
|
19 | | -
|
20 | | - language = forms.CharField(initial='en',
|
21 | | - widget=forms.Select(choices=wiki.supported_languages(output='django')))
|
22 | | - print 'Project: %s' % language
|
23 | | - date = forms.DateField(widget=MonthYearWidget(years=years))
|
24 | | -
|
| 2 | +import datetime |
| 3 | +from django import forms |
| 4 | + |
| 5 | +from wikilytics.api.widgets import MonthYearWidget |
| 6 | +from editor_trends.classes import wikiprojects |
| 7 | + |
| 8 | + |
| 9 | +wiki = wikiprojects.Wiki('settings') |
| 10 | + |
| 11 | + |
| 12 | +years = [year for year in xrange(2001, datetime.date.today().year + 1)] |
| 13 | +#print wiki.supported_languages() |
| 14 | +#print wiki.supported_projects() |
| 15 | + |
| 16 | +class SearchForm(forms.Form): |
| 17 | + project = forms.CharField(initial='wiki', |
| 18 | + widget=forms.Select(choices=wiki.supported_projects())) |
| 19 | + |
| 20 | + language = forms.CharField(initial='en', |
| 21 | + widget=forms.Select(choices=wiki.supported_languages(output='django'))) |
| 22 | + #print 'Project: %s' % language |
| 23 | + #date = forms.DateField(widget=MonthYearWidget(years=years)) |
| 24 | + |
Property changes on: trunk/tools/editor_trends/wikilytics/api/forms.py |
___________________________________________________________________ |
Added: svn:eol-style |
25 | 25 | + native |
Index: trunk/tools/editor_trends/wikilytics/api/widgets.py |
— | — | @@ -1,84 +1,84 @@ |
2 | | -import datetime
|
3 | | -import re
|
4 | | -
|
5 | | -from django.forms.widgets import Widget, Select
|
6 | | -from django.utils.dates import MONTHS
|
7 | | -from django.utils.safestring import mark_safe
|
8 | | -
|
9 | | -__all__ = ('MonthYearWidget',)
|
10 | | -
|
11 | | -RE_DATE = re.compile(r'(\d{4})-(\d\d?)-(\d\d?)$')
|
12 | | -
|
13 | | -class MonthYearWidget(Widget):
|
14 | | - """
|
15 | | - A Widget that splits date input into two <select> boxes for month and year,
|
16 | | - with 'day' defaulting to the first of the month.
|
17 | | -
|
18 | | - Based on SelectDateWidget, in
|
19 | | -
|
20 | | - django/trunk/django/forms/extras/widgets.py
|
21 | | -
|
22 | | -
|
23 | | - """
|
24 | | - none_value = (0, '---')
|
25 | | - month_field = '%s_month'
|
26 | | - year_field = '%s_year'
|
27 | | -
|
28 | | - def __init__(self, attrs=None, years=None, required=True):
|
29 | | - # years is an optional list/tuple of years to use in the "year" select box.
|
30 | | - self.attrs = attrs or {}
|
31 | | - self.required = required
|
32 | | - if years:
|
33 | | - self.years = years
|
34 | | - else:
|
35 | | - this_year = datetime.date.today().year
|
36 | | - self.years = range(this_year, this_year + 10)
|
37 | | -
|
38 | | - def render(self, name, value, attrs=None):
|
39 | | - try:
|
40 | | - year_val, month_val = value.year, value.month
|
41 | | - except AttributeError:
|
42 | | - year_val = month_val = None
|
43 | | - if isinstance(value, basestring):
|
44 | | - match = RE_DATE.match(value)
|
45 | | - if match:
|
46 | | - year_val, month_val, day_val = [int(v) for v in match.groups()]
|
47 | | -
|
48 | | - output = []
|
49 | | -
|
50 | | - if 'id' in self.attrs:
|
51 | | - id_ = self.attrs['id']
|
52 | | - else:
|
53 | | - id_ = 'id_%s' % name
|
54 | | -
|
55 | | - month_choices = MONTHS.items()
|
56 | | - if not (self.required and value):
|
57 | | - month_choices.append(self.none_value)
|
58 | | - month_choices.sort()
|
59 | | - local_attrs = self.build_attrs(id=self.month_field % id_)
|
60 | | - s = Select(choices=month_choices)
|
61 | | - select_html = s.render(self.month_field % name, month_val, local_attrs)
|
62 | | - output.append(select_html)
|
63 | | -
|
64 | | - year_choices = [(i, i) for i in self.years]
|
65 | | - if not (self.required and value):
|
66 | | - year_choices.insert(0, self.none_value)
|
67 | | - local_attrs['id'] = self.year_field % id_
|
68 | | - s = Select(choices=year_choices)
|
69 | | - select_html = s.render(self.year_field % name, year_val, local_attrs)
|
70 | | - output.append(select_html)
|
71 | | -
|
72 | | - return mark_safe(u'\n'.join(output))
|
73 | | -
|
74 | | - def id_for_label(self, id_):
|
75 | | - return '%s_month' % id_
|
76 | | - id_for_label = classmethod(id_for_label)
|
77 | | -
|
78 | | - def value_from_datadict(self, data, files, name):
|
79 | | - y = data.get(self.year_field % name)
|
80 | | - m = data.get(self.month_field % name)
|
81 | | - if y == m == "0":
|
82 | | - return None
|
83 | | - if y and m:
|
84 | | - return '%s-%s-%s' % (y, m, 1)
|
85 | | - return data.get(name, None)
|
| 2 | +import datetime |
| 3 | +import re |
| 4 | + |
| 5 | +from django.forms.widgets import Widget, Select |
| 6 | +from django.utils.dates import MONTHS |
| 7 | +from django.utils.safestring import mark_safe |
| 8 | + |
| 9 | +__all__ = ('MonthYearWidget',) |
| 10 | + |
| 11 | +RE_DATE = re.compile(r'(\d{4})-(\d\d?)-(\d\d?)$') |
| 12 | + |
| 13 | +class MonthYearWidget(Widget): |
| 14 | + """ |
| 15 | + A Widget that splits date input into two <select> boxes for month and year, |
| 16 | + with 'day' defaulting to the first of the month. |
| 17 | + |
| 18 | + Based on SelectDateWidget, in |
| 19 | + |
| 20 | + django/trunk/django/forms/extras/widgets.py |
| 21 | + |
| 22 | + |
| 23 | + """ |
| 24 | + none_value = (0, '---') |
| 25 | + month_field = '%s_month' |
| 26 | + year_field = '%s_year' |
| 27 | + |
| 28 | + def __init__(self, attrs=None, years=None, required=True): |
| 29 | + # years is an optional list/tuple of years to use in the "year" select box. |
| 30 | + self.attrs = attrs or {} |
| 31 | + self.required = required |
| 32 | + if years: |
| 33 | + self.years = years |
| 34 | + else: |
| 35 | + this_year = datetime.date.today().year |
| 36 | + self.years = range(this_year, this_year + 10) |
| 37 | + |
| 38 | + def render(self, name, value, attrs=None): |
| 39 | + try: |
| 40 | + year_val, month_val = value.year, value.month |
| 41 | + except AttributeError: |
| 42 | + year_val = month_val = None |
| 43 | + if isinstance(value, basestring): |
| 44 | + match = RE_DATE.match(value) |
| 45 | + if match: |
| 46 | + year_val, month_val, day_val = [int(v) for v in match.groups()] |
| 47 | + |
| 48 | + output = [] |
| 49 | + |
| 50 | + if 'id' in self.attrs: |
| 51 | + id_ = self.attrs['id'] |
| 52 | + else: |
| 53 | + id_ = 'id_%s' % name |
| 54 | + |
| 55 | + month_choices = MONTHS.items() |
| 56 | + if not (self.required and value): |
| 57 | + month_choices.append(self.none_value) |
| 58 | + month_choices.sort() |
| 59 | + local_attrs = self.build_attrs(id=self.month_field % id_) |
| 60 | + s = Select(choices=month_choices) |
| 61 | + select_html = s.render(self.month_field % name, month_val, local_attrs) |
| 62 | + output.append(select_html) |
| 63 | + |
| 64 | + year_choices = [(i, i) for i in self.years] |
| 65 | + if not (self.required and value): |
| 66 | + year_choices.insert(0, self.none_value) |
| 67 | + local_attrs['id'] = self.year_field % id_ |
| 68 | + s = Select(choices=year_choices) |
| 69 | + select_html = s.render(self.year_field % name, year_val, local_attrs) |
| 70 | + output.append(select_html) |
| 71 | + |
| 72 | + return mark_safe(u'\n'.join(output)) |
| 73 | + |
| 74 | + def id_for_label(self, id_): |
| 75 | + return '%s_month' % id_ |
| 76 | + id_for_label = classmethod(id_for_label) |
| 77 | + |
| 78 | + def value_from_datadict(self, data, files, name): |
| 79 | + y = data.get(self.year_field % name) |
| 80 | + m = data.get(self.month_field % name) |
| 81 | + if y == m == "0": |
| 82 | + return None |
| 83 | + if y and m: |
| 84 | + return '%s-%s-%s' % (y, m, 1) |
| 85 | + return data.get(name, None) |
Property changes on: trunk/tools/editor_trends/wikilytics/api/widgets.py |
___________________________________________________________________ |
Added: svn:eol-style |
86 | 86 | + native |