├── .gitignore ├── AUTHORS ├── LICENSE ├── MANIFEST ├── MANIFEST.in ├── README.md ├── sequence_field ├── __init__.py ├── admin.py ├── constants.py ├── exceptions.py ├── expanders.py ├── fields.py ├── models.py ├── settings.py ├── strings.py └── utils.py ├── setup.py └── test_project ├── app ├── __init__.py ├── admin.py ├── models.py ├── strings.py ├── tests.py └── views.py ├── manage.py └── test_project ├── __init__.py ├── settings.py ├── urls.py └── wsgi.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Generic files 2 | *~ 3 | *.lock 4 | *.out 5 | 6 | # OS specific files 7 | .DS_Store 8 | # Vim 9 | .*.swp 10 | .*.swo 11 | 12 | # Emacs 13 | .emacs-project 14 | \#.# 15 | */.#* 16 | \#* 17 | .#* 18 | *~ 19 | *.idea 20 | 21 | # Komodo 22 | *.komodoproject 23 | 24 | # Python-specific 25 | *.log 26 | *.py[co] 27 | 28 | # Virtualenv-specific 29 | env/ 30 | 31 | # Django-specific 32 | local_settings.py 33 | doccupations/media/!.ignoreme 34 | doccupations/static 35 | #static/admin_tools 36 | *.pot 37 | 38 | # Python packages-specific 39 | *.egg 40 | *.egg-info 41 | dist 42 | build 43 | eggs 44 | parts 45 | var 46 | sdist 47 | develop-eggs 48 | .installed.cfg 49 | 50 | # pip-specific 51 | pip-log.txt 52 | 53 | # Unit test / coverage reports 54 | .coverage 55 | .tox 56 | 57 | # SQLite-specific 58 | data/!.turd 59 | *.sqlite 60 | *.sqlite3 61 | 62 | #Redis 63 | *.rdb 64 | 65 | #Coverage byproducts 66 | .coverage 67 | htmlcov 68 | cover 69 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Antonio Ognio 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012, Antonio Ognio. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1) Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | 2) Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | 3) Neither the name of django-sequence-field nor the names of its contributors 13 | may be used to endorse or promote products derived from this software 14 | without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /MANIFEST: -------------------------------------------------------------------------------- 1 | # file GENERATED by distutils, do NOT edit 2 | LICENSE 3 | AUTHORS 4 | README.md 5 | setup.py 6 | sequence_field/__init__.py 7 | sequence_field/admin.py 8 | sequence_field/constants.py 9 | sequence_field/exceptions.py 10 | sequence_field/expanders.py 11 | sequence_field/fields.py 12 | sequence_field/models.py 13 | sequence_field/settings.py 14 | sequence_field/strings.py 15 | sequence_field/utils.py 16 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE 2 | include AUTHORS 3 | include README.md 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Django Sequence Field 2 | ===================== 3 | 4 | A Django field for creating templated sequenced strings. 5 | 6 | Usage: 7 | 8 | Importing and using the SequenceField class: 9 | 10 | ```python 11 | from sequence_field.fields import SequenceField 12 | 13 | # Create your models here. 14 | 15 | class TestModel(models.Model): 16 | 17 | sequence = SequenceField( 18 | key='test.sequence.1', 19 | template='%Y%m%d%(code)s%NNNNN', 20 | params={'code':'ABC'}, 21 | auto=True 22 | ) 23 | 24 | ``` 25 | 26 | When creating new objects, the sequence is generated automatically 27 | based on the template: 28 | 29 | 30 | ```python 31 | from my_app.models import TestModel 32 | 33 | obj = TestModel() 34 | obj.save() 35 | 36 | print obj.sequence # 20140703ABC00001 37 | 38 | obj = TestModel() 39 | obj.save() 40 | 41 | print obj.sequence # 20140703ABC00002 42 | ``` 43 | 44 | An accompaning ```Sequence``` model is used by this app to store the 45 | current value for each key. When a new key is declared in a field a 46 | new ```Sequence``` instance is created and saved on the fly. 47 | 48 | If you need to customize the creation of each sequence value passing 49 | different parameters you'll have to do it at the model level with 50 | code like this: 51 | 52 | ```python 53 | from sequence_field.models import Sequence 54 | print Sequence.next( 55 | 'test.sequence.1', template='%Y%m%d%(code)s%NNNNN', params={'code':'XYZ'} 56 | ) # 20140703XYZ00003 57 | ``` 58 | 59 | Templates can also be stored in the database so you don't have to pass them 60 | all the time. If a template is provided the first time a key is used it gets 61 | automatically stored. 62 | 63 | ```python 64 | >>> from sequence_field.models import Sequence 65 | >>> Sequence.next('test.sequence.20', template='%m%d%Y-%NNNNNNNNNNN') 66 | '07042014-00000000001' 67 | >>> Sequence.next('test.sequence.20') 68 | '07042014-00000000002' 69 | ``` 70 | 71 | You can use the provided Expander classes or build your own. 72 | As an example see the code for the ```TimeExpander``` class the uses 73 | Python's ```strftime``` function to perform time-related expansions: 74 | 75 | ```python 76 | class TimeExpander(BaseExpander): 77 | 78 | def expand(self, template=None, count=None, params={}, value=None): 79 | import time 80 | (template, count, params, value) = self.setvars( 81 | template, count, params, value 82 | ) 83 | return time.strftime(value) 84 | ``` 85 | 86 | The default expanders are: (taken from the ```constants.py``` file) 87 | 88 | ```python 89 | SEQUENCE_FIELD_DEFAULT_EXPANDERS = ( 90 | 'sequence_field.expanders.NumericExpander', 91 | 'sequence_field.expanders.TimeExpander', 92 | 'sequence_field.expanders.ParameterExpander', 93 | ) 94 | ``` 95 | 96 | At your Django project's ```settings.py``` file you can customize this 97 | variables: (default values are shown) 98 | 99 | ```python 100 | SEQUENCE_FIELD_DEFAULT_VALUE # 1 101 | 102 | SEQUENCE_FIELD_ADMIN # True 103 | 104 | SEQUENCE_FIELD_DEFAULT_TEMPLATE # '%N' 105 | 106 | SEQUENCE_FIELD_DEFAULT_PATTERN # r'(\d+)' 107 | 108 | SEQUENCE_FIELD_DEFAULT_EXPANDERS # Already mentioned in the previous section. 109 | ``` 110 | 111 | Installation from Github 112 | ======================== 113 | 114 | ```pip install https://github.com/gnrfan/django-sequence-field/zipball/master``` 115 | 116 | Add this line to your ```requirements.txt``` file: 117 | 118 | ```-e git+https://github.com/gnrfan/django-sequence-field.git@HEAD#egg=django-sequence-field``` 119 | 120 | Then just run: 121 | 122 | ```pip install -r requirements.txt```. 123 | 124 | (c) 2014 Antonio Ognio 125 | -------------------------------------------------------------------------------- /sequence_field/__init__.py: -------------------------------------------------------------------------------- 1 | from sequence_field.fields import SequenceField 2 | 3 | __version__ = '0.1' 4 | -------------------------------------------------------------------------------- /sequence_field/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from sequence_field.models import Sequence 3 | from sequence_field import settings as sequence_field_settings 4 | 5 | # Sequence Field 6 | 7 | class SequenceAdmin(admin.ModelAdmin): 8 | 9 | list_display = ( 10 | 'id', 'key', 'value', 'created', 'updated' 11 | ) 12 | 13 | readonly_fields = ('created', 'updated', ) 14 | 15 | ordering = ('key', ) 16 | 17 | 18 | if sequence_field_settings.SEQUENCE_FIELD_ADMIN: 19 | admin.site.register(Sequence, SequenceAdmin) 20 | 21 | -------------------------------------------------------------------------------- /sequence_field/constants.py: -------------------------------------------------------------------------------- 1 | # Sequence Field constants 2 | 3 | SEQUENCE_KEY_LENGTH = 128 4 | 5 | SEQUENCE_TEMPLATE_LENGTH = 128 6 | 7 | SEQUENCE_DEFAULT_VALUE = 1 8 | 9 | SEQUENCE_FIELD_ADMIN = True 10 | 11 | SEQUENCE_FIELD_DEFAULT_PATTERN = r'(\d+)' 12 | 13 | SEQUENCE_FIELD_DEFAULT_TEMPLATE = '%N' 14 | 15 | SEQUENCE_FIELD_DEFAULT_EXPANDERS = ( 16 | 'sequence_field.expanders.NumericExpander', 17 | 'sequence_field.expanders.TimeExpander', 18 | 'sequence_field.expanders.ParameterExpander', 19 | ) 20 | -------------------------------------------------------------------------------- /sequence_field/exceptions.py: -------------------------------------------------------------------------------- 1 | # Exceptions 2 | 3 | class SequenceFieldException(Exception): 4 | pass 5 | -------------------------------------------------------------------------------- /sequence_field/expanders.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Sequence Field Expanders 4 | 5 | import re 6 | 7 | class BaseExpander(object): 8 | 9 | def __init__(self, template=None, count=None, params={}, value=None): 10 | self.template = template 11 | self.count = count 12 | self.params = params 13 | self.value = value 14 | 15 | def setvars(self, template=None, count=None, params={}, value=None): 16 | # Parameters take precedence over attributes 17 | template = template if template is not None else self.template 18 | count = count if count is not None else self.count 19 | params = params if len(params)>0 else self.params 20 | value = value if value is not None else self.value 21 | # Copy current value from template 22 | if value is None or len(value) == 0: 23 | value = template 24 | return (template, count, params, value, ) 25 | 26 | def expand(self, template=None, count=None, params={}, value=None): 27 | # Do nothing, just return the value 28 | (template, count, params, value) = self.setvars( 29 | template, count, params, value 30 | ) 31 | return value 32 | 33 | 34 | class NumericExpander(BaseExpander): 35 | 36 | regexp = r'^(.*)(?P%N+)(.*)$' 37 | 38 | def __init__(self, template=None, count=None, params={}, value=None): 39 | super(NumericExpander, self).__init__(template, count, params, value) 40 | self.format = '%d' 41 | 42 | def set_format_from_numeric_placeholder(self, numeric_placeholder): 43 | format = '%%0%dd' % len(numeric_placeholder.replace('%', '')) 44 | self.format = format 45 | 46 | def expand_count(self, count=None): 47 | if count is None: 48 | count = self.count 49 | return self.format % count 50 | 51 | def get_numeric_placeholder_from_groupdict(self, groupdict): 52 | if 'numeric_placeholder' in groupdict: 53 | return groupdict['numeric_placeholder'] 54 | else: 55 | return '' 56 | 57 | def get_numeric_placeholder(self, template=None): 58 | if template is None: 59 | template = self.template 60 | match = re.match(self.regexp, template) 61 | if match is not None: 62 | return self.get_numeric_placeholder_from_groupdict( 63 | match.groupdict() 64 | ) 65 | else: 66 | return None 67 | 68 | def expand_with_expanded_count(self, expanded_count, value=None): 69 | if value is None: 70 | value = self.value 71 | parts = [ 72 | re.sub(self.regexp, r'\1', value), 73 | expanded_count, 74 | re.sub(self.regexp, r'\3', value) 75 | ] 76 | return ''.join(parts) 77 | 78 | def expand(self, template=None, count=None, params={}, value=None): 79 | (template, count, params, value) = self.setvars( 80 | template, count, params, value 81 | ) 82 | numeric_placeholder = self.get_numeric_placeholder() 83 | self.set_format_from_numeric_placeholder(numeric_placeholder) 84 | expanded_count = self.expand_count() 85 | value = self.expand_with_expanded_count(expanded_count, value) 86 | return value 87 | 88 | 89 | class ParameterExpander(BaseExpander): 90 | 91 | def expand(self, template=None, count=None, params={}, value=None): 92 | (template, count, params, value) = self.setvars( 93 | template, count, params, value 94 | ) 95 | return value % params 96 | 97 | 98 | class TimeExpander(BaseExpander): 99 | 100 | def expand(self, template=None, count=None, params={}, value=None): 101 | import time 102 | (template, count, params, value) = self.setvars( 103 | template, count, params, value 104 | ) 105 | return time.strftime(value) 106 | -------------------------------------------------------------------------------- /sequence_field/fields.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from django.db import models 4 | from sequence_field.models import Sequence 5 | from sequence_field.exceptions import SequenceFieldException 6 | from sequence_field import settings as sequence_field_settings 7 | from sequence_field import strings 8 | 9 | class SequenceField(models.TextField): 10 | """ Stores sequence values based on templates. """ 11 | 12 | description = strings.SEQUENCE_FIELD_DESCRIPTION 13 | 14 | def __init__(self, *args, **kwargs): 15 | self.default_error_messages = { 16 | 'invalid': strings.SEQUENCE_FIELD_PATTERN_MISMATCH 17 | } 18 | self._db_type = kwargs.pop('db_type', None) 19 | self.evaluate_formfield = kwargs.pop('evaluate_formfield', False) 20 | 21 | self.lazy = kwargs.pop('lazy', True) 22 | 23 | try: 24 | self.key = kwargs.pop('key') 25 | except KeyError: 26 | raise SequenceFieldException( 27 | strings.SEQUENCE_FIELD_MISSING_KEY 28 | ) 29 | 30 | default_pattern = \ 31 | sequence_field_settings.SEQUENCE_FIELD_DEFAULT_PATTERN 32 | self.pattern = kwargs.pop('pattern', default_pattern) 33 | 34 | default_template = Sequence.get_template_by_key(self.key) 35 | self.template = kwargs.pop('template', default_template) 36 | 37 | Sequence.create_if_missing(self.key, self.template) 38 | 39 | default_expanders = \ 40 | sequence_field_settings.SEQUENCE_FIELD_DEFAULT_EXPANDERS 41 | 42 | self.params = kwargs.pop('params', {}) 43 | 44 | self.expanders = kwargs.pop('expanders', default_expanders) 45 | 46 | self.auto = kwargs.pop('auto', False) 47 | 48 | kwargs['help_text'] = kwargs.get( 49 | 'help_text', self.default_error_messages['invalid'] 50 | ) 51 | 52 | super(SequenceField, self).__init__(*args, **kwargs) 53 | 54 | def _next_value(self): 55 | seq = Sequence.create_if_missing(self.key, self.template) 56 | return seq.next_value(self.template, self.params, self.expanders) 57 | 58 | 59 | def pre_save(self, model_instance, add): 60 | """ 61 | This is used to ensure that we auto-set values if required. 62 | See CharField.pre_save 63 | """ 64 | value = getattr(model_instance, self.attname, None) 65 | if self.auto and add and not value: 66 | # Assign a new value for this attribute if required. 67 | sequence_string = self._next_value() 68 | setattr(model_instance, self.attname, sequence_string) 69 | value = sequence_string 70 | return value 71 | 72 | 73 | try: 74 | # add support for South migrations 75 | from south.modelsinspector import add_introspection_rules 76 | rules = [ 77 | ( 78 | (SequenceField,), 79 | [], 80 | { 81 | 'db_type': ['_db_type', {'default': None}] 82 | } 83 | ) 84 | ] 85 | add_introspection_rules(rules, ['^sequence_field\.fields\.SequenceField']) 86 | except ImportError: 87 | pass 88 | -------------------------------------------------------------------------------- /sequence_field/models.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from django.db import models 4 | from django.db.utils import OperationalError 5 | from sequence_field import utils 6 | from sequence_field import strings 7 | from sequence_field import constants 8 | from sequence_field import settings as sequence_field_settings 9 | 10 | # Sequence Field 11 | 12 | class Sequence(models.Model): 13 | 14 | key = models.CharField( 15 | verbose_name=strings.SEQUENCE_KEY, 16 | max_length=constants.SEQUENCE_KEY_LENGTH, 17 | unique=True 18 | ) 19 | 20 | value = models.PositiveIntegerField( 21 | verbose_name=strings.SEQUENCE_VALUE, 22 | default=sequence_field_settings.SEQUENCE_FIELD_DEFAULT_VALUE 23 | ) 24 | 25 | template = models.CharField( 26 | verbose_name=strings.SEQUENCE_TEMPLATE, 27 | max_length=constants.SEQUENCE_TEMPLATE_LENGTH, 28 | default=sequence_field_settings.SEQUENCE_FIELD_DEFAULT_TEMPLATE 29 | ) 30 | 31 | created = models.DateTimeField( 32 | verbose_name=strings.SEQUENCE_CREATED, 33 | auto_now_add=True 34 | ) 35 | 36 | updated = models.DateTimeField( 37 | verbose_name=strings.SEQUENCE_UPDATED, 38 | auto_now=True 39 | ) 40 | 41 | class Meta: 42 | verbose_name = strings.SEQUENCE_MODEL_NAME 43 | verbose_name_plural = strings.SEQUENCE_MODEL_NAME_PLURAL 44 | 45 | def __unicode__(self): 46 | return self.key 47 | 48 | def increment(self, commit=True): 49 | self.value += 1 50 | if commit: 51 | self.save() 52 | 53 | def next_value(self, template=None, params=None, 54 | expanders=None, commit=True): 55 | 56 | default_template = self.template 57 | 58 | default_expanders = \ 59 | sequence_field_settings.SEQUENCE_FIELD_DEFAULT_EXPANDERS 60 | 61 | count = self.value 62 | template = template if template is not None else default_template 63 | params = params if params is not None else {} 64 | expanders = expanders if expanders is not None else default_expanders 65 | if commit: 66 | self.increment() 67 | return utils.expand(template, count, params, expanders=expanders) 68 | 69 | 70 | @classmethod 71 | def create_if_missing(cls, key, template=None): 72 | default_template = \ 73 | sequence_field_settings.SEQUENCE_FIELD_DEFAULT_TEMPLATE 74 | try: 75 | (seq, created) = Sequence.objects.get_or_create(key=key) 76 | # If a template is provided the first time it gets stored 77 | if created and template is not None: 78 | seq.template = template 79 | seq.save() 80 | return seq 81 | except OperationalError: 82 | return None 83 | 84 | 85 | @classmethod 86 | def next(cls, key, template=None, params=None, 87 | expanders=None, commit=True): 88 | seq = Sequence.create_if_missing(key, template) 89 | return seq.next_value(template, params, expanders, commit) 90 | 91 | @classmethod 92 | def get_template_by_key(cls, key): 93 | default_template = \ 94 | sequence_field_settings.SEQUENCE_FIELD_DEFAULT_TEMPLATE 95 | try: 96 | seq = Sequence.objects.get(key=key) 97 | return seq.template 98 | except (OperationalError, Sequence.DoesNotExist): 99 | return default_template 100 | -------------------------------------------------------------------------------- /sequence_field/settings.py: -------------------------------------------------------------------------------- 1 | # Sequence Field Settings 2 | 3 | from django.conf import settings 4 | from sequence_field import constants 5 | 6 | 7 | SEQUENCE_FIELD_DEFAULT_VALUE = getattr( 8 | settings, 9 | 'SEQUENCE_FIELD_DEFAULT_VALUE', 10 | constants.SEQUENCE_DEFAULT_VALUE 11 | ) 12 | 13 | SEQUENCE_FIELD_ADMIN = getattr( 14 | settings, 15 | 'SEQUENCE_FIELD_ADMIN', 16 | constants.SEQUENCE_FIELD_ADMIN 17 | ) 18 | 19 | SEQUENCE_FIELD_DEFAULT_TEMPLATE = getattr( 20 | settings, 21 | 'SEQUENCE_FIELD_DEFAULT_TEMPLATE', 22 | constants.SEQUENCE_FIELD_DEFAULT_TEMPLATE 23 | ) 24 | 25 | SEQUENCE_FIELD_DEFAULT_PATTERN = getattr( 26 | settings, 27 | 'SEQUENCE_FIELD_DEFAULT_PATTERN', 28 | constants.SEQUENCE_FIELD_DEFAULT_PATTERN 29 | ) 30 | 31 | SEQUENCE_FIELD_DEFAULT_EXPANDERS = getattr( 32 | settings, 33 | 'SEQUENCE_FIELD_DEFAULT_EXPANDERS', 34 | constants.SEQUENCE_FIELD_DEFAULT_EXPANDERS 35 | ) 36 | -------------------------------------------------------------------------------- /sequence_field/strings.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from django.utils.translation import ugettext as _ 4 | 5 | # Sequence Field 6 | 7 | SEQUENCE_KEY = _(u'Key') 8 | SEQUENCE_VALUE = _(u'Value') 9 | SEQUENCE_TEMPLATE = _(u'Template') 10 | SEQUENCE_CREATED = _(u'Created at') 11 | SEQUENCE_UPDATED = _(u'Updated at') 12 | 13 | SEQUENCE_MODEL_NAME = _(u'Sequence') 14 | SEQUENCE_MODEL_NAME_PLURAL = _(u'Sequences') 15 | 16 | SEQUENCE_FIELD_DESCRIPTION = _(u'Templated sequence object') 17 | 18 | # Errors 19 | 20 | SEQUENCE_FIELD_PATTERN_MISMATCH = _( 21 | u'The value does not match the specified pattern' 22 | ) 23 | 24 | SEQUENCE_FIELD_MISSING_KEY = _( 25 | u'The key parameter is mandatory and is missing' 26 | ) 27 | 28 | SEQUENCE_FIELD_KEY_MISMATCH = _( 29 | u'The key \'%(key)s\' does not match any of the existing ' 30 | u'sequence model objects' 31 | ) 32 | -------------------------------------------------------------------------------- /sequence_field/utils.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | def load_class(name): 4 | components = name.split('.') 5 | module_path = '.'.join(components[:-1]) 6 | class_name = components[-1] 7 | mod = __import__(module_path, fromlist=[class_name]) 8 | klass = getattr(mod, class_name) 9 | return klass 10 | 11 | 12 | def expand(template, count, params={}, value=None, expanders=[]): 13 | for expander_class in expanders: 14 | klass = load_class(expander_class) 15 | expander = klass(template, count, params, value) 16 | value = expander.expand() 17 | return value 18 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | description = 'Generic JSON model and form fields.' 4 | 5 | try: 6 | with open('README.md') as f: 7 | long_description = f.read() 8 | except IOError: 9 | long_description = description 10 | 11 | setup( 12 | name = 'django-sequence-field', 13 | version = '0.1', 14 | description = description, 15 | author = 'Antonio Ognio', 16 | author_email = 'antonio@ognio.com', 17 | url = 'https://github.com/gnrfan/django-sequence-field', 18 | long_description = long_description, 19 | packages = ['sequence_field'], 20 | install_requires = ['django >= 1.6'], 21 | classifiers = [ 22 | 'Development Status :: 3 - Alpha', 23 | 'Intended Audience :: Developers', 24 | 'License :: OSI Approved :: BSD License', 25 | 'Operating System :: OS Independent', 26 | 'Programming Language :: Python', 27 | 'Topic :: Software Development :: Libraries :: Python Modules', 28 | ], 29 | ) 30 | -------------------------------------------------------------------------------- /test_project/app/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnrfan/django-sequence-field/466f609a08ef39203336ca912dae57d2e12a4a30/test_project/app/__init__.py -------------------------------------------------------------------------------- /test_project/app/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /test_project/app/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from sequence_field.fields import SequenceField 3 | from app import strings 4 | 5 | # Create your models here. 6 | 7 | class TestModel(models.Model): 8 | 9 | sequence = SequenceField( 10 | verbose_name=strings.TESTMODEL_SEQUENCE, 11 | key='app.test.sequence.1', 12 | template='%Y%m%d%(code)s%NNNNN', 13 | params={'code':'ABC'}, 14 | auto=True 15 | ) 16 | 17 | created = models.DateTimeField( 18 | verbose_name=strings.TESTMODEL_CREATED, 19 | auto_now_add=True 20 | ) 21 | 22 | updated = models.DateTimeField( 23 | verbose_name=strings.TESTMODEL_UPDATED, 24 | auto_now=True 25 | ) 26 | 27 | class Meta: 28 | verbose_name = strings.TESTMODEL_MODEL_NAME 29 | verbose_name_plural = strings.TESTMODEL_MODEL_NAME_PLURAL 30 | 31 | def __unicode__(self): 32 | return self.sequence 33 | -------------------------------------------------------------------------------- /test_project/app/strings.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from django.utils.translation import ugettext as _ 4 | 5 | # Test model 6 | 7 | TESTMODEL_SEQUENCE = _(u'Sequence') 8 | TESTMODEL_CREATED = _(u'Created at') 9 | TESTMODEL_UPDATED = _(u'Updated at') 10 | 11 | TESTMODEL_MODEL_NAME = _(u'Test model') 12 | TESTMODEL_MODEL_NAME_PLURAL = _(u'Test models') 13 | 14 | -------------------------------------------------------------------------------- /test_project/app/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /test_project/app/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | # Create your views here. 4 | -------------------------------------------------------------------------------- /test_project/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | 7 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "test_project.settings") 8 | from django.core.management import execute_from_command_line 9 | execute_from_command_line(sys.argv) 10 | -------------------------------------------------------------------------------- /test_project/test_project/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnrfan/django-sequence-field/466f609a08ef39203336ca912dae57d2e12a4a30/test_project/test_project/__init__.py -------------------------------------------------------------------------------- /test_project/test_project/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for test_project project. 3 | 4 | For more information on this file, see 5 | https://docs.djangoproject.com/en/1.6/topics/settings/ 6 | 7 | For the full list of settings and their values, see 8 | https://docs.djangoproject.com/en/1.6/ref/settings/ 9 | """ 10 | 11 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 12 | import os 13 | BASE_DIR = os.path.dirname(os.path.dirname(__file__)) 14 | 15 | # Quick-start development settings - unsuitable for production 16 | # See https://docs.djangoproject.com/en/1.6/howto/deployment/checklist/ 17 | 18 | # SECURITY WARNING: keep the secret key used in production secret! 19 | SECRET_KEY = 'j_r0as=zm@up)azpkmnednqd^p(m#ypok_dhi3h+=4roe%+$#0' 20 | 21 | # SECURITY WARNING: don't run with debug turned on in production! 22 | DEBUG = True 23 | 24 | TEMPLATE_DEBUG = True 25 | 26 | ALLOWED_HOSTS = [] 27 | 28 | 29 | # Application definition 30 | 31 | INSTALLED_APPS = ( 32 | # Django 33 | 'django.contrib.admin', 34 | 'django.contrib.auth', 35 | 'django.contrib.contenttypes', 36 | 'django.contrib.sessions', 37 | 'django.contrib.messages', 38 | 'django.contrib.staticfiles', 39 | # Project 40 | 'sequence_field', 41 | 'app' 42 | ) 43 | 44 | MIDDLEWARE_CLASSES = ( 45 | 'django.contrib.sessions.middleware.SessionMiddleware', 46 | 'django.middleware.common.CommonMiddleware', 47 | 'django.middleware.csrf.CsrfViewMiddleware', 48 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 49 | 'django.contrib.messages.middleware.MessageMiddleware', 50 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 51 | ) 52 | 53 | ROOT_URLCONF = 'test_project.urls' 54 | 55 | WSGI_APPLICATION = 'test_project.wsgi.application' 56 | 57 | 58 | # Database 59 | # https://docs.djangoproject.com/en/1.6/ref/settings/#databases 60 | 61 | DATABASES = { 62 | 'default': { 63 | 'ENGINE': 'django.db.backends.sqlite3', 64 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 65 | } 66 | } 67 | 68 | # Internationalization 69 | # https://docs.djangoproject.com/en/1.6/topics/i18n/ 70 | 71 | LANGUAGE_CODE = 'en-us' 72 | 73 | TIME_ZONE = 'UTC' 74 | 75 | USE_I18N = True 76 | 77 | USE_L10N = True 78 | 79 | USE_TZ = True 80 | 81 | 82 | # Static files (CSS, JavaScript, Images) 83 | # https://docs.djangoproject.com/en/1.6/howto/static-files/ 84 | 85 | STATIC_URL = '/static/' 86 | -------------------------------------------------------------------------------- /test_project/test_project/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import patterns, include, url 2 | 3 | from django.contrib import admin 4 | admin.autodiscover() 5 | 6 | urlpatterns = patterns('', 7 | # Examples: 8 | # url(r'^$', 'test_project.views.home', name='home'), 9 | # url(r'^blog/', include('blog.urls')), 10 | 11 | url(r'^admin/', include(admin.site.urls)), 12 | ) 13 | -------------------------------------------------------------------------------- /test_project/test_project/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for test_project project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.6/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "test_project.settings") 12 | 13 | from django.core.wsgi import get_wsgi_application 14 | application = get_wsgi_application() 15 | --------------------------------------------------------------------------------