Skip to content

Commit 463b1c1

Browse files
committed
Initial commit
0 parents  commit 463b1c1

File tree

7 files changed

+183
-0
lines changed

7 files changed

+183
-0
lines changed

Diff for: .gitattributes

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Set default behaviour, in case users don't have core.autocrlf set.
2+
* text=auto
3+
4+
# Explicitly declare text files we want to always be normalized and converted
5+
# to native line endings on checkout.
6+
.gitignore text
7+
.gitattributes text
8+
*.py text
9+
*.md text

Diff for: .gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.pyc

Diff for: COPYING

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Copyright (c) 2014 Marc Hoersken <[email protected]>
2+
3+
Permission is hereby granted, free of charge, to any person obtaining a copy of
4+
this software and associated documentation files (the "Software"), to deal in
5+
the Software without restriction, including without limitation the rights to
6+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7+
the Software, and to permit persons to whom the Software is furnished to do so,
8+
subject to the following conditions:
9+
10+
The above copyright notice and this permission notice shall be included in all
11+
copies or substantial portions of the Software.
12+
13+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19+
SOFTWARE.

Diff for: README.md

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
[Django-Celery-Model](https://github.com/mback2k/django-celery-model) is an
2+
extension to [Django-Celery](https://github.com/celery/django-celery)
3+
which adds supports for tracking tasks aligned to Django model instances.
4+
5+
Installation
6+
------------
7+
You can install the latest version from GitHub manually:
8+
9+
git clone https://github.com/mback2k/django-celery-model.git
10+
cd django-celery-model
11+
python setup.py install
12+
13+
or via pip:
14+
15+
pip install https://github.com/mback2k/django-celery-model/zipball/master
16+
17+
Configuration
18+
-------------
19+
Add the package to your `INSTALLED_APPS`:
20+
21+
INSTALLED_APPS += (
22+
'djcelery',
23+
'djcelery_model',
24+
)
25+
26+
License
27+
-------
28+
* Released under MIT License
29+
* Copyright (c) 2014 Marc Hoersken <[email protected]>

Diff for: djcelery_model/__init__.py

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
"""
2+
django-celery-model is an extension to Celery and django-celery that supports tasks aligned to Django models.
3+
"""
4+
5+
__version_info__ = {
6+
'major': 0,
7+
'minor': 0,
8+
'micro': 1,
9+
'releaselevel': 'dev',
10+
}
11+
12+
def get_version():
13+
"""
14+
Return the formatted version information
15+
"""
16+
vers = ["%(major)i.%(minor)i" % __version_info__, ]
17+
18+
if __version_info__['micro']:
19+
vers.append(".%(micro)i" % __version_info__)
20+
if __version_info__['releaselevel'] != 'final':
21+
vers.append('%(releaselevel)s' % __version_info__)
22+
return ''.join(vers)
23+
24+
__version__ = get_version()

Diff for: djcelery_model/models.py

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# -*- coding: utf-8 -*-
2+
from django.db import models
3+
from django.contrib.contenttypes import generic
4+
from django.contrib.contenttypes.models import ContentType
5+
from celery.result import BaseAsyncResult
6+
from celery.utils import uuid
7+
8+
class ModelTaskMeta(models.Model):
9+
content_type = models.ForeignKey(ContentType)
10+
object_id = models.PositiveIntegerField()
11+
content_object = generic.GenericForeignKey()
12+
task_id = models.CharField(max_length=255, unique=True)
13+
14+
def __unicode__(self):
15+
return self.task_id
16+
17+
class ModelAsyncResult(BaseAsyncResult):
18+
def forget(self):
19+
ModelTaskMeta.objects.filter(task_id=self.id).delete()
20+
return super(ModelAsyncResult, self).forget()
21+
22+
class TaskMixin(object):
23+
class Meta:
24+
abstract = True
25+
26+
@property
27+
def tasks(self):
28+
content_type = ContentType.objects.get_for_model(self)
29+
queryset = ModelTaskMeta.objects.filter(content_type=content_type)
30+
return queryset.filter(object_id=self.pk)
31+
32+
def apply_async(self, task, *args, **kwargs):
33+
if 'task_id' in kwargs:
34+
task_id = kwargs['task_id']
35+
else:
36+
task_id = kwargs['task_id'] = uuid()
37+
try:
38+
taskmeta = ModelTaskMeta.objects.get(task_id=task_id)
39+
taskmeta.content_object = self
40+
forget_if_ready(BaseAsyncResult(task_id))
41+
except ModelTaskMeta.DoesNotExist:
42+
taskmeta = ModelTaskMeta(task_id=task_id, content_object=self)
43+
taskmeta.save()
44+
return task.apply_async(*args, **kwargs)
45+
46+
def get_task_results(self):
47+
return map(lambda task_id: ModelAsyncResult(task_id),
48+
self.tasks.values_list('task_id', flat=True))
49+
50+
def get_task_result(self, task_id):
51+
if self.tasks.filter(task_id=task_id).exists():
52+
return ModelAsyncResult(task_id)
53+
return BaseAsyncResult(task_id)
54+
55+
def clear_task_results(self):
56+
map(forget_if_ready, self.get_task_results())
57+
58+
def clear_task_result(self, task_id):
59+
forget_if_ready(self.get_task_result(task_id))
60+
61+
@property
62+
def has_running_task(self):
63+
return len(filter(lambda x: not x.ready(), self.get_task_results())) > 0
64+
65+
def forget_if_ready(async_result):
66+
if async_result and async_result.ready():
67+
async_result.forget()

Diff for: setup.py

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
from setuptools import setup, find_packages
2+
import os
3+
4+
def read_file(filename):
5+
"""Read a file into a string"""
6+
path = os.path.abspath(os.path.dirname(__file__))
7+
filepath = os.path.join(path, filename)
8+
try:
9+
return open(filepath).read()
10+
except IOError:
11+
return ''
12+
13+
setup(
14+
name='django-celery-model',
15+
version=__import__('djcelery_model').__version__,
16+
author='Marc Hoersken',
17+
author_email='[email protected]',
18+
packages=find_packages(),
19+
include_package_data=True,
20+
url='https://github.com/mback2k/django-celery-model',
21+
license='MIT',
22+
description=u' '.join(__import__('djcelery_model').__doc__.splitlines()).strip(),
23+
install_requires=['Celery>=3.1.10'],
24+
classifiers=[
25+
'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
26+
'Intended Audience :: Developers',
27+
'License :: OSI Approved :: MIT License',
28+
'Programming Language :: Python',
29+
'Topic :: Software Development :: Libraries :: Python Modules',
30+
'Development Status :: 4 - Beta',
31+
'Operating System :: OS Independent',
32+
],
33+
long_description=read_file('README.md'),
34+
)

0 commit comments

Comments
 (0)