include copy of django_extension, dont install django from git
This commit is contained in:
parent
055018f12e
commit
3f7215035a
200 changed files with 14119 additions and 4 deletions
11
contrib/django_extensions/.gitignore
vendored
Normal file
11
contrib/django_extensions/.gitignore
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
*.pyc
|
||||
*.pyo
|
||||
*.egg-info
|
||||
MANIFEST
|
||||
build
|
||||
dist
|
||||
docs/_build
|
||||
docs/_static
|
||||
*.egg-info
|
||||
.tox
|
||||
*.bak
|
29
contrib/django_extensions/.travis.yml
Normal file
29
contrib/django_extensions/.travis.yml
Normal file
|
@ -0,0 +1,29 @@
|
|||
language: python
|
||||
|
||||
python:
|
||||
- 2.6
|
||||
- 2.7
|
||||
- 3.3
|
||||
|
||||
env:
|
||||
- DJANGO=Django==1.3 --use-mirrors
|
||||
- DJANGO=Django==1.4 --use-mirrors
|
||||
- DJANGO=Django==1.5 --use-mirrors
|
||||
|
||||
install:
|
||||
- pip install -q $DJANGO
|
||||
- pip install flake8 --use-mirrors
|
||||
- if [[ $TRAVIS_PYTHON_VERSION < '3.0' ]]; then pip install -q python-keyczar --use-mirrors; fi
|
||||
- pip install -q PyYAML --use-mirrors
|
||||
- pip install -e . --use-mirrors
|
||||
|
||||
script:
|
||||
- flake8 --ignore=E501,W391 .
|
||||
- python setup.py test
|
||||
|
||||
matrix:
|
||||
exclude:
|
||||
- python: 3.3
|
||||
env: DJANGO=Django==1.3 --use-mirrors
|
||||
- python: 3.3
|
||||
env: DJANGO=Django==1.4 --use-mirrors
|
8
contrib/django_extensions/.tx/config
Normal file
8
contrib/django_extensions/.tx/config
Normal file
|
@ -0,0 +1,8 @@
|
|||
[django-extensions.master]
|
||||
file_filter = django_extensions/locale/<lang>/LC_MESSAGES/django.po
|
||||
source_file = django_extensions/locale/en/LC_MESSAGES/django.po
|
||||
source_lang = en
|
||||
|
||||
[main]
|
||||
host = https://www.transifex.net
|
||||
|
19
contrib/django_extensions/LICENSE
Normal file
19
contrib/django_extensions/LICENSE
Normal file
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2007 Michael Trier
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
5
contrib/django_extensions/MANIFEST.in
Normal file
5
contrib/django_extensions/MANIFEST.in
Normal file
|
@ -0,0 +1,5 @@
|
|||
recursive-include django_extensions/conf *.tmpl
|
||||
recursive-include django_extensions/templates *.html
|
||||
recursive-include django_extensions/static *
|
||||
recursive-include docs *
|
||||
include LICENSE
|
73
contrib/django_extensions/README.rst
Normal file
73
contrib/django_extensions/README.rst
Normal file
|
@ -0,0 +1,73 @@
|
|||
===================
|
||||
Django Extensions
|
||||
===================
|
||||
|
||||
.. image:: https://secure.travis-ci.org/django-extensions/django-extensions.png?branch=master
|
||||
:alt: Build Status
|
||||
:target: http://travis-ci.org/django-extensions/django-extensions
|
||||
|
||||
Django Extensions is a collection of custom extensions for the Django Framework.
|
||||
|
||||
Getting Started
|
||||
===============
|
||||
|
||||
The easiest way to figure out what Django Extensions are all about is to watch the `excellent screencast by Eric Holscher`__. In a couple minutes Eric walks you through a half a dozen command extensions.
|
||||
|
||||
Getting It
|
||||
==========
|
||||
|
||||
You can get Django Extensions by using pip or easy_install::
|
||||
|
||||
$ pip install django-extensions
|
||||
or
|
||||
$ easy_install django-extensions
|
||||
|
||||
If you want to install it from source, grab the git repository from GitHub and run setup.py::
|
||||
|
||||
$ git clone git://github.com/django-extensions/django-extensions.git
|
||||
$ cd django-extensions
|
||||
$ python setup.py install
|
||||
|
||||
Installing It
|
||||
=============
|
||||
|
||||
To enable `django_extensions` in your project you need to add it to `INSTALLED_APPS` in your projects `settings.py` file::
|
||||
|
||||
INSTALLED_APPS = (
|
||||
...
|
||||
'django_extensions',
|
||||
...
|
||||
)
|
||||
|
||||
|
||||
Using It
|
||||
========
|
||||
|
||||
Generate (and view) a graphviz graph of app models::
|
||||
|
||||
$ python manage.py graph_models -a -o myapp_models.png
|
||||
|
||||
Produce a tab-separated list of `(url_pattern, view_function, name)` tuples for a project::
|
||||
|
||||
$ python manage.py show_urls
|
||||
|
||||
Getting Involved
|
||||
================
|
||||
|
||||
Open Source projects can always use more help. Fixing a problem, documenting a feature, adding translation in your language. If you have some time to spare and like to help us, here are the places to do so:
|
||||
|
||||
- GitHub: https://github.com/django-extensions/django-extensions
|
||||
- Mailing list: http://groups.google.com/group/django-extensions
|
||||
- Translations: https://www.transifex.net/projects/p/django-extensions/
|
||||
|
||||
Documentation
|
||||
=============
|
||||
|
||||
You can view documentation online at:
|
||||
|
||||
- http://packages.python.org/django-extensions/
|
||||
|
||||
Or you can look at the docs/ directory in the repository.
|
||||
|
||||
__ http://ericholscher.com/blog/2008/sep/12/screencast-django-command-extensions/
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
Metadata-Version: 1.1
|
||||
Name: django-extensions
|
||||
Version: 1.2.3
|
||||
Summary: Extensions for Django
|
||||
Home-page: http://github.com/django-extensions/django-extensions
|
||||
Author: Bas van Oostveen
|
||||
Author-email: v.oostveen@gmail.com
|
||||
License: New BSD License
|
||||
Description: django-extensions bundles several useful
|
||||
additions for Django projects. See the project page for more information:
|
||||
http://github.com/django-extensions/django-extensions
|
||||
Platform: any
|
||||
Classifier: Development Status :: 4 - Beta
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Environment :: Web Environment
|
||||
Classifier: Framework :: Django
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: License :: OSI Approved :: BSD License
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Topic :: Utilities
|
152
contrib/django_extensions/django_extensions.egg-info/SOURCES.txt
Normal file
152
contrib/django_extensions/django_extensions.egg-info/SOURCES.txt
Normal file
|
@ -0,0 +1,152 @@
|
|||
LICENSE
|
||||
MANIFEST.in
|
||||
README.rst
|
||||
django_extensions/__init__.py
|
||||
django_extensions/future_1_5.py
|
||||
django_extensions/models.py
|
||||
django_extensions/settings.py
|
||||
django_extensions.egg-info/PKG-INFO
|
||||
django_extensions.egg-info/SOURCES.txt
|
||||
django_extensions.egg-info/dependency_links.txt
|
||||
django_extensions.egg-info/requires.txt
|
||||
django_extensions.egg-info/top_level.txt
|
||||
django_extensions/admin/__init__.py
|
||||
django_extensions/admin/widgets.py
|
||||
django_extensions/conf/app_template/__init__.py.tmpl
|
||||
django_extensions/conf/app_template/forms.py.tmpl
|
||||
django_extensions/conf/app_template/models.py.tmpl
|
||||
django_extensions/conf/app_template/urls.py.tmpl
|
||||
django_extensions/conf/app_template/views.py.tmpl
|
||||
django_extensions/conf/command_template/management/__init__.py.tmpl
|
||||
django_extensions/conf/command_template/management/commands/__init__.py.tmpl
|
||||
django_extensions/conf/command_template/management/commands/sample.py.tmpl
|
||||
django_extensions/conf/jobs_template/jobs/__init__.py.tmpl
|
||||
django_extensions/conf/jobs_template/jobs/sample.py.tmpl
|
||||
django_extensions/conf/jobs_template/jobs/daily/__init__.py.tmpl
|
||||
django_extensions/conf/jobs_template/jobs/hourly/__init__.py.tmpl
|
||||
django_extensions/conf/jobs_template/jobs/monthly/__init__.py.tmpl
|
||||
django_extensions/conf/jobs_template/jobs/weekly/__init__.py.tmpl
|
||||
django_extensions/conf/jobs_template/jobs/yearly/__init__.py.tmpl
|
||||
django_extensions/db/__init__.py
|
||||
django_extensions/db/models.py
|
||||
django_extensions/db/fields/__init__.py
|
||||
django_extensions/db/fields/encrypted.py
|
||||
django_extensions/db/fields/json.py
|
||||
django_extensions/jobs/__init__.py
|
||||
django_extensions/jobs/daily/__init__.py
|
||||
django_extensions/jobs/daily/cache_cleanup.py
|
||||
django_extensions/jobs/daily/daily_cleanup.py
|
||||
django_extensions/jobs/hourly/__init__.py
|
||||
django_extensions/jobs/minutely/__init__.py
|
||||
django_extensions/jobs/monthly/__init__.py
|
||||
django_extensions/jobs/weekly/__init__.py
|
||||
django_extensions/jobs/yearly/__init__.py
|
||||
django_extensions/management/__init__.py
|
||||
django_extensions/management/base.py
|
||||
django_extensions/management/color.py
|
||||
django_extensions/management/jobs.py
|
||||
django_extensions/management/modelviz.py
|
||||
django_extensions/management/notebook_extension.py
|
||||
django_extensions/management/shells.py
|
||||
django_extensions/management/signals.py
|
||||
django_extensions/management/technical_response.py
|
||||
django_extensions/management/utils.py
|
||||
django_extensions/management/commands/__init__.py
|
||||
django_extensions/management/commands/clean_pyc.py
|
||||
django_extensions/management/commands/compile_pyc.py
|
||||
django_extensions/management/commands/create_app.py
|
||||
django_extensions/management/commands/create_command.py
|
||||
django_extensions/management/commands/create_jobs.py
|
||||
django_extensions/management/commands/describe_form.py
|
||||
django_extensions/management/commands/dumpscript.py
|
||||
django_extensions/management/commands/export_emails.py
|
||||
django_extensions/management/commands/find_template.py
|
||||
django_extensions/management/commands/generate_secret_key.py
|
||||
django_extensions/management/commands/graph_models.py
|
||||
django_extensions/management/commands/mail_debug.py
|
||||
django_extensions/management/commands/notes.py
|
||||
django_extensions/management/commands/passwd.py
|
||||
django_extensions/management/commands/pipchecker.py
|
||||
django_extensions/management/commands/print_settings.py
|
||||
django_extensions/management/commands/print_user_for_session.py
|
||||
django_extensions/management/commands/reset_db.py
|
||||
django_extensions/management/commands/runjob.py
|
||||
django_extensions/management/commands/runjobs.py
|
||||
django_extensions/management/commands/runprofileserver.py
|
||||
django_extensions/management/commands/runscript.py
|
||||
django_extensions/management/commands/runserver_plus.py
|
||||
django_extensions/management/commands/set_fake_emails.py
|
||||
django_extensions/management/commands/set_fake_passwords.py
|
||||
django_extensions/management/commands/shell_plus.py
|
||||
django_extensions/management/commands/show_templatetags.py
|
||||
django_extensions/management/commands/show_urls.py
|
||||
django_extensions/management/commands/sqlcreate.py
|
||||
django_extensions/management/commands/sqldiff.py
|
||||
django_extensions/management/commands/sync_media_s3.py
|
||||
django_extensions/management/commands/sync_s3.py
|
||||
django_extensions/management/commands/syncdata.py
|
||||
django_extensions/management/commands/unreferenced_files.py
|
||||
django_extensions/management/commands/update_permissions.py
|
||||
django_extensions/management/commands/validate_templates.py
|
||||
django_extensions/migrations/0001_empty.py
|
||||
django_extensions/migrations/__init__.py
|
||||
django_extensions/mongodb/__init__.py
|
||||
django_extensions/mongodb/models.py
|
||||
django_extensions/mongodb/fields/__init__.py
|
||||
django_extensions/mongodb/fields/encrypted.py
|
||||
django_extensions/mongodb/fields/json.py
|
||||
django_extensions/static/django_extensions/css/jquery.autocomplete.css
|
||||
django_extensions/static/django_extensions/img/indicator.gif
|
||||
django_extensions/static/django_extensions/js/jquery.ajaxQueue.js
|
||||
django_extensions/static/django_extensions/js/jquery.autocomplete.js
|
||||
django_extensions/static/django_extensions/js/jquery.bgiframe.min.js
|
||||
django_extensions/templates/django_extensions/widgets/foreignkey_searchinput.html
|
||||
django_extensions/templatetags/__init__.py
|
||||
django_extensions/templatetags/highlighting.py
|
||||
django_extensions/templatetags/indent_text.py
|
||||
django_extensions/templatetags/syntax_color.py
|
||||
django_extensions/templatetags/truncate_letters.py
|
||||
django_extensions/templatetags/widont.py
|
||||
django_extensions/tests/__init__.py
|
||||
django_extensions/tests/encrypted_fields.py
|
||||
django_extensions/tests/fields.py
|
||||
django_extensions/tests/json_field.py
|
||||
django_extensions/tests/management_command.py
|
||||
django_extensions/tests/models.py
|
||||
django_extensions/tests/test_dumpscript.py
|
||||
django_extensions/tests/urls.py
|
||||
django_extensions/tests/utils.py
|
||||
django_extensions/tests/uuid_field.py
|
||||
django_extensions/tests/management/__init__.py
|
||||
django_extensions/tests/management/commands/__init__.py
|
||||
django_extensions/tests/management/commands/error_raising_command.py
|
||||
django_extensions/utils/__init__.py
|
||||
django_extensions/utils/dia2django.py
|
||||
django_extensions/utils/text.py
|
||||
django_extensions/utils/validatingtemplatetags.py
|
||||
docs/AUTHORS
|
||||
docs/Makefile
|
||||
docs/admin_extensions.rst
|
||||
docs/command_extension_ideas.rst
|
||||
docs/command_extensions.rst
|
||||
docs/conf.py
|
||||
docs/create_app.rst
|
||||
docs/creating_release.txt
|
||||
docs/dumpscript.rst
|
||||
docs/export_emails.rst
|
||||
docs/field_extensions.rst
|
||||
docs/graph_models.rst
|
||||
docs/index.rst
|
||||
docs/installation_instructions.rst
|
||||
docs/jobs_scheduling.rst
|
||||
docs/model_extensions.rst
|
||||
docs/namespace_proposal.rst
|
||||
docs/print_settings.rst
|
||||
docs/runprofileserver.rst
|
||||
docs/runscript.rst
|
||||
docs/runserver_plus.rst
|
||||
docs/shell_plus.rst
|
||||
docs/sqlcreate.rst
|
||||
docs/sqldiff.rst
|
||||
docs/sync_s3.rst
|
||||
docs/validate_templates.rst
|
|
@ -0,0 +1 @@
|
|||
|
|
@ -0,0 +1 @@
|
|||
six
|
|
@ -0,0 +1 @@
|
|||
django_extensions
|
13
contrib/django_extensions/django_extensions/__init__.py
Normal file
13
contrib/django_extensions/django_extensions/__init__.py
Normal file
|
@ -0,0 +1,13 @@
|
|||
|
||||
VERSION = (1, 2, 3, 'DEV')
|
||||
|
||||
# Dynamically calculate the version based on VERSION tuple
|
||||
if len(VERSION) > 2 and VERSION[2] is not None:
|
||||
if isinstance(VERSION[2], int):
|
||||
str_version = "%s.%s.%s" % VERSION[:3]
|
||||
else:
|
||||
str_version = "%s.%s_%s" % VERSION[:3]
|
||||
else:
|
||||
str_version = "%s.%s" % VERSION[:2]
|
||||
|
||||
__version__ = str_version
|
145
contrib/django_extensions/django_extensions/admin/__init__.py
Normal file
145
contrib/django_extensions/django_extensions/admin/__init__.py
Normal file
|
@ -0,0 +1,145 @@
|
|||
#
|
||||
# Autocomplete feature for admin panel
|
||||
#
|
||||
# Most of the code has been written by Jannis Leidel and was updated a bit
|
||||
# for django_extensions.
|
||||
# http://jannisleidel.com/2008/11/autocomplete-form-widget-foreignkey-model-fields/
|
||||
#
|
||||
# to_string_function, Satchmo adaptation and some comments added by emes
|
||||
# (Michal Salaban)
|
||||
#
|
||||
|
||||
import six
|
||||
import operator
|
||||
from six.moves import reduce
|
||||
from django.http import HttpResponse, HttpResponseNotFound
|
||||
from django.db import models
|
||||
from django.db.models.query import QuerySet
|
||||
from django.utils.encoding import smart_str
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.utils.text import get_text_list
|
||||
try:
|
||||
from functools import update_wrapper
|
||||
assert update_wrapper
|
||||
except ImportError:
|
||||
from django.utils.functional import update_wrapper
|
||||
|
||||
from django_extensions.admin.widgets import ForeignKeySearchInput
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
if 'reversion' in settings.INSTALLED_APPS:
|
||||
from reversion.admin import VersionAdmin as ModelAdmin
|
||||
assert ModelAdmin
|
||||
else:
|
||||
from django.contrib.admin import ModelAdmin
|
||||
|
||||
|
||||
class ForeignKeyAutocompleteAdmin(ModelAdmin):
|
||||
"""Admin class for models using the autocomplete feature.
|
||||
|
||||
There are two additional fields:
|
||||
- related_search_fields: defines fields of managed model that
|
||||
have to be represented by autocomplete input, together with
|
||||
a list of target model fields that are searched for
|
||||
input string, e.g.:
|
||||
|
||||
related_search_fields = {
|
||||
'author': ('first_name', 'email'),
|
||||
}
|
||||
|
||||
- related_string_functions: contains optional functions which
|
||||
take target model instance as only argument and return string
|
||||
representation. By default __unicode__() method of target
|
||||
object is used.
|
||||
"""
|
||||
|
||||
related_search_fields = {}
|
||||
related_string_functions = {}
|
||||
|
||||
def get_urls(self):
|
||||
try:
|
||||
from django.conf.urls import patterns, url
|
||||
except ImportError: # django < 1.4
|
||||
from django.conf.urls.defaults import patterns, url
|
||||
|
||||
def wrap(view):
|
||||
def wrapper(*args, **kwargs):
|
||||
return self.admin_site.admin_view(view)(*args, **kwargs)
|
||||
return update_wrapper(wrapper, view)
|
||||
|
||||
info = self.model._meta.app_label, self.model._meta.module_name
|
||||
|
||||
urlpatterns = patterns('', url(r'foreignkey_autocomplete/$', wrap(self.foreignkey_autocomplete), name='%s_%s_autocomplete' % info))
|
||||
urlpatterns += super(ForeignKeyAutocompleteAdmin, self).get_urls()
|
||||
return urlpatterns
|
||||
|
||||
def foreignkey_autocomplete(self, request):
|
||||
"""
|
||||
Searches in the fields of the given related model and returns the
|
||||
result as a simple string to be used by the jQuery Autocomplete plugin
|
||||
"""
|
||||
query = request.GET.get('q', None)
|
||||
app_label = request.GET.get('app_label', None)
|
||||
model_name = request.GET.get('model_name', None)
|
||||
search_fields = request.GET.get('search_fields', None)
|
||||
object_pk = request.GET.get('object_pk', None)
|
||||
try:
|
||||
to_string_function = self.related_string_functions[model_name]
|
||||
except KeyError:
|
||||
to_string_function = lambda x: x.__unicode__()
|
||||
if search_fields and app_label and model_name and (query or object_pk):
|
||||
def construct_search(field_name):
|
||||
# use different lookup methods depending on the notation
|
||||
if field_name.startswith('^'):
|
||||
return "%s__istartswith" % field_name[1:]
|
||||
elif field_name.startswith('='):
|
||||
return "%s__iexact" % field_name[1:]
|
||||
elif field_name.startswith('@'):
|
||||
return "%s__search" % field_name[1:]
|
||||
else:
|
||||
return "%s__icontains" % field_name
|
||||
model = models.get_model(app_label, model_name)
|
||||
queryset = model._default_manager.all()
|
||||
data = ''
|
||||
if query:
|
||||
for bit in query.split():
|
||||
or_queries = [models.Q(**{construct_search(smart_str(field_name)): smart_str(bit)}) for field_name in search_fields.split(',')]
|
||||
other_qs = QuerySet(model)
|
||||
other_qs.dup_select_related(queryset)
|
||||
other_qs = other_qs.filter(reduce(operator.or_, or_queries))
|
||||
queryset = queryset & other_qs
|
||||
data = ''.join([six.u('%s|%s\n' % (to_string_function(f), f.pk)) for f in queryset])
|
||||
elif object_pk:
|
||||
try:
|
||||
obj = queryset.get(pk=object_pk)
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
data = to_string_function(obj)
|
||||
return HttpResponse(data)
|
||||
return HttpResponseNotFound()
|
||||
|
||||
def get_help_text(self, field_name, model_name):
|
||||
searchable_fields = self.related_search_fields.get(field_name, None)
|
||||
if searchable_fields:
|
||||
help_kwargs = {
|
||||
'model_name': model_name,
|
||||
'field_list': get_text_list(searchable_fields, _('and')),
|
||||
}
|
||||
return _('Use the left field to do %(model_name)s lookups in the fields %(field_list)s.') % help_kwargs
|
||||
return ''
|
||||
|
||||
def formfield_for_dbfield(self, db_field, **kwargs):
|
||||
"""
|
||||
Overrides the default widget for Foreignkey fields if they are
|
||||
specified in the related_search_fields class attribute.
|
||||
"""
|
||||
if (isinstance(db_field, models.ForeignKey) and db_field.name in self.related_search_fields):
|
||||
model_name = db_field.rel.to._meta.object_name
|
||||
help_text = self.get_help_text(db_field.name, model_name)
|
||||
if kwargs.get('help_text'):
|
||||
help_text = six.u('%s %s' % (kwargs['help_text'], help_text))
|
||||
kwargs['widget'] = ForeignKeySearchInput(db_field.rel, self.related_search_fields[db_field.name])
|
||||
kwargs['help_text'] = help_text
|
||||
return super(ForeignKeyAutocompleteAdmin, self).formfield_for_dbfield(db_field, **kwargs)
|
94
contrib/django_extensions/django_extensions/admin/widgets.py
Normal file
94
contrib/django_extensions/django_extensions/admin/widgets.py
Normal file
|
@ -0,0 +1,94 @@
|
|||
import six
|
||||
import django
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.contrib.admin.sites import site
|
||||
from django.utils.safestring import mark_safe
|
||||
if django.get_version() >= "1.4":
|
||||
from django.utils.text import Truncator
|
||||
else:
|
||||
from django.utils.text import truncate_words
|
||||
from django.template.loader import render_to_string
|
||||
from django.contrib.admin.widgets import ForeignKeyRawIdWidget
|
||||
|
||||
|
||||
class ForeignKeySearchInput(ForeignKeyRawIdWidget):
|
||||
"""
|
||||
A Widget for displaying ForeignKeys in an autocomplete search input
|
||||
instead in a <select> box.
|
||||
"""
|
||||
# Set in subclass to render the widget with a different template
|
||||
widget_template = None
|
||||
# Set this to the patch of the search view
|
||||
search_path = '../foreignkey_autocomplete/'
|
||||
|
||||
def _media(self):
|
||||
js_files = ['django_extensions/js/jquery.bgiframe.min.js',
|
||||
'django_extensions/js/jquery.ajaxQueue.js',
|
||||
'django_extensions/js/jquery.autocomplete.js']
|
||||
return forms.Media(css={'all': ('django_extensions/css/jquery.autocomplete.css',)},
|
||||
js=js_files)
|
||||
|
||||
media = property(_media)
|
||||
|
||||
def label_for_value(self, value):
|
||||
key = self.rel.get_related_field().name
|
||||
obj = self.rel.to._default_manager.get(**{key: value})
|
||||
if django.get_version() >= "1.4":
|
||||
return Truncator(obj).words(14, truncate='...')
|
||||
else:
|
||||
return truncate_words(obj, 14)
|
||||
|
||||
def __init__(self, rel, search_fields, attrs=None):
|
||||
self.search_fields = search_fields
|
||||
if django.get_version() >= "1.4":
|
||||
super(ForeignKeySearchInput, self).__init__(rel, site, attrs)
|
||||
else:
|
||||
super(ForeignKeySearchInput, self).__init__(rel, attrs)
|
||||
|
||||
def render(self, name, value, attrs=None):
|
||||
if attrs is None:
|
||||
attrs = {}
|
||||
#output = [super(ForeignKeySearchInput, self).render(name, value, attrs)]
|
||||
opts = self.rel.to._meta
|
||||
app_label = opts.app_label
|
||||
model_name = opts.object_name.lower()
|
||||
related_url = '../../../%s/%s/' % (app_label, model_name)
|
||||
params = self.url_parameters()
|
||||
if params:
|
||||
url = '?' + '&'.join(['%s=%s' % (k, v) for k, v in params.items()])
|
||||
else:
|
||||
url = ''
|
||||
if not 'class' in attrs:
|
||||
attrs['class'] = 'vForeignKeyRawIdAdminField'
|
||||
# Call the TextInput render method directly to have more control
|
||||
output = [forms.TextInput.render(self, name, value, attrs)]
|
||||
if value:
|
||||
label = self.label_for_value(value)
|
||||
else:
|
||||
label = six.u('')
|
||||
|
||||
try:
|
||||
admin_media_prefix = settings.ADMIN_MEDIA_PREFIX
|
||||
except AttributeError:
|
||||
admin_media_prefix = settings.STATIC_URL + "admin/"
|
||||
|
||||
context = {
|
||||
'url': url,
|
||||
'related_url': related_url,
|
||||
'admin_media_prefix': admin_media_prefix,
|
||||
'search_path': self.search_path,
|
||||
'search_fields': ','.join(self.search_fields),
|
||||
'model_name': model_name,
|
||||
'app_label': app_label,
|
||||
'label': label,
|
||||
'name': name,
|
||||
'pre_django_14': (django.VERSION[:2] < (1, 4)),
|
||||
}
|
||||
output.append(render_to_string(self.widget_template or (
|
||||
'django_extensions/widgets/%s/%s/foreignkey_searchinput.html' % (app_label, model_name),
|
||||
'django_extensions/widgets/%s/foreignkey_searchinput.html' % app_label,
|
||||
'django_extensions/widgets/foreignkey_searchinput.html',
|
||||
), context))
|
||||
output.reverse()
|
||||
return mark_safe(six.u('').join(output))
|
|
@ -0,0 +1,3 @@
|
|||
from django import forms
|
||||
|
||||
# place form definition here
|
|
@ -0,0 +1,3 @@
|
|||
from django.db import models
|
||||
|
||||
# Create your models here.
|
|
@ -0,0 +1,6 @@
|
|||
try:
|
||||
from django.conf.urls import *
|
||||
except ImportError: # django < 1.4
|
||||
from django.conf.urls.defaults import *
|
||||
|
||||
# place app url patterns here
|
|
@ -0,0 +1 @@
|
|||
# Create your views here.
|
|
@ -0,0 +1,7 @@
|
|||
from django.core.management.base import {{ base_command }}
|
||||
|
||||
class Command({{ base_command }}):
|
||||
help = "My shiny new management command."
|
||||
|
||||
def {{ handle_method }}:
|
||||
raise NotImplementedError()
|
|
@ -0,0 +1,8 @@
|
|||
from django_extensions.management.jobs import BaseJob
|
||||
|
||||
class Job(BaseJob):
|
||||
help = "My sample job."
|
||||
|
||||
def execute(self):
|
||||
# executing empty sample job
|
||||
pass
|
|
@ -0,0 +1,287 @@
|
|||
"""
|
||||
Django Extensions additional model fields
|
||||
"""
|
||||
import re
|
||||
import six
|
||||
try:
|
||||
import uuid
|
||||
HAS_UUID = True
|
||||
except ImportError:
|
||||
HAS_UUID = False
|
||||
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.template.defaultfilters import slugify
|
||||
from django.db.models import DateTimeField, CharField, SlugField
|
||||
|
||||
try:
|
||||
from django.utils.timezone import now as datetime_now
|
||||
assert datetime_now
|
||||
except ImportError:
|
||||
import datetime
|
||||
datetime_now = datetime.datetime.now
|
||||
|
||||
try:
|
||||
from django.utils.encoding import force_unicode # NOQA
|
||||
except ImportError:
|
||||
from django.utils.encoding import force_text as force_unicode # NOQA
|
||||
|
||||
|
||||
class AutoSlugField(SlugField):
|
||||
""" AutoSlugField
|
||||
|
||||
By default, sets editable=False, blank=True.
|
||||
|
||||
Required arguments:
|
||||
|
||||
populate_from
|
||||
Specifies which field or list of fields the slug is populated from.
|
||||
|
||||
Optional arguments:
|
||||
|
||||
separator
|
||||
Defines the used separator (default: '-')
|
||||
|
||||
overwrite
|
||||
If set to True, overwrites the slug on every save (default: False)
|
||||
|
||||
Inspired by SmileyChris' Unique Slugify snippet:
|
||||
http://www.djangosnippets.org/snippets/690/
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs.setdefault('blank', True)
|
||||
kwargs.setdefault('editable', False)
|
||||
|
||||
populate_from = kwargs.pop('populate_from', None)
|
||||
if populate_from is None:
|
||||
raise ValueError("missing 'populate_from' argument")
|
||||
else:
|
||||
self._populate_from = populate_from
|
||||
self.separator = kwargs.pop('separator', six.u('-'))
|
||||
self.overwrite = kwargs.pop('overwrite', False)
|
||||
self.allow_duplicates = kwargs.pop('allow_duplicates', False)
|
||||
super(AutoSlugField, self).__init__(*args, **kwargs)
|
||||
|
||||
def _slug_strip(self, value):
|
||||
"""
|
||||
Cleans up a slug by removing slug separator characters that occur at
|
||||
the beginning or end of a slug.
|
||||
|
||||
If an alternate separator is used, it will also replace any instances
|
||||
of the default '-' separator with the new separator.
|
||||
"""
|
||||
re_sep = '(?:-|%s)' % re.escape(self.separator)
|
||||
value = re.sub('%s+' % re_sep, self.separator, value)
|
||||
return re.sub(r'^%s+|%s+$' % (re_sep, re_sep), '', value)
|
||||
|
||||
def get_queryset(self, model_cls, slug_field):
|
||||
for field, model in model_cls._meta.get_fields_with_model():
|
||||
if model and field == slug_field:
|
||||
return model._default_manager.all()
|
||||
return model_cls._default_manager.all()
|
||||
|
||||
def slugify_func(self, content):
|
||||
if content:
|
||||
return slugify(content)
|
||||
return ''
|
||||
|
||||
def create_slug(self, model_instance, add):
|
||||
# get fields to populate from and slug field to set
|
||||
if not isinstance(self._populate_from, (list, tuple)):
|
||||
self._populate_from = (self._populate_from, )
|
||||
slug_field = model_instance._meta.get_field(self.attname)
|
||||
|
||||
if add or self.overwrite:
|
||||
# slugify the original field content and set next step to 2
|
||||
slug_for_field = lambda field: self.slugify_func(getattr(model_instance, field))
|
||||
slug = self.separator.join(map(slug_for_field, self._populate_from))
|
||||
next = 2
|
||||
else:
|
||||
# get slug from the current model instance
|
||||
slug = getattr(model_instance, self.attname)
|
||||
# model_instance is being modified, and overwrite is False,
|
||||
# so instead of doing anything, just return the current slug
|
||||
return slug
|
||||
|
||||
# strip slug depending on max_length attribute of the slug field
|
||||
# and clean-up
|
||||
slug_len = slug_field.max_length
|
||||
if slug_len:
|
||||
slug = slug[:slug_len]
|
||||
slug = self._slug_strip(slug)
|
||||
original_slug = slug
|
||||
|
||||
if self.allow_duplicates:
|
||||
return slug
|
||||
|
||||
# exclude the current model instance from the queryset used in finding
|
||||
# the next valid slug
|
||||
queryset = self.get_queryset(model_instance.__class__, slug_field)
|
||||
if model_instance.pk:
|
||||
queryset = queryset.exclude(pk=model_instance.pk)
|
||||
|
||||
# form a kwarg dict used to impliment any unique_together contraints
|
||||
kwargs = {}
|
||||
for params in model_instance._meta.unique_together:
|
||||
if self.attname in params:
|
||||
for param in params:
|
||||
kwargs[param] = getattr(model_instance, param, None)
|
||||
kwargs[self.attname] = slug
|
||||
|
||||
# increases the number while searching for the next valid slug
|
||||
# depending on the given slug, clean-up
|
||||
while not slug or queryset.filter(**kwargs):
|
||||
slug = original_slug
|
||||
end = '%s%s' % (self.separator, next)
|
||||
end_len = len(end)
|
||||
if slug_len and len(slug) + end_len > slug_len:
|
||||
slug = slug[:slug_len - end_len]
|
||||
slug = self._slug_strip(slug)
|
||||
slug = '%s%s' % (slug, end)
|
||||
kwargs[self.attname] = slug
|
||||
next += 1
|
||||
return slug
|
||||
|
||||
def pre_save(self, model_instance, add):
|
||||
value = force_unicode(self.create_slug(model_instance, add))
|
||||
setattr(model_instance, self.attname, value)
|
||||
return value
|
||||
|
||||
def get_internal_type(self):
|
||||
return "SlugField"
|
||||
|
||||
def south_field_triple(self):
|
||||
"Returns a suitable description of this field for South."
|
||||
# We'll just introspect the _actual_ field.
|
||||
from south.modelsinspector import introspector
|
||||
field_class = '%s.AutoSlugField' % self.__module__
|
||||
args, kwargs = introspector(self)
|
||||
kwargs.update({
|
||||
'populate_from': repr(self._populate_from),
|
||||
'separator': repr(self.separator),
|
||||
'overwrite': repr(self.overwrite),
|
||||
'allow_duplicates': repr(self.allow_duplicates),
|
||||
})
|
||||
# That's our definition!
|
||||
return (field_class, args, kwargs)
|
||||
|
||||
|
||||
class CreationDateTimeField(DateTimeField):
|
||||
""" CreationDateTimeField
|
||||
|
||||
By default, sets editable=False, blank=True, default=datetime.now
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs.setdefault('editable', False)
|
||||
kwargs.setdefault('blank', True)
|
||||
kwargs.setdefault('default', datetime_now)
|
||||
DateTimeField.__init__(self, *args, **kwargs)
|
||||
|
||||
def get_internal_type(self):
|
||||
return "DateTimeField"
|
||||
|
||||
def south_field_triple(self):
|
||||
"Returns a suitable description of this field for South."
|
||||
# We'll just introspect ourselves, since we inherit.
|
||||
from south.modelsinspector import introspector
|
||||
field_class = "django.db.models.fields.DateTimeField"
|
||||
args, kwargs = introspector(self)
|
||||
return (field_class, args, kwargs)
|
||||
|
||||
|
||||
class ModificationDateTimeField(CreationDateTimeField):
|
||||
""" ModificationDateTimeField
|
||||
|
||||
By default, sets editable=False, blank=True, default=datetime.now
|
||||
|
||||
Sets value to datetime.now() on each save of the model.
|
||||
"""
|
||||
|
||||
def pre_save(self, model, add):
|
||||
value = datetime_now()
|
||||
setattr(model, self.attname, value)
|
||||
return value
|
||||
|
||||
def get_internal_type(self):
|
||||
return "DateTimeField"
|
||||
|
||||
def south_field_triple(self):
|
||||
"Returns a suitable description of this field for South."
|
||||
# We'll just introspect ourselves, since we inherit.
|
||||
from south.modelsinspector import introspector
|
||||
field_class = "django.db.models.fields.DateTimeField"
|
||||
args, kwargs = introspector(self)
|
||||
return (field_class, args, kwargs)
|
||||
|
||||
|
||||
class UUIDVersionError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class UUIDField(CharField):
|
||||
""" UUIDField
|
||||
|
||||
By default uses UUID version 4 (randomly generated UUID).
|
||||
|
||||
The field support all uuid versions which are natively supported by the uuid python module, except version 2.
|
||||
For more information see: http://docs.python.org/lib/module-uuid.html
|
||||
"""
|
||||
|
||||
def __init__(self, verbose_name=None, name=None, auto=True, version=4, node=None, clock_seq=None, namespace=None, **kwargs):
|
||||
if not HAS_UUID:
|
||||
raise ImproperlyConfigured("'uuid' module is required for UUIDField. (Do you have Python 2.5 or higher installed ?)")
|
||||
kwargs.setdefault('max_length', 36)
|
||||
if auto:
|
||||
self.empty_strings_allowed = False
|
||||
kwargs['blank'] = True
|
||||
kwargs.setdefault('editable', False)
|
||||
self.auto = auto
|
||||
self.version = version
|
||||
if version == 1:
|
||||
self.node, self.clock_seq = node, clock_seq
|
||||
elif version == 3 or version == 5:
|
||||
self.namespace, self.name = namespace, name
|
||||
CharField.__init__(self, verbose_name, name, **kwargs)
|
||||
|
||||
def get_internal_type(self):
|
||||
return CharField.__name__
|
||||
|
||||
def create_uuid(self):
|
||||
if not self.version or self.version == 4:
|
||||
return uuid.uuid4()
|
||||
elif self.version == 1:
|
||||
return uuid.uuid1(self.node, self.clock_seq)
|
||||
elif self.version == 2:
|
||||
raise UUIDVersionError("UUID version 2 is not supported.")
|
||||
elif self.version == 3:
|
||||
return uuid.uuid3(self.namespace, self.name)
|
||||
elif self.version == 5:
|
||||
return uuid.uuid5(self.namespace, self.name)
|
||||
else:
|
||||
raise UUIDVersionError("UUID version %s is not valid." % self.version)
|
||||
|
||||
def pre_save(self, model_instance, add):
|
||||
value = super(UUIDField, self).pre_save(model_instance, add)
|
||||
if self.auto and add and value is None:
|
||||
value = force_unicode(self.create_uuid())
|
||||
setattr(model_instance, self.attname, value)
|
||||
return value
|
||||
else:
|
||||
if self.auto and not value:
|
||||
value = force_unicode(self.create_uuid())
|
||||
setattr(model_instance, self.attname, value)
|
||||
return value
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
if self.auto:
|
||||
return None
|
||||
return super(UUIDField, self).formfield(**kwargs)
|
||||
|
||||
def south_field_triple(self):
|
||||
"Returns a suitable description of this field for South."
|
||||
# We'll just introspect the _actual_ field.
|
||||
from south.modelsinspector import introspector
|
||||
field_class = "django.db.models.fields.CharField"
|
||||
args, kwargs = introspector(self)
|
||||
# That's our definition!
|
||||
return (field_class, args, kwargs)
|
|
@ -0,0 +1,138 @@
|
|||
import six
|
||||
from django.db import models
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
import warnings
|
||||
|
||||
try:
|
||||
from keyczar import keyczar
|
||||
except ImportError:
|
||||
raise ImportError('Using an encrypted field requires the Keyczar module. '
|
||||
'You can obtain Keyczar from http://www.keyczar.org/.')
|
||||
|
||||
|
||||
class EncryptionWarning(RuntimeWarning):
|
||||
pass
|
||||
|
||||
|
||||
class BaseEncryptedField(models.Field):
|
||||
prefix = 'enc_str:::'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
if not hasattr(settings, 'ENCRYPTED_FIELD_KEYS_DIR'):
|
||||
raise ImproperlyConfigured('You must set the settings.ENCRYPTED_FIELD_KEYS_DIR '
|
||||
'setting to your Keyczar keys directory.')
|
||||
crypt_class = self.get_crypt_class()
|
||||
self.crypt = crypt_class.Read(settings.ENCRYPTED_FIELD_KEYS_DIR)
|
||||
|
||||
# Encrypted size is larger than unencrypted
|
||||
self.unencrypted_length = max_length = kwargs.get('max_length', None)
|
||||
if max_length:
|
||||
max_length = len(self.prefix) + len(self.crypt.Encrypt('x' * max_length))
|
||||
# TODO: Re-examine if this logic will actually make a large-enough
|
||||
# max-length for unicode strings that have non-ascii characters in them.
|
||||
kwargs['max_length'] = max_length
|
||||
|
||||
super(BaseEncryptedField, self).__init__(*args, **kwargs)
|
||||
|
||||
def get_crypt_class(self):
|
||||
"""
|
||||
Get the Keyczar class to use.
|
||||
|
||||
The class can be customized with the ENCRYPTED_FIELD_MODE setting. By default,
|
||||
this setting is DECRYPT_AND_ENCRYPT. Set this to ENCRYPT to disable decryption.
|
||||
This is necessary if you are only providing public keys to Keyczar.
|
||||
|
||||
Returns:
|
||||
keyczar.Encrypter if ENCRYPTED_FIELD_MODE is ENCRYPT.
|
||||
keyczar.Crypter if ENCRYPTED_FIELD_MODE is DECRYPT_AND_ENCRYPT.
|
||||
|
||||
Override this method to customize the type of Keyczar class returned.
|
||||
"""
|
||||
|
||||
crypt_type = getattr(settings, 'ENCRYPTED_FIELD_MODE', 'DECRYPT_AND_ENCRYPT')
|
||||
if crypt_type == 'ENCRYPT':
|
||||
crypt_class_name = 'Encrypter'
|
||||
elif crypt_type == 'DECRYPT_AND_ENCRYPT':
|
||||
crypt_class_name = 'Crypter'
|
||||
else:
|
||||
raise ImproperlyConfigured(
|
||||
'ENCRYPTED_FIELD_MODE must be either DECRYPT_AND_ENCRYPT '
|
||||
'or ENCRYPT, not %s.' % crypt_type)
|
||||
return getattr(keyczar, crypt_class_name)
|
||||
|
||||
def to_python(self, value):
|
||||
if isinstance(self.crypt.primary_key, keyczar.keys.RsaPublicKey):
|
||||
retval = value
|
||||
elif value and (value.startswith(self.prefix)):
|
||||
if hasattr(self.crypt, 'Decrypt'):
|
||||
retval = self.crypt.Decrypt(value[len(self.prefix):])
|
||||
if retval:
|
||||
retval = retval.decode('utf-8')
|
||||
else:
|
||||
retval = value
|
||||
else:
|
||||
retval = value
|
||||
return retval
|
||||
|
||||
def get_db_prep_value(self, value, connection, prepared=False):
|
||||
if value and not value.startswith(self.prefix):
|
||||
# We need to encode a unicode string into a byte string, first.
|
||||
# keyczar expects a bytestring, not a unicode string.
|
||||
if type(value) == six.types.UnicodeType:
|
||||
value = value.encode('utf-8')
|
||||
# Truncated encrypted content is unreadable,
|
||||
# so truncate before encryption
|
||||
max_length = self.unencrypted_length
|
||||
if max_length and len(value) > max_length:
|
||||
warnings.warn("Truncating field %s from %d to %d bytes" % (
|
||||
self.name, len(value), max_length), EncryptionWarning
|
||||
)
|
||||
value = value[:max_length]
|
||||
|
||||
value = self.prefix + self.crypt.Encrypt(value)
|
||||
return value
|
||||
|
||||
|
||||
class EncryptedTextField(six.with_metaclass(models.SubfieldBase,
|
||||
BaseEncryptedField)):
|
||||
def get_internal_type(self):
|
||||
return 'TextField'
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
defaults = {'widget': forms.Textarea}
|
||||
defaults.update(kwargs)
|
||||
return super(EncryptedTextField, self).formfield(**defaults)
|
||||
|
||||
def south_field_triple(self):
|
||||
"Returns a suitable description of this field for South."
|
||||
# We'll just introspect the _actual_ field.
|
||||
from south.modelsinspector import introspector
|
||||
field_class = "django.db.models.fields.TextField"
|
||||
args, kwargs = introspector(self)
|
||||
# That's our definition!
|
||||
return (field_class, args, kwargs)
|
||||
|
||||
|
||||
class EncryptedCharField(six.with_metaclass(models.SubfieldBase,
|
||||
BaseEncryptedField)):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(EncryptedCharField, self).__init__(*args, **kwargs)
|
||||
|
||||
def get_internal_type(self):
|
||||
return "CharField"
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
defaults = {'max_length': self.max_length}
|
||||
defaults.update(kwargs)
|
||||
return super(EncryptedCharField, self).formfield(**defaults)
|
||||
|
||||
def south_field_triple(self):
|
||||
"Returns a suitable description of this field for South."
|
||||
# We'll just introspect the _actual_ field.
|
||||
from south.modelsinspector import introspector
|
||||
field_class = "django.db.models.fields.CharField"
|
||||
args, kwargs = introspector(self)
|
||||
# That's our definition!
|
||||
return (field_class, args, kwargs)
|
|
@ -0,0 +1,98 @@
|
|||
"""
|
||||
JSONField automatically serializes most Python terms to JSON data.
|
||||
Creates a TEXT field with a default value of "{}". See test_json.py for
|
||||
more information.
|
||||
|
||||
from django.db import models
|
||||
from django_extensions.db.fields import json
|
||||
|
||||
class LOL(models.Model):
|
||||
extra = json.JSONField()
|
||||
"""
|
||||
|
||||
import six
|
||||
from decimal import Decimal
|
||||
from django.db import models
|
||||
from django.conf import settings
|
||||
from django.core.serializers.json import DjangoJSONEncoder
|
||||
|
||||
try:
|
||||
# Django <= 1.6 backwards compatibility
|
||||
from django.utils import simplejson as json
|
||||
except ImportError:
|
||||
# Django >= 1.7
|
||||
import json
|
||||
|
||||
|
||||
def dumps(value):
|
||||
return DjangoJSONEncoder().encode(value)
|
||||
|
||||
|
||||
def loads(txt):
|
||||
value = json.loads(
|
||||
txt,
|
||||
parse_float=Decimal,
|
||||
encoding=settings.DEFAULT_CHARSET
|
||||
)
|
||||
return value
|
||||
|
||||
|
||||
class JSONDict(dict):
|
||||
"""
|
||||
Hack so repr() called by dumpdata will output JSON instead of
|
||||
Python formatted data. This way fixtures will work!
|
||||
"""
|
||||
def __repr__(self):
|
||||
return dumps(self)
|
||||
|
||||
|
||||
class JSONList(list):
|
||||
"""
|
||||
As above
|
||||
"""
|
||||
def __repr__(self):
|
||||
return dumps(self)
|
||||
|
||||
|
||||
class JSONField(six.with_metaclass(models.SubfieldBase, models.TextField)):
|
||||
"""JSONField is a generic textfield that neatly serializes/unserializes
|
||||
JSON objects seamlessly. Main thingy must be a dict object."""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
default = kwargs.get('default', None)
|
||||
if default is None:
|
||||
kwargs['default'] = '{}'
|
||||
elif isinstance(default, (list, dict)):
|
||||
kwargs['default'] = dumps(default)
|
||||
models.TextField.__init__(self, *args, **kwargs)
|
||||
|
||||
def to_python(self, value):
|
||||
"""Convert our string value to JSON after we load it from the DB"""
|
||||
if value is None or value == '':
|
||||
return {}
|
||||
elif isinstance(value, six.string_types):
|
||||
res = loads(value)
|
||||
if isinstance(res, dict):
|
||||
return JSONDict(**res)
|
||||
else:
|
||||
return JSONList(res)
|
||||
|
||||
else:
|
||||
return value
|
||||
|
||||
def get_db_prep_save(self, value, connection):
|
||||
"""Convert our JSON object to a string before we save"""
|
||||
if not isinstance(value, (list, dict)):
|
||||
return super(JSONField, self).get_db_prep_save("", connection=connection)
|
||||
else:
|
||||
return super(JSONField, self).get_db_prep_save(dumps(value),
|
||||
connection=connection)
|
||||
|
||||
def south_field_triple(self):
|
||||
"Returns a suitable description of this field for South."
|
||||
# We'll just introspect the _actual_ field.
|
||||
from south.modelsinspector import introspector
|
||||
field_class = "django.db.models.fields.TextField"
|
||||
args, kwargs = introspector(self)
|
||||
# That's our definition!
|
||||
return (field_class, args, kwargs)
|
78
contrib/django_extensions/django_extensions/db/models.py
Normal file
78
contrib/django_extensions/django_extensions/db/models.py
Normal file
|
@ -0,0 +1,78 @@
|
|||
"""
|
||||
Django Extensions abstract base model classes.
|
||||
"""
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django_extensions.db.fields import (ModificationDateTimeField,
|
||||
CreationDateTimeField, AutoSlugField)
|
||||
|
||||
try:
|
||||
from django.utils.timezone import now as datetime_now
|
||||
assert datetime_now
|
||||
except ImportError:
|
||||
import datetime
|
||||
datetime_now = datetime.datetime.now
|
||||
|
||||
|
||||
class TimeStampedModel(models.Model):
|
||||
""" TimeStampedModel
|
||||
An abstract base class model that provides self-managed "created" and
|
||||
"modified" fields.
|
||||
"""
|
||||
created = CreationDateTimeField(_('created'))
|
||||
modified = ModificationDateTimeField(_('modified'))
|
||||
|
||||
class Meta:
|
||||
get_latest_by = 'modified'
|
||||
ordering = ('-modified', '-created',)
|
||||
abstract = True
|
||||
|
||||
|
||||
class TitleSlugDescriptionModel(models.Model):
|
||||
""" TitleSlugDescriptionModel
|
||||
An abstract base class model that provides title and description fields
|
||||
and a self-managed "slug" field that populates from the title.
|
||||
"""
|
||||
title = models.CharField(_('title'), max_length=255)
|
||||
slug = AutoSlugField(_('slug'), populate_from='title')
|
||||
description = models.TextField(_('description'), blank=True, null=True)
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
|
||||
class ActivatorModelManager(models.Manager):
|
||||
""" ActivatorModelManager
|
||||
Manager to return instances of ActivatorModel: SomeModel.objects.active() / .inactive()
|
||||
"""
|
||||
def active(self):
|
||||
""" Returns active instances of ActivatorModel: SomeModel.objects.active() """
|
||||
return self.get_query_set().filter(status=ActivatorModel.ACTIVE_STATUS)
|
||||
|
||||
def inactive(self):
|
||||
""" Returns inactive instances of ActivatorModel: SomeModel.objects.inactive() """
|
||||
return self.get_query_set().filter(status=ActivatorModel.INACTIVE_STATUS)
|
||||
|
||||
|
||||
class ActivatorModel(models.Model):
|
||||
""" ActivatorModel
|
||||
An abstract base class model that provides activate and deactivate fields.
|
||||
"""
|
||||
INACTIVE_STATUS, ACTIVE_STATUS = range(2)
|
||||
STATUS_CHOICES = (
|
||||
(INACTIVE_STATUS, _('Inactive')),
|
||||
(ACTIVE_STATUS, _('Active')),
|
||||
)
|
||||
status = models.IntegerField(_('status'), choices=STATUS_CHOICES, default=ACTIVE_STATUS)
|
||||
activate_date = models.DateTimeField(blank=True, null=True, help_text=_('keep empty for an immediate activation'))
|
||||
deactivate_date = models.DateTimeField(blank=True, null=True, help_text=_('keep empty for indefinite activation'))
|
||||
objects = ActivatorModelManager()
|
||||
|
||||
class Meta:
|
||||
ordering = ('status', '-activate_date',)
|
||||
abstract = True
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.activate_date:
|
||||
self.activate_date = datetime_now()
|
||||
super(ActivatorModel, self).save(*args, **kwargs)
|
16
contrib/django_extensions/django_extensions/future_1_5.py
Normal file
16
contrib/django_extensions/django_extensions/future_1_5.py
Normal file
|
@ -0,0 +1,16 @@
|
|||
"""
|
||||
A forwards compatibility module.
|
||||
|
||||
Implements some features of Django 1.5 related to the 'Custom User Model' feature
|
||||
when the application is run with a lower version of Django.
|
||||
"""
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
User.USERNAME_FIELD = "username"
|
||||
User.get_username = lambda self: self.username
|
||||
|
||||
|
||||
def get_user_model():
|
||||
return User
|
|
@ -0,0 +1,50 @@
|
|||
"""
|
||||
Daily cleanup job.
|
||||
|
||||
Can be run as a cronjob to clean out old data from the database (only expired
|
||||
sessions at the moment).
|
||||
"""
|
||||
|
||||
from django_extensions.management.jobs import DailyJob
|
||||
|
||||
|
||||
class Job(DailyJob):
|
||||
help = "Cache (db) cleanup Job"
|
||||
|
||||
def execute(self):
|
||||
from django.conf import settings
|
||||
from django.db import transaction
|
||||
import os
|
||||
|
||||
try:
|
||||
from django.utils import timezone
|
||||
except ImportError:
|
||||
timezone = None
|
||||
|
||||
if hasattr(settings, 'CACHES') and timezone:
|
||||
from django.core.cache import get_cache
|
||||
from django.db import router, connections
|
||||
|
||||
for cache_name, cache_options in settings.CACHES.iteritems():
|
||||
if cache_options['BACKEND'].endswith("DatabaseCache"):
|
||||
cache = get_cache(cache_name)
|
||||
db = router.db_for_write(cache.cache_model_class)
|
||||
cursor = connections[db].cursor()
|
||||
now = timezone.now()
|
||||
cache._cull(db, cursor, now)
|
||||
transaction.commit_unless_managed(using=db)
|
||||
return
|
||||
|
||||
if hasattr(settings, 'CACHE_BACKEND'):
|
||||
if settings.CACHE_BACKEND.startswith('db://'):
|
||||
from django.db import connection
|
||||
os.environ['TZ'] = settings.TIME_ZONE
|
||||
table_name = settings.CACHE_BACKEND[5:]
|
||||
cursor = connection.cursor()
|
||||
cursor.execute(
|
||||
"DELETE FROM %s WHERE %s < current_timestamp;" % (
|
||||
connection.ops.quote_name(table_name),
|
||||
connection.ops.quote_name('expires')
|
||||
)
|
||||
)
|
||||
transaction.commit_unless_managed()
|
|
@ -0,0 +1,16 @@
|
|||
"""
|
||||
Daily cleanup job.
|
||||
|
||||
Can be run as a cronjob to clean out old data from the database (only expired
|
||||
sessions at the moment).
|
||||
"""
|
||||
|
||||
from django_extensions.management.jobs import DailyJob
|
||||
|
||||
|
||||
class Job(DailyJob):
|
||||
help = "Django Daily Cleanup Job"
|
||||
|
||||
def execute(self):
|
||||
from django.core import management
|
||||
management.call_command("cleanup")
|
Binary file not shown.
|
@ -0,0 +1,77 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: django-extensions\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2011-02-02 11:42+0100\n"
|
||||
"PO-Revision-Date: 2011-02-02 10:42+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: cs\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2\n"
|
||||
|
||||
#: admin/__init__.py:121
|
||||
msgid "and"
|
||||
msgstr ""
|
||||
|
||||
#: admin/__init__.py:123
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Use the left field to do %(model_name)s lookups in the fields %(field_list)s."
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:15
|
||||
msgid "created"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:16
|
||||
msgid "modified"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:26
|
||||
msgid "title"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:27
|
||||
msgid "slug"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:28
|
||||
msgid "description"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:50
|
||||
msgid "Inactive"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:51
|
||||
msgid "Active"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:53
|
||||
msgid "status"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:56
|
||||
msgid "keep empty for an immediate activation"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:58
|
||||
msgid "keep empty for indefinite activation"
|
||||
msgstr ""
|
||||
|
||||
#: management/commands/show_urls.py:34
|
||||
#, python-format
|
||||
msgid "%s does not appear to be a urlpattern object"
|
||||
msgstr ""
|
||||
|
||||
#: templates/django_extensions/widgets/foreignkey_searchinput.html:4
|
||||
msgid "Lookup"
|
||||
msgstr ""
|
Binary file not shown.
|
@ -0,0 +1,79 @@
|
|||
# django_extentions in Danish.
|
||||
# django_extensions på Dansk.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# Michael Lind Mortensen <illio@cs.au.dk>, 2009.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2011-02-02 11:42+0100\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: admin/__init__.py:121
|
||||
msgid "and"
|
||||
msgstr "og"
|
||||
|
||||
#: admin/__init__.py:123
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Use the left field to do %(model_name)s lookups in the fields %(field_list)s."
|
||||
msgstr ""
|
||||
"Brug feltet til venstre til at lave %(model_name)s lookups i felterne %"
|
||||
"(field_list)s."
|
||||
|
||||
#: db/models.py:15
|
||||
msgid "created"
|
||||
msgstr "skabt"
|
||||
|
||||
#: db/models.py:16
|
||||
msgid "modified"
|
||||
msgstr "ændret"
|
||||
|
||||
#: db/models.py:26
|
||||
msgid "title"
|
||||
msgstr "titel"
|
||||
|
||||
#: db/models.py:27
|
||||
msgid "slug"
|
||||
msgstr "slug"
|
||||
|
||||
#: db/models.py:28
|
||||
msgid "description"
|
||||
msgstr "beskrivelse"
|
||||
|
||||
#: db/models.py:50
|
||||
msgid "Inactive"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:51
|
||||
msgid "Active"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:53
|
||||
msgid "status"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:56
|
||||
msgid "keep empty for an immediate activation"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:58
|
||||
msgid "keep empty for indefinite activation"
|
||||
msgstr ""
|
||||
|
||||
#: management/commands/show_urls.py:34
|
||||
#, python-format
|
||||
msgid "%s does not appear to be a urlpattern object"
|
||||
msgstr ""
|
||||
|
||||
#: templates/django_extensions/widgets/foreignkey_searchinput.html:4
|
||||
msgid "Lookup"
|
||||
msgstr "Lookup"
|
Binary file not shown.
|
@ -0,0 +1,77 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2011-02-02 11:42+0100\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: admin/__init__.py:121
|
||||
msgid "and"
|
||||
msgstr "und"
|
||||
|
||||
#: admin/__init__.py:123
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Use the left field to do %(model_name)s lookups in the fields %(field_list)s."
|
||||
msgstr ""
|
||||
"Das linke Feld benutzen, um %(model_name)s Abfragen in den Feldern %"
|
||||
"(field_list)s durchführen."
|
||||
|
||||
#: db/models.py:15
|
||||
msgid "created"
|
||||
msgstr "erstellt"
|
||||
|
||||
#: db/models.py:16
|
||||
msgid "modified"
|
||||
msgstr "geändert"
|
||||
|
||||
#: db/models.py:26
|
||||
msgid "title"
|
||||
msgstr "Titel"
|
||||
|
||||
#: db/models.py:27
|
||||
msgid "slug"
|
||||
msgstr "Slug"
|
||||
|
||||
#: db/models.py:28
|
||||
msgid "description"
|
||||
msgstr "Beschreibung"
|
||||
|
||||
#: db/models.py:50
|
||||
msgid "Inactive"
|
||||
msgstr "Inaktiv"
|
||||
|
||||
#: db/models.py:51
|
||||
msgid "Active"
|
||||
msgstr "Aktiv"
|
||||
|
||||
#: db/models.py:53
|
||||
msgid "status"
|
||||
msgstr "Status"
|
||||
|
||||
#: db/models.py:56
|
||||
msgid "keep empty for an immediate activation"
|
||||
msgstr "Leer lassen für sofortige Aktivierung"
|
||||
|
||||
#: db/models.py:58
|
||||
msgid "keep empty for indefinite activation"
|
||||
msgstr "Leer lassen für unbefristete Aktivierung"
|
||||
|
||||
#: management/commands/show_urls.py:34
|
||||
#, python-format
|
||||
msgid "%s does not appear to be a urlpattern object"
|
||||
msgstr "%s ist kein urlpattern Objekt"
|
||||
|
||||
#: templates/django_extensions/widgets/foreignkey_searchinput.html:4
|
||||
msgid "Lookup"
|
||||
msgstr "Abfrage"
|
Binary file not shown.
|
@ -0,0 +1,79 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: django-extensions\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2011-02-02 11:42+0100\n"
|
||||
"PO-Revision-Date: 2011-02-02 10:38+0000\n"
|
||||
"Last-Translator: Jannis <jannis@leidel.info>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: el\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
||||
|
||||
#: admin/__init__.py:121
|
||||
msgid "and"
|
||||
msgstr "και"
|
||||
|
||||
#: admin/__init__.py:123
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Use the left field to do %(model_name)s lookups in the fields %(field_list)s."
|
||||
msgstr ""
|
||||
"Χρησιμοποίησε το αριστερό πεδίο για να κάνεις αναζήτηση του %(model_name)s "
|
||||
"με βάσει τα πεδία %(field_list)s."
|
||||
|
||||
#: db/models.py:15
|
||||
msgid "created"
|
||||
msgstr "δημιουργήθηκε"
|
||||
|
||||
#: db/models.py:16
|
||||
msgid "modified"
|
||||
msgstr "τροποποιήθηκε"
|
||||
|
||||
#: db/models.py:26
|
||||
msgid "title"
|
||||
msgstr "τίτλος"
|
||||
|
||||
#: db/models.py:27
|
||||
msgid "slug"
|
||||
msgstr "μίνι-όνομα"
|
||||
|
||||
#: db/models.py:28
|
||||
msgid "description"
|
||||
msgstr "περιγραφή"
|
||||
|
||||
#: db/models.py:50
|
||||
msgid "Inactive"
|
||||
msgstr "ανενεργό"
|
||||
|
||||
#: db/models.py:51
|
||||
msgid "Active"
|
||||
msgstr "Ενεργό"
|
||||
|
||||
#: db/models.py:53
|
||||
msgid "status"
|
||||
msgstr "κατάσταση"
|
||||
|
||||
#: db/models.py:56
|
||||
msgid "keep empty for an immediate activation"
|
||||
msgstr "αφήστε άδειο για άμεση ενεργοποίηση"
|
||||
|
||||
#: db/models.py:58
|
||||
msgid "keep empty for indefinite activation"
|
||||
msgstr "αφήστε άδειο για αόριστη ενεργοποίηση"
|
||||
|
||||
#: management/commands/show_urls.py:34
|
||||
#, python-format
|
||||
msgid "%s does not appear to be a urlpattern object"
|
||||
msgstr "% s δεν φαίνεται να είναι ένα αντικείμενο urlpattern"
|
||||
|
||||
#: templates/django_extensions/widgets/foreignkey_searchinput.html:4
|
||||
msgid "Lookup"
|
||||
msgstr "Αναζήτηση"
|
Binary file not shown.
|
@ -0,0 +1,76 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2011-02-02 11:42+0100\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: admin/__init__.py:121
|
||||
msgid "and"
|
||||
msgstr ""
|
||||
|
||||
#: admin/__init__.py:123
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Use the left field to do %(model_name)s lookups in the fields %(field_list)s."
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:15
|
||||
msgid "created"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:16
|
||||
msgid "modified"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:26
|
||||
msgid "title"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:27
|
||||
msgid "slug"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:28
|
||||
msgid "description"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:50
|
||||
msgid "Inactive"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:51
|
||||
msgid "Active"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:53
|
||||
msgid "status"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:56
|
||||
msgid "keep empty for an immediate activation"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:58
|
||||
msgid "keep empty for indefinite activation"
|
||||
msgstr ""
|
||||
|
||||
#: management/commands/show_urls.py:34
|
||||
#, python-format
|
||||
msgid "%s does not appear to be a urlpattern object"
|
||||
msgstr ""
|
||||
|
||||
#: templates/django_extensions/widgets/foreignkey_searchinput.html:4
|
||||
msgid "Lookup"
|
||||
msgstr ""
|
Binary file not shown.
|
@ -0,0 +1,77 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2011-02-02 11:43+0100\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: admin/__init__.py:121
|
||||
msgid "and"
|
||||
msgstr "y"
|
||||
|
||||
#: admin/__init__.py:123
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Use the left field to do %(model_name)s lookups in the fields %(field_list)s."
|
||||
msgstr ""
|
||||
"Utilice el campo de la izquierda para hacer búsquedas en los campos %"
|
||||
"(field_list)s de %(model_name)s."
|
||||
|
||||
#: db/models.py:15
|
||||
msgid "created"
|
||||
msgstr "creado"
|
||||
|
||||
#: db/models.py:16
|
||||
msgid "modified"
|
||||
msgstr "modificado"
|
||||
|
||||
#: db/models.py:26
|
||||
msgid "title"
|
||||
msgstr "titulo"
|
||||
|
||||
#: db/models.py:27
|
||||
msgid "slug"
|
||||
msgstr "slug"
|
||||
|
||||
#: db/models.py:28
|
||||
msgid "description"
|
||||
msgstr "descripción"
|
||||
|
||||
#: db/models.py:50
|
||||
msgid "Inactive"
|
||||
msgstr "Inactivo"
|
||||
|
||||
#: db/models.py:51
|
||||
msgid "Active"
|
||||
msgstr "Activo"
|
||||
|
||||
#: db/models.py:53
|
||||
msgid "status"
|
||||
msgstr "estado"
|
||||
|
||||
#: db/models.py:56
|
||||
msgid "keep empty for an immediate activation"
|
||||
msgstr "mantener vacío para una activación inmediata"
|
||||
|
||||
#: db/models.py:58
|
||||
msgid "keep empty for indefinite activation"
|
||||
msgstr "deje vacío para mantener la activación indefinida"
|
||||
|
||||
#: management/commands/show_urls.py:34
|
||||
#, python-format
|
||||
msgid "%s does not appear to be a urlpattern object"
|
||||
msgstr "% s no parece ser un objeto urlpattern"
|
||||
|
||||
#: templates/django_extensions/widgets/foreignkey_searchinput.html:4
|
||||
msgid "Lookup"
|
||||
msgstr "Buscar"
|
Binary file not shown.
|
@ -0,0 +1,75 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2011-02-02 11:43+0100\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: admin/__init__.py:121
|
||||
msgid "and"
|
||||
msgstr "ja"
|
||||
|
||||
#: admin/__init__.py:123
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Use the left field to do %(model_name)s lookups in the fields %(field_list)s."
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:15
|
||||
msgid "created"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:16
|
||||
msgid "modified"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:26
|
||||
msgid "title"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:27
|
||||
msgid "slug"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:28
|
||||
msgid "description"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:50
|
||||
msgid "Inactive"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:51
|
||||
msgid "Active"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:53
|
||||
msgid "status"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:56
|
||||
msgid "keep empty for an immediate activation"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:58
|
||||
msgid "keep empty for indefinite activation"
|
||||
msgstr ""
|
||||
|
||||
#: management/commands/show_urls.py:34
|
||||
#, python-format
|
||||
msgid "%s does not appear to be a urlpattern object"
|
||||
msgstr ""
|
||||
|
||||
#: templates/django_extensions/widgets/foreignkey_searchinput.html:4
|
||||
msgid "Lookup"
|
||||
msgstr ""
|
Binary file not shown.
|
@ -0,0 +1,82 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: django-extensions\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2011-02-02 11:43+0100\n"
|
||||
"PO-Revision-Date: 2011-02-02 10:38+0000\n"
|
||||
"Last-Translator: Jannis <jannis@leidel.info>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: fr\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1)\n"
|
||||
|
||||
#: admin/__init__.py:121
|
||||
msgid "and"
|
||||
msgstr "et"
|
||||
|
||||
#: admin/__init__.py:123
|
||||
#, fuzzy, python-format
|
||||
msgid ""
|
||||
"Use the left field to do %(model_name)s lookups in the fields %(field_list)s."
|
||||
msgstr ""
|
||||
"Utilisez le champ de gauche pour faire des recheres de %(MODEL_NAME)s dans "
|
||||
"les champs %(field_list)s."
|
||||
|
||||
#: db/models.py:15
|
||||
msgid "created"
|
||||
msgstr "créé"
|
||||
|
||||
#: db/models.py:16
|
||||
msgid "modified"
|
||||
msgstr "mise à jour"
|
||||
|
||||
#: db/models.py:26
|
||||
msgid "title"
|
||||
msgstr "titre"
|
||||
|
||||
#: db/models.py:27
|
||||
msgid "slug"
|
||||
msgstr "slug"
|
||||
|
||||
#: db/models.py:28
|
||||
msgid "description"
|
||||
msgstr "description"
|
||||
|
||||
#: db/models.py:50
|
||||
msgid "Inactive"
|
||||
msgstr "inactif"
|
||||
|
||||
#: db/models.py:51
|
||||
msgid "Active"
|
||||
msgstr "active"
|
||||
|
||||
#: db/models.py:53
|
||||
msgid "status"
|
||||
msgstr "état"
|
||||
|
||||
#: db/models.py:56
|
||||
#, fuzzy
|
||||
msgid "keep empty for an immediate activation"
|
||||
msgstr "garder vide pour l'activation immédiate"
|
||||
|
||||
#: db/models.py:58
|
||||
#, fuzzy
|
||||
msgid "keep empty for indefinite activation"
|
||||
msgstr "garder vide pour l'activation de durée indéterminée"
|
||||
|
||||
#: management/commands/show_urls.py:34
|
||||
#, fuzzy, python-format
|
||||
msgid "%s does not appear to be a urlpattern object"
|
||||
msgstr "%s ne semble pas être un objet urlpattern"
|
||||
|
||||
#: templates/django_extensions/widgets/foreignkey_searchinput.html:4
|
||||
#, fuzzy
|
||||
msgid "Lookup"
|
||||
msgstr "Recherche"
|
Binary file not shown.
|
@ -0,0 +1,77 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2011-02-02 11:43+0100\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: admin/__init__.py:121
|
||||
msgid "and"
|
||||
msgstr "és"
|
||||
|
||||
#: admin/__init__.py:123
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Use the left field to do %(model_name)s lookups in the fields %(field_list)s."
|
||||
msgstr ""
|
||||
"Használd a baloldali mezőt hogy keress a %(model_name)s %(field_list)s. "
|
||||
"mezőiben"
|
||||
|
||||
#: db/models.py:15
|
||||
msgid "created"
|
||||
msgstr "létrehozva"
|
||||
|
||||
#: db/models.py:16
|
||||
msgid "modified"
|
||||
msgstr "módosítva"
|
||||
|
||||
#: db/models.py:26
|
||||
msgid "title"
|
||||
msgstr "Cím"
|
||||
|
||||
#: db/models.py:27
|
||||
msgid "slug"
|
||||
msgstr "Slug"
|
||||
|
||||
#: db/models.py:28
|
||||
msgid "description"
|
||||
msgstr "Leírás"
|
||||
|
||||
#: db/models.py:50
|
||||
msgid "Inactive"
|
||||
msgstr "Inaktív"
|
||||
|
||||
#: db/models.py:51
|
||||
msgid "Active"
|
||||
msgstr "Aktív"
|
||||
|
||||
#: db/models.py:53
|
||||
msgid "status"
|
||||
msgstr "Állapot"
|
||||
|
||||
#: db/models.py:56
|
||||
msgid "keep empty for an immediate activation"
|
||||
msgstr "Üresen hagyni azonnali aktiváláshoz"
|
||||
|
||||
#: db/models.py:58
|
||||
msgid "keep empty for indefinite activation"
|
||||
msgstr "Üresen hagyni korlátlan aktiváláshoz"
|
||||
|
||||
#: management/commands/show_urls.py:34
|
||||
#, python-format
|
||||
msgid "%s does not appear to be a urlpattern object"
|
||||
msgstr "Úgy néz ki hogy %s nem egy urlpattern objektum"
|
||||
|
||||
#: templates/django_extensions/widgets/foreignkey_searchinput.html:4
|
||||
msgid "Lookup"
|
||||
msgstr "Lekérdezés"
|
Binary file not shown.
|
@ -0,0 +1,77 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2011-02-02 11:43+0100\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: admin/__init__.py:121
|
||||
msgid "and"
|
||||
msgstr "e"
|
||||
|
||||
#: admin/__init__.py:123
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Use the left field to do %(model_name)s lookups in the fields %(field_list)s."
|
||||
msgstr ""
|
||||
"Utilizzare il campo a sinistra per fare ricerche nei campi %(field_list)s "
|
||||
"del modello %(model_name)s."
|
||||
|
||||
#: db/models.py:15
|
||||
msgid "created"
|
||||
msgstr "creato"
|
||||
|
||||
#: db/models.py:16
|
||||
msgid "modified"
|
||||
msgstr "modificato"
|
||||
|
||||
#: db/models.py:26
|
||||
msgid "title"
|
||||
msgstr "titolo"
|
||||
|
||||
#: db/models.py:27
|
||||
msgid "slug"
|
||||
msgstr "slug"
|
||||
|
||||
#: db/models.py:28
|
||||
msgid "description"
|
||||
msgstr "descrizione"
|
||||
|
||||
#: db/models.py:50
|
||||
msgid "Inactive"
|
||||
msgstr "Inattivo"
|
||||
|
||||
#: db/models.py:51
|
||||
msgid "Active"
|
||||
msgstr "Attivo"
|
||||
|
||||
#: db/models.py:53
|
||||
msgid "status"
|
||||
msgstr "stato"
|
||||
|
||||
#: db/models.py:56
|
||||
msgid "keep empty for an immediate activation"
|
||||
msgstr "lasciare vuoto per attivazione immediata"
|
||||
|
||||
#: db/models.py:58
|
||||
msgid "keep empty for indefinite activation"
|
||||
msgstr "lasciare vuoti per attivazione indefinita"
|
||||
|
||||
#: management/commands/show_urls.py:34
|
||||
#, python-format
|
||||
msgid "%s does not appear to be a urlpattern object"
|
||||
msgstr "% s non sembra essere un oggetto urlPattern"
|
||||
|
||||
#: templates/django_extensions/widgets/foreignkey_searchinput.html:4
|
||||
msgid "Lookup"
|
||||
msgstr "Ricerca"
|
Binary file not shown.
|
@ -0,0 +1,77 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2011-02-02 11:43+0100\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: admin/__init__.py:121
|
||||
msgid "and"
|
||||
msgstr "と"
|
||||
|
||||
#: admin/__init__.py:123
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Use the left field to do %(model_name)s lookups in the fields %(field_list)s."
|
||||
msgstr ""
|
||||
"%(field_list)s フィールドの内容から %(model_name)s を検索するには左のフィール"
|
||||
"ドを使用して下さい。"
|
||||
|
||||
#: db/models.py:15
|
||||
msgid "created"
|
||||
msgstr "作成日時"
|
||||
|
||||
#: db/models.py:16
|
||||
msgid "modified"
|
||||
msgstr "変更日時"
|
||||
|
||||
#: db/models.py:26
|
||||
msgid "title"
|
||||
msgstr "タイトル"
|
||||
|
||||
#: db/models.py:27
|
||||
msgid "slug"
|
||||
msgstr "スラグ"
|
||||
|
||||
#: db/models.py:28
|
||||
msgid "description"
|
||||
msgstr "説明"
|
||||
|
||||
#: db/models.py:50
|
||||
msgid "Inactive"
|
||||
msgstr "非アクティブ"
|
||||
|
||||
#: db/models.py:51
|
||||
msgid "Active"
|
||||
msgstr "アクティブ"
|
||||
|
||||
#: db/models.py:53
|
||||
msgid "status"
|
||||
msgstr "ステータス"
|
||||
|
||||
#: db/models.py:56
|
||||
msgid "keep empty for an immediate activation"
|
||||
msgstr "すぐに有効化する場合は空白のままにして下さい"
|
||||
|
||||
#: db/models.py:58
|
||||
msgid "keep empty for indefinite activation"
|
||||
msgstr "無期限に有効化しておく場合は空白のままにして下さい"
|
||||
|
||||
#: management/commands/show_urls.py:34
|
||||
#, python-format
|
||||
msgid "%s does not appear to be a urlpattern object"
|
||||
msgstr "%s は urlpattern オブジェクトではないようです"
|
||||
|
||||
#: templates/django_extensions/widgets/foreignkey_searchinput.html:4
|
||||
msgid "Lookup"
|
||||
msgstr "検索"
|
Binary file not shown.
|
@ -0,0 +1,77 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2011-02-02 11:43+0100\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Zbigniew Siciarz <antyqjon@gmail.com>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: admin/__init__.py:121
|
||||
msgid "and"
|
||||
msgstr "i"
|
||||
|
||||
#: admin/__init__.py:123
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Use the left field to do %(model_name)s lookups in the fields %(field_list)s."
|
||||
msgstr ""
|
||||
"Użyj pola po lewej, by wyszukać pola %(field_list)s w modelu %(model_name)s."
|
||||
|
||||
#: db/models.py:15
|
||||
msgid "created"
|
||||
msgstr "utworzony"
|
||||
|
||||
#: db/models.py:16
|
||||
msgid "modified"
|
||||
msgstr "zmodyfikowany"
|
||||
|
||||
#: db/models.py:26
|
||||
msgid "title"
|
||||
msgstr "tytuł"
|
||||
|
||||
#: db/models.py:27
|
||||
msgid "slug"
|
||||
msgstr "slug"
|
||||
|
||||
#: db/models.py:28
|
||||
msgid "description"
|
||||
msgstr "opis"
|
||||
|
||||
#: db/models.py:50
|
||||
msgid "Inactive"
|
||||
msgstr "Nieaktywny"
|
||||
|
||||
#: db/models.py:51
|
||||
msgid "Active"
|
||||
msgstr "Aktywny"
|
||||
|
||||
#: db/models.py:53
|
||||
msgid "status"
|
||||
msgstr "stan"
|
||||
|
||||
#: db/models.py:56
|
||||
msgid "keep empty for an immediate activation"
|
||||
msgstr "pozostaw puste, by aktywować od razu"
|
||||
|
||||
#: db/models.py:58
|
||||
msgid "keep empty for indefinite activation"
|
||||
msgstr "pozostaw puste, by nie definiować daty deaktywacji"
|
||||
|
||||
#: management/commands/show_urls.py:34
|
||||
#, python-format
|
||||
msgid "%s does not appear to be a urlpattern object"
|
||||
msgstr "%s nie jest obiektem typu urlpattern"
|
||||
|
||||
#: templates/django_extensions/widgets/foreignkey_searchinput.html:4
|
||||
msgid "Lookup"
|
||||
msgstr "Szukaj"
|
Binary file not shown.
|
@ -0,0 +1,77 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2011-02-02 11:43+0100\n"
|
||||
"PO-Revision-Date: 2010-11-15 22:06-0300\n"
|
||||
"Last-Translator: Fernando Silva <fernand at liquuid dot net>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: admin/__init__.py:121
|
||||
msgid "and"
|
||||
msgstr "e"
|
||||
|
||||
#: admin/__init__.py:123
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Use the left field to do %(model_name)s lookups in the fields %(field_list)s."
|
||||
msgstr ""
|
||||
"Use o campo esquerdo para fazer com que o modelo %(model_name)s procure nos "
|
||||
"campos %(field_list)s."
|
||||
|
||||
#: db/models.py:15
|
||||
msgid "created"
|
||||
msgstr "criado"
|
||||
|
||||
#: db/models.py:16
|
||||
msgid "modified"
|
||||
msgstr "modificado"
|
||||
|
||||
#: db/models.py:26
|
||||
msgid "title"
|
||||
msgstr "título"
|
||||
|
||||
#: db/models.py:27
|
||||
msgid "slug"
|
||||
msgstr "slug"
|
||||
|
||||
#: db/models.py:28
|
||||
msgid "description"
|
||||
msgstr "descrição"
|
||||
|
||||
#: db/models.py:50
|
||||
msgid "Inactive"
|
||||
msgstr "Inativo"
|
||||
|
||||
#: db/models.py:51
|
||||
msgid "Active"
|
||||
msgstr "Ativo"
|
||||
|
||||
#: db/models.py:53
|
||||
msgid "status"
|
||||
msgstr "estado"
|
||||
|
||||
#: db/models.py:56
|
||||
msgid "keep empty for an immediate activation"
|
||||
msgstr "deixe vazio para ativação imediata"
|
||||
|
||||
#: db/models.py:58
|
||||
msgid "keep empty for indefinite activation"
|
||||
msgstr "deixe vazio para ativação por tempo indeterminado"
|
||||
|
||||
#: management/commands/show_urls.py:34
|
||||
#, python-format
|
||||
msgid "%s does not appear to be a urlpattern object"
|
||||
msgstr "%s não parece ser um objeto urlpattern"
|
||||
|
||||
#: templates/django_extensions/widgets/foreignkey_searchinput.html:4
|
||||
msgid "Lookup"
|
||||
msgstr "Busca"
|
Binary file not shown.
|
@ -0,0 +1,79 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# Claudemiro Alves Feitosa Neto <dimiro1@gmail.com>, 2013.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2013-09-13 22:49-0300\n"
|
||||
"PO-Revision-Date: 2013-09-13 22:49-0300\n"
|
||||
"Last-Translator: Claudemiro Alves Feitosa <dimiro1@gmail.com>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#: admin/__init__.py:128
|
||||
msgid "and"
|
||||
msgstr "e"
|
||||
|
||||
#: admin/__init__.py:130
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Use the left field to do %(model_name)s lookups in the fields %(field_list)s."
|
||||
msgstr "Use o campo da esquerda para fazer com que o modelo %(model_name)s procure nos "
|
||||
"campos %(field_list)s"
|
||||
|
||||
#: db/models.py:22 mongodb/models.py:17
|
||||
msgid "created"
|
||||
msgstr "criado"
|
||||
|
||||
#: db/models.py:23 mongodb/models.py:18
|
||||
msgid "modified"
|
||||
msgstr "modificado"
|
||||
|
||||
#: db/models.py:36 mongodb/models.py:29
|
||||
msgid "title"
|
||||
msgstr "título"
|
||||
|
||||
#: db/models.py:37 mongodb/models.py:30
|
||||
msgid "slug"
|
||||
msgstr "slug"
|
||||
|
||||
#: db/models.py:38 mongodb/models.py:31
|
||||
msgid "description"
|
||||
msgstr "descrição"
|
||||
|
||||
#: db/models.py:63 mongodb/models.py:55
|
||||
msgid "Inactive"
|
||||
msgstr "Inativo"
|
||||
|
||||
#: db/models.py:64 mongodb/models.py:56
|
||||
msgid "Active"
|
||||
msgstr "Ativo"
|
||||
|
||||
#: db/models.py:66 mongodb/models.py:58
|
||||
msgid "status"
|
||||
msgstr "status"
|
||||
|
||||
#: db/models.py:67 mongodb/models.py:59
|
||||
msgid "keep empty for an immediate activation"
|
||||
msgstr "deixe vazio para uma ativação imediata"
|
||||
|
||||
#: db/models.py:68 mongodb/models.py:60
|
||||
msgid "keep empty for indefinite activation"
|
||||
msgstr "deixe vazio para ativação por tempo indeterminado"
|
||||
|
||||
#: mongodb/fields/__init__.py:24
|
||||
#, python-format
|
||||
msgid "String (up to %(max_length)s)"
|
||||
msgstr "Cadeia de Caracteres (até %(max_length)s)"
|
||||
|
||||
#: templates/django_extensions/widgets/foreignkey_searchinput.html:4
|
||||
msgid "Lookup"
|
||||
msgstr "Busca"
|
Binary file not shown.
|
@ -0,0 +1,80 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: django-extensions\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2011-02-02 11:43+0100\n"
|
||||
"PO-Revision-Date: 2011-02-02 10:38+0000\n"
|
||||
"Last-Translator: Jannis <jannis@leidel.info>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: ro\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < "
|
||||
"20)) ? 1 : 2)\n"
|
||||
|
||||
#: admin/__init__.py:121
|
||||
msgid "and"
|
||||
msgstr "și"
|
||||
|
||||
#: admin/__init__.py:123
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Use the left field to do %(model_name)s lookups in the fields %(field_list)s."
|
||||
msgstr ""
|
||||
"Folosește câmpul din stânga pentru a efectua căutări de %(model_name)s în "
|
||||
"câmpurile %(field_list)s."
|
||||
|
||||
#: db/models.py:15
|
||||
msgid "created"
|
||||
msgstr "creat"
|
||||
|
||||
#: db/models.py:16
|
||||
msgid "modified"
|
||||
msgstr "modificat"
|
||||
|
||||
#: db/models.py:26
|
||||
msgid "title"
|
||||
msgstr "Titlu"
|
||||
|
||||
#: db/models.py:27
|
||||
msgid "slug"
|
||||
msgstr "Slug"
|
||||
|
||||
#: db/models.py:28
|
||||
msgid "description"
|
||||
msgstr "Descriere"
|
||||
|
||||
#: db/models.py:50
|
||||
msgid "Inactive"
|
||||
msgstr "Inactiv"
|
||||
|
||||
#: db/models.py:51
|
||||
msgid "Active"
|
||||
msgstr "Activ"
|
||||
|
||||
#: db/models.py:53
|
||||
msgid "status"
|
||||
msgstr "Stare"
|
||||
|
||||
#: db/models.py:56
|
||||
msgid "keep empty for an immediate activation"
|
||||
msgstr "A se lăsa gol pentru activare imediată"
|
||||
|
||||
#: db/models.py:58
|
||||
msgid "keep empty for indefinite activation"
|
||||
msgstr "A se lăsa gol pentru activare nelimitată"
|
||||
|
||||
#: management/commands/show_urls.py:34
|
||||
#, python-format
|
||||
msgid "%s does not appear to be a urlpattern object"
|
||||
msgstr "%s nu pare să fie un obiect urlpattern"
|
||||
|
||||
#: templates/django_extensions/widgets/foreignkey_searchinput.html:4
|
||||
msgid "Lookup"
|
||||
msgstr "Căutare"
|
Binary file not shown.
|
@ -0,0 +1,78 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: django-extensions\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2011-02-02 11:43+0100\n"
|
||||
"PO-Revision-Date: 2011-02-02 10:42+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: ru\n"
|
||||
"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%"
|
||||
"10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
|
||||
|
||||
#: admin/__init__.py:121
|
||||
msgid "and"
|
||||
msgstr ""
|
||||
|
||||
#: admin/__init__.py:123
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Use the left field to do %(model_name)s lookups in the fields %(field_list)s."
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:15
|
||||
msgid "created"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:16
|
||||
msgid "modified"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:26
|
||||
msgid "title"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:27
|
||||
msgid "slug"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:28
|
||||
msgid "description"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:50
|
||||
msgid "Inactive"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:51
|
||||
msgid "Active"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:53
|
||||
msgid "status"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:56
|
||||
msgid "keep empty for an immediate activation"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:58
|
||||
msgid "keep empty for indefinite activation"
|
||||
msgstr ""
|
||||
|
||||
#: management/commands/show_urls.py:34
|
||||
#, python-format
|
||||
msgid "%s does not appear to be a urlpattern object"
|
||||
msgstr ""
|
||||
|
||||
#: templates/django_extensions/widgets/foreignkey_searchinput.html:4
|
||||
msgid "Lookup"
|
||||
msgstr ""
|
Binary file not shown.
|
@ -0,0 +1,77 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: django-extensions\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2011-02-02 11:43+0100\n"
|
||||
"PO-Revision-Date: 2011-02-02 10:42+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: sk\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2\n"
|
||||
|
||||
#: admin/__init__.py:121
|
||||
msgid "and"
|
||||
msgstr ""
|
||||
|
||||
#: admin/__init__.py:123
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Use the left field to do %(model_name)s lookups in the fields %(field_list)s."
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:15
|
||||
msgid "created"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:16
|
||||
msgid "modified"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:26
|
||||
msgid "title"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:27
|
||||
msgid "slug"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:28
|
||||
msgid "description"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:50
|
||||
msgid "Inactive"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:51
|
||||
msgid "Active"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:53
|
||||
msgid "status"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:56
|
||||
msgid "keep empty for an immediate activation"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:58
|
||||
msgid "keep empty for indefinite activation"
|
||||
msgstr ""
|
||||
|
||||
#: management/commands/show_urls.py:34
|
||||
#, python-format
|
||||
msgid "%s does not appear to be a urlpattern object"
|
||||
msgstr ""
|
||||
|
||||
#: templates/django_extensions/widgets/foreignkey_searchinput.html:4
|
||||
msgid "Lookup"
|
||||
msgstr ""
|
Binary file not shown.
|
@ -0,0 +1,77 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: django-extensions\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2011-02-02 11:43+0100\n"
|
||||
"PO-Revision-Date: 2011-02-02 10:42+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: tr\n"
|
||||
"Plural-Forms: nplurals=1; plural=0\n"
|
||||
|
||||
#: admin/__init__.py:121
|
||||
msgid "and"
|
||||
msgstr ""
|
||||
|
||||
#: admin/__init__.py:123
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Use the left field to do %(model_name)s lookups in the fields %(field_list)s."
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:15
|
||||
msgid "created"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:16
|
||||
msgid "modified"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:26
|
||||
msgid "title"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:27
|
||||
msgid "slug"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:28
|
||||
msgid "description"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:50
|
||||
msgid "Inactive"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:51
|
||||
msgid "Active"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:53
|
||||
msgid "status"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:56
|
||||
msgid "keep empty for an immediate activation"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:58
|
||||
msgid "keep empty for indefinite activation"
|
||||
msgstr ""
|
||||
|
||||
#: management/commands/show_urls.py:34
|
||||
#, python-format
|
||||
msgid "%s does not appear to be a urlpattern object"
|
||||
msgstr ""
|
||||
|
||||
#: templates/django_extensions/widgets/foreignkey_searchinput.html:4
|
||||
msgid "Lookup"
|
||||
msgstr ""
|
Binary file not shown.
|
@ -0,0 +1,77 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: django-extensions\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2011-02-02 11:43+0100\n"
|
||||
"PO-Revision-Date: 2011-02-02 10:42+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: zh_CN\n"
|
||||
"Plural-Forms: nplurals=1; plural=0\n"
|
||||
|
||||
#: admin/__init__.py:121
|
||||
msgid "and"
|
||||
msgstr ""
|
||||
|
||||
#: admin/__init__.py:123
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Use the left field to do %(model_name)s lookups in the fields %(field_list)s."
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:15
|
||||
msgid "created"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:16
|
||||
msgid "modified"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:26
|
||||
msgid "title"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:27
|
||||
msgid "slug"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:28
|
||||
msgid "description"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:50
|
||||
msgid "Inactive"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:51
|
||||
msgid "Active"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:53
|
||||
msgid "status"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:56
|
||||
msgid "keep empty for an immediate activation"
|
||||
msgstr ""
|
||||
|
||||
#: db/models.py:58
|
||||
msgid "keep empty for indefinite activation"
|
||||
msgstr ""
|
||||
|
||||
#: management/commands/show_urls.py:34
|
||||
#, python-format
|
||||
msgid "%s does not appear to be a urlpattern object"
|
||||
msgstr ""
|
||||
|
||||
#: templates/django_extensions/widgets/foreignkey_searchinput.html:4
|
||||
msgid "Lookup"
|
||||
msgstr ""
|
|
@ -0,0 +1,53 @@
|
|||
import sys
|
||||
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.utils.log import getLogger
|
||||
|
||||
|
||||
logger = getLogger('django.commands')
|
||||
|
||||
|
||||
class LoggingBaseCommand(BaseCommand):
|
||||
"""
|
||||
A subclass of BaseCommand that logs run time errors to `django.commands`.
|
||||
To use this, create a management command subclassing LoggingBaseCommand:
|
||||
|
||||
from django_extensions.management.base import LoggingBaseCommand
|
||||
|
||||
class Command(LoggingBaseCommand):
|
||||
help = 'Test error'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
raise Exception
|
||||
|
||||
|
||||
And then define a logging handler in settings.py:
|
||||
|
||||
LOGGING = {
|
||||
... # Other stuff here
|
||||
|
||||
'handlers': {
|
||||
'mail_admins': {
|
||||
'level': 'ERROR',
|
||||
'filters': ['require_debug_false'],
|
||||
'class': 'django.utils.log.AdminEmailHandler'
|
||||
},
|
||||
},
|
||||
'loggers': {
|
||||
'django.commands': {
|
||||
'handlers': ['mail_admins'],
|
||||
'level': 'ERROR',
|
||||
'propagate': False,
|
||||
},
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
"""
|
||||
|
||||
def execute(self, *args, **options):
|
||||
try:
|
||||
super(LoggingBaseCommand, self).execute(*args, **options)
|
||||
except Exception as e:
|
||||
logger.error(e, exc_info=sys.exc_info(), extra={'status_code': 500})
|
||||
raise
|
|
@ -0,0 +1,19 @@
|
|||
"""
|
||||
Sets up the terminal color scheme.
|
||||
"""
|
||||
|
||||
from django.core.management import color
|
||||
from django.utils import termcolors
|
||||
|
||||
|
||||
def color_style():
|
||||
style = color.color_style()
|
||||
if color.supports_color():
|
||||
style.INFO = termcolors.make_style(fg='green')
|
||||
style.WARN = termcolors.make_style(fg='yellow')
|
||||
style.BOLD = termcolors.make_style(opts=('bold',))
|
||||
style.URL = termcolors.make_style(fg='green', opts=('bold',))
|
||||
style.MODULE = termcolors.make_style(fg='yellow')
|
||||
style.MODULE_NAME = termcolors.make_style(opts=('bold',))
|
||||
style.URL_NAME = termcolors.make_style(fg='red')
|
||||
return style
|
|
@ -0,0 +1,37 @@
|
|||
from django.core.management.base import NoArgsCommand
|
||||
from django_extensions.management.utils import get_project_root
|
||||
from optparse import make_option
|
||||
from os.path import join as _j
|
||||
import os
|
||||
|
||||
|
||||
class Command(NoArgsCommand):
|
||||
option_list = NoArgsCommand.option_list + (
|
||||
make_option('--optimize', '-o', '-O', action='store_true', dest='optimize',
|
||||
help='Remove optimized python bytecode files'),
|
||||
make_option('--path', '-p', action='store', dest='path',
|
||||
help='Specify path to recurse into'),
|
||||
)
|
||||
help = "Removes all python bytecode compiled files from the project."
|
||||
|
||||
requires_model_validation = False
|
||||
|
||||
def handle_noargs(self, **options):
|
||||
project_root = options.get("path", None)
|
||||
if not project_root:
|
||||
project_root = get_project_root()
|
||||
exts = options.get("optimize", False) and [".pyc", ".pyo"] or [".pyc"]
|
||||
verbose = int(options.get("verbosity", 1))
|
||||
|
||||
if verbose > 1:
|
||||
print("Project Root: %s" % project_root)
|
||||
|
||||
for root, dirs, files in os.walk(project_root):
|
||||
for file in files:
|
||||
ext = os.path.splitext(file)[1]
|
||||
if ext in exts:
|
||||
full_path = _j(root, file)
|
||||
if verbose > 1:
|
||||
print(full_path)
|
||||
os.remove(full_path)
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
from django.core.management.base import NoArgsCommand
|
||||
from django_extensions.management.utils import get_project_root
|
||||
from optparse import make_option
|
||||
from os.path import join as _j
|
||||
import py_compile
|
||||
import os
|
||||
|
||||
|
||||
class Command(NoArgsCommand):
|
||||
option_list = NoArgsCommand.option_list + (
|
||||
make_option('--path', '-p', action='store', dest='path', help='Specify path to recurse into'),
|
||||
)
|
||||
help = "Compile python bytecode files for the project."
|
||||
|
||||
requires_model_validation = False
|
||||
|
||||
def handle_noargs(self, **options):
|
||||
project_root = options.get("path", None)
|
||||
if not project_root:
|
||||
project_root = get_project_root()
|
||||
verbose = int(options.get("verbosity", 1)) > 1
|
||||
|
||||
for root, dirs, files in os.walk(project_root):
|
||||
for file in files:
|
||||
ext = os.path.splitext(file)[1]
|
||||
if ext == ".py":
|
||||
full_path = _j(root, file)
|
||||
if verbose:
|
||||
print("%sc" % full_path)
|
||||
py_compile.compile(full_path)
|
|
@ -0,0 +1,138 @@
|
|||
import os
|
||||
import re
|
||||
import sys
|
||||
import django_extensions
|
||||
from django.conf import settings
|
||||
from django.db import connection
|
||||
from django.core.management.base import CommandError, LabelCommand
|
||||
from django.template import Template, Context
|
||||
from django_extensions.settings import REPLACEMENTS
|
||||
from django_extensions.utils.dia2django import dia2django
|
||||
from django_extensions.management.utils import _make_writeable
|
||||
from optparse import make_option
|
||||
|
||||
|
||||
class Command(LabelCommand):
|
||||
option_list = LabelCommand.option_list + (
|
||||
make_option('--template', '-t', action='store', dest='app_template',
|
||||
help='The path to the app template'),
|
||||
make_option('--parent_path', '-p', action='store', dest='parent_path',
|
||||
help='The parent path of the application to be created'),
|
||||
make_option('-d', action='store_true', dest='dia_parse',
|
||||
help='Generate model.py and admin.py from [APP_NAME].dia file'),
|
||||
make_option('--diagram', action='store', dest='dia_path',
|
||||
help='The diagram path of the app to be created. -d is implied'),
|
||||
)
|
||||
|
||||
help = ("Creates an application directory structure for the specified application name.")
|
||||
args = "APP_NAME"
|
||||
label = 'application name'
|
||||
|
||||
requires_model_validation = False
|
||||
can_import_settings = True
|
||||
|
||||
def handle_label(self, label, **options):
|
||||
project_dir = os.getcwd()
|
||||
project_name = os.path.split(project_dir)[-1]
|
||||
app_name = label
|
||||
app_template = options.get('app_template') or os.path.join(django_extensions.__path__[0], 'conf', 'app_template')
|
||||
app_dir = os.path.join(options.get('parent_path') or project_dir, app_name)
|
||||
dia_path = options.get('dia_path') or os.path.join(project_dir, '%s.dia' % app_name)
|
||||
|
||||
if not os.path.exists(app_template):
|
||||
raise CommandError("The template path, %r, does not exist." % app_template)
|
||||
|
||||
if not re.search(r'^\w+$', label):
|
||||
raise CommandError("%r is not a valid application name. Please use only numbers, letters and underscores." % label)
|
||||
|
||||
dia_parse = options.get('dia_path') or options.get('dia_parse')
|
||||
if dia_parse:
|
||||
if not os.path.exists(dia_path):
|
||||
raise CommandError("The diagram path, %r, does not exist." % dia_path)
|
||||
if app_name in settings.INSTALLED_APPS:
|
||||
raise CommandError("The application %s should not be defined in the settings file. Please remove %s now, and add it after using this command." % (app_name, app_name))
|
||||
tables = [name for name in connection.introspection.table_names() if name.startswith('%s_' % app_name)]
|
||||
if tables:
|
||||
raise CommandError("%r application has tables in the database. Please delete them." % app_name)
|
||||
|
||||
try:
|
||||
os.makedirs(app_dir)
|
||||
except OSError as e:
|
||||
raise CommandError(e)
|
||||
|
||||
copy_template(app_template, app_dir, project_name, app_name)
|
||||
|
||||
if dia_parse:
|
||||
generate_models_and_admin(dia_path, app_dir, project_name, app_name)
|
||||
print("Application %r created." % app_name)
|
||||
print("Please add now %r and any other dependent application in settings.INSTALLED_APPS, and run 'manage syncdb'" % app_name)
|
||||
|
||||
|
||||
def copy_template(app_template, copy_to, project_name, app_name):
|
||||
"""copies the specified template directory to the copy_to location"""
|
||||
import shutil
|
||||
|
||||
app_template = os.path.normpath(app_template)
|
||||
# walks the template structure and copies it
|
||||
for d, subdirs, files in os.walk(app_template):
|
||||
relative_dir = d[len(app_template) + 1:]
|
||||
d_new = os.path.join(copy_to, relative_dir).replace('app_name', app_name)
|
||||
if relative_dir and not os.path.exists(d_new):
|
||||
os.mkdir(d_new)
|
||||
for i, subdir in enumerate(subdirs):
|
||||
if subdir.startswith('.'):
|
||||
del subdirs[i]
|
||||
replacements = {'app_name': app_name, 'project_name': project_name}
|
||||
replacements.update(REPLACEMENTS)
|
||||
for f in files:
|
||||
if f.endswith('.pyc') or f.startswith('.DS_Store'):
|
||||
continue
|
||||
path_old = os.path.join(d, f)
|
||||
path_new = os.path.join(d_new, f.replace('app_name', app_name))
|
||||
if os.path.exists(path_new):
|
||||
path_new = os.path.join(d_new, f)
|
||||
if os.path.exists(path_new):
|
||||
continue
|
||||
if path_new.endswith('.tmpl'):
|
||||
path_new = path_new[:-5]
|
||||
fp_old = open(path_old, 'r')
|
||||
fp_new = open(path_new, 'w')
|
||||
fp_new.write(Template(fp_old.read()).render(Context(replacements)))
|
||||
fp_old.close()
|
||||
fp_new.close()
|
||||
try:
|
||||
shutil.copymode(path_old, path_new)
|
||||
_make_writeable(path_new)
|
||||
except OSError:
|
||||
sys.stderr.write("Notice: Couldn't set permission bits on %s. You're probably using an uncommon filesystem setup. No problem.\n" % path_new)
|
||||
|
||||
|
||||
def generate_models_and_admin(dia_path, app_dir, project_name, app_name):
|
||||
"""Generates the models.py and admin.py files"""
|
||||
|
||||
def format_text(string, indent=False):
|
||||
"""format string in lines of 80 or less characters"""
|
||||
retval = ''
|
||||
while string:
|
||||
line = string[:77]
|
||||
last_space = line.rfind(' ')
|
||||
if last_space != -1 and len(string) > 77:
|
||||
retval += "%s \\\n" % string[:last_space]
|
||||
string = string[last_space + 1:]
|
||||
else:
|
||||
retval += "%s\n" % string
|
||||
string = ''
|
||||
if string and indent:
|
||||
string = ' %s' % string
|
||||
return retval
|
||||
|
||||
model_path = os.path.join(app_dir, 'models.py')
|
||||
admin_path = os.path.join(app_dir, 'admin.py')
|
||||
|
||||
models_txt = 'from django.db import models\n' + dia2django(dia_path)
|
||||
open(model_path, 'w').write(models_txt)
|
||||
|
||||
classes = re.findall('class (\w+)', models_txt)
|
||||
admin_txt = 'from django.contrib.admin import site, ModelAdmin\n' + format_text('from %s.%s.models import %s' % (project_name, app_name, ', '.join(classes)), indent=True)
|
||||
admin_txt += format_text('\n\n%s' % '\n'.join(map((lambda t: 'site.register(%s)' % t), classes)))
|
||||
open(admin_path, 'w').write(admin_txt)
|
|
@ -0,0 +1,81 @@
|
|||
import os
|
||||
import sys
|
||||
from django.core.management.base import CommandError, AppCommand
|
||||
from django_extensions.management.utils import _make_writeable
|
||||
from optparse import make_option
|
||||
|
||||
|
||||
class Command(AppCommand):
|
||||
option_list = AppCommand.option_list + (
|
||||
make_option('--name', '-n', action='store', dest='command_name', default='sample',
|
||||
help='The name to use for the management command'),
|
||||
make_option('--base', '-b', action='store', dest='base_command', default='Base',
|
||||
help='The base class used for implementation of this command. Should be one of Base, App, Label, or NoArgs'),
|
||||
)
|
||||
|
||||
help = ("Creates a Django management command directory structure for the given app name"
|
||||
" in the current directory.")
|
||||
args = "[appname]"
|
||||
label = 'application name'
|
||||
|
||||
requires_model_validation = False
|
||||
# Can't import settings during this command, because they haven't
|
||||
# necessarily been created.
|
||||
can_import_settings = True
|
||||
|
||||
def handle_app(self, app, **options):
|
||||
directory = os.getcwd()
|
||||
app_name = app.__name__.split('.')[-2]
|
||||
project_dir = os.path.join(directory, app_name)
|
||||
if not os.path.exists(project_dir):
|
||||
try:
|
||||
os.mkdir(project_dir)
|
||||
except OSError as e:
|
||||
raise CommandError(e)
|
||||
|
||||
copy_template('command_template', project_dir, options.get('command_name'), '%sCommand' % options.get('base_command'))
|
||||
|
||||
|
||||
def copy_template(template_name, copy_to, command_name, base_command):
|
||||
"""copies the specified template directory to the copy_to location"""
|
||||
import django_extensions
|
||||
import shutil
|
||||
|
||||
template_dir = os.path.join(django_extensions.__path__[0], 'conf', template_name)
|
||||
|
||||
handle_method = "handle(self, *args, **options)"
|
||||
if base_command == 'AppCommand':
|
||||
handle_method = "handle_app(self, app, **options)"
|
||||
elif base_command == 'LabelCommand':
|
||||
handle_method = "handle_label(self, label, **options)"
|
||||
elif base_command == 'NoArgsCommand':
|
||||
handle_method = "handle_noargs(self, **options)"
|
||||
|
||||
# walks the template structure and copies it
|
||||
for d, subdirs, files in os.walk(template_dir):
|
||||
relative_dir = d[len(template_dir) + 1:]
|
||||
if relative_dir and not os.path.exists(os.path.join(copy_to, relative_dir)):
|
||||
os.mkdir(os.path.join(copy_to, relative_dir))
|
||||
for i, subdir in enumerate(subdirs):
|
||||
if subdir.startswith('.'):
|
||||
del subdirs[i]
|
||||
for f in files:
|
||||
if f.endswith('.pyc') or f.startswith('.DS_Store'):
|
||||
continue
|
||||
path_old = os.path.join(d, f)
|
||||
path_new = os.path.join(copy_to, relative_dir, f.replace('sample', command_name))
|
||||
if os.path.exists(path_new):
|
||||
path_new = os.path.join(copy_to, relative_dir, f)
|
||||
if os.path.exists(path_new):
|
||||
continue
|
||||
path_new = path_new.rstrip(".tmpl")
|
||||
fp_old = open(path_old, 'r')
|
||||
fp_new = open(path_new, 'w')
|
||||
fp_new.write(fp_old.read().replace('{{ command_name }}', command_name).replace('{{ base_command }}', base_command).replace('{{ handle_method }}', handle_method))
|
||||
fp_old.close()
|
||||
fp_new.close()
|
||||
try:
|
||||
shutil.copymode(path_old, path_new)
|
||||
_make_writeable(path_new)
|
||||
except OSError:
|
||||
sys.stderr.write("Notice: Couldn't set permission bits on %s. You're probably using an uncommon filesystem setup. No problem.\n" % path_new)
|
|
@ -0,0 +1,56 @@
|
|||
import os
|
||||
import sys
|
||||
from django.core.management.base import AppCommand
|
||||
from django_extensions.management.utils import _make_writeable
|
||||
|
||||
|
||||
class Command(AppCommand):
|
||||
help = ("Creates a Django jobs command directory structure for the given app name in the current directory.")
|
||||
args = "[appname]"
|
||||
label = 'application name'
|
||||
|
||||
requires_model_validation = False
|
||||
# Can't import settings during this command, because they haven't
|
||||
# necessarily been created.
|
||||
can_import_settings = True
|
||||
|
||||
def handle_app(self, app, **options):
|
||||
app_dir = os.path.dirname(app.__file__)
|
||||
copy_template('jobs_template', app_dir)
|
||||
|
||||
|
||||
def copy_template(template_name, copy_to):
|
||||
"""copies the specified template directory to the copy_to location"""
|
||||
import django_extensions
|
||||
import shutil
|
||||
|
||||
template_dir = os.path.join(django_extensions.__path__[0], 'conf', template_name)
|
||||
|
||||
# walks the template structure and copies it
|
||||
for d, subdirs, files in os.walk(template_dir):
|
||||
relative_dir = d[len(template_dir) + 1:]
|
||||
if relative_dir and not os.path.exists(os.path.join(copy_to, relative_dir)):
|
||||
os.mkdir(os.path.join(copy_to, relative_dir))
|
||||
for i, subdir in enumerate(subdirs):
|
||||
if subdir.startswith('.'):
|
||||
del subdirs[i]
|
||||
for f in files:
|
||||
if f.endswith('.pyc') or f.startswith('.DS_Store'):
|
||||
continue
|
||||
path_old = os.path.join(d, f)
|
||||
path_new = os.path.join(copy_to, relative_dir, f)
|
||||
if os.path.exists(path_new):
|
||||
path_new = os.path.join(copy_to, relative_dir, f)
|
||||
if os.path.exists(path_new):
|
||||
continue
|
||||
path_new = path_new.rstrip(".tmpl")
|
||||
fp_old = open(path_old, 'r')
|
||||
fp_new = open(path_new, 'w')
|
||||
fp_new.write(fp_old.read())
|
||||
fp_old.close()
|
||||
fp_new.close()
|
||||
try:
|
||||
shutil.copymode(path_old, path_new)
|
||||
_make_writeable(path_new)
|
||||
except OSError:
|
||||
sys.stderr.write("Notice: Couldn't set permission bits on %s. You're probably using an uncommon filesystem setup. No problem.\n" % path_new)
|
|
@ -0,0 +1,66 @@
|
|||
from django.core.management.base import LabelCommand, CommandError
|
||||
from django.utils.encoding import force_unicode
|
||||
|
||||
|
||||
class Command(LabelCommand):
|
||||
help = "Outputs the specified model as a form definition to the shell."
|
||||
args = "[app.model]"
|
||||
label = 'application name and model name'
|
||||
|
||||
requires_model_validation = True
|
||||
can_import_settings = True
|
||||
|
||||
def handle_label(self, label, **options):
|
||||
return describe_form(label)
|
||||
|
||||
|
||||
def describe_form(label, fields=None):
|
||||
"""
|
||||
Returns a string describing a form based on the model
|
||||
"""
|
||||
from django.db.models.loading import get_model
|
||||
try:
|
||||
app_name, model_name = label.split('.')[-2:]
|
||||
except (IndexError, ValueError):
|
||||
raise CommandError("Need application and model name in the form: appname.model")
|
||||
model = get_model(app_name, model_name)
|
||||
|
||||
opts = model._meta
|
||||
field_list = []
|
||||
for f in opts.fields + opts.many_to_many:
|
||||
if not f.editable:
|
||||
continue
|
||||
if fields and not f.name in fields:
|
||||
continue
|
||||
formfield = f.formfield()
|
||||
if not '__dict__' in dir(formfield):
|
||||
continue
|
||||
attrs = {}
|
||||
valid_fields = ['required', 'initial', 'max_length', 'min_length', 'max_value', 'min_value', 'max_digits', 'decimal_places', 'choices', 'help_text', 'label']
|
||||
for k, v in formfield.__dict__.items():
|
||||
if k in valid_fields and v is not None:
|
||||
# ignore defaults, to minimize verbosity
|
||||
if k == 'required' and v:
|
||||
continue
|
||||
if k == 'help_text' and not v:
|
||||
continue
|
||||
if k == 'widget':
|
||||
attrs[k] = v.__class__
|
||||
elif k in ['help_text', 'label']:
|
||||
attrs[k] = force_unicode(v).strip()
|
||||
else:
|
||||
attrs[k] = v
|
||||
|
||||
params = ', '.join(['%s=%r' % (k, v) for k, v in attrs.items()])
|
||||
field_list.append(' %(field_name)s = forms.%(field_type)s(%(params)s)' % {
|
||||
'field_name': f.name,
|
||||
'field_type': formfield.__class__.__name__,
|
||||
'params': params
|
||||
})
|
||||
return '''
|
||||
from django import forms
|
||||
from %(app_name)s.models import %(object_name)s
|
||||
|
||||
class %(object_name)sForm(forms.Form):
|
||||
%(field_list)s
|
||||
''' % {'app_name': app_name, 'object_name': opts.object_name, 'field_list': '\n'.join(field_list)}
|
|
@ -0,0 +1,751 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: UTF-8 -*-
|
||||
"""
|
||||
Title: Dumpscript management command
|
||||
Project: Hardytools (queryset-refactor version)
|
||||
Author: Will Hardy (http://willhardy.com.au)
|
||||
Date: June 2008
|
||||
Usage: python manage.py dumpscript appname > scripts/scriptname.py
|
||||
$Revision: 217 $
|
||||
|
||||
Description:
|
||||
Generates a Python script that will repopulate the database using objects.
|
||||
The advantage of this approach is that it is easy to understand, and more
|
||||
flexible than directly populating the database, or using XML.
|
||||
|
||||
* It also allows for new defaults to take effect and only transfers what is
|
||||
needed.
|
||||
* If a new database schema has a NEW ATTRIBUTE, it is simply not
|
||||
populated (using a default value will make the transition smooth :)
|
||||
* If a new database schema REMOVES AN ATTRIBUTE, it is simply ignored
|
||||
and the data moves across safely (I'm assuming we don't want this
|
||||
attribute anymore.
|
||||
* Problems may only occur if there is a new model and is now a required
|
||||
ForeignKey for an existing model. But this is easy to fix by editing the
|
||||
populate script. Half of the job is already done as all ForeingKey
|
||||
lookups occur though the locate_object() function in the generated script.
|
||||
|
||||
Improvements:
|
||||
See TODOs and FIXMEs scattered throughout :-)
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import datetime
|
||||
import six
|
||||
|
||||
import django
|
||||
from django.db.models import AutoField, BooleanField, FileField, ForeignKey
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.core.management.base import BaseCommand
|
||||
|
||||
# conditional import, force_unicode was renamed in Django 1.5
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
try:
|
||||
from django.utils.encoding import smart_unicode, force_unicode # NOQA
|
||||
except ImportError:
|
||||
from django.utils.encoding import smart_text as smart_unicode, force_text as force_unicode # NOQA
|
||||
|
||||
|
||||
def orm_item_locator(orm_obj):
|
||||
"""
|
||||
This function is called every time an object that will not be exported is required.
|
||||
Where orm_obj is the referred object.
|
||||
We postpone the lookup to locate_object() which will be run on the generated script
|
||||
|
||||
"""
|
||||
|
||||
the_class = orm_obj._meta.object_name
|
||||
original_class = the_class
|
||||
pk_name = orm_obj._meta.pk.name
|
||||
original_pk_name = pk_name
|
||||
pk_value = getattr(orm_obj, pk_name)
|
||||
|
||||
while hasattr(pk_value, "_meta") and hasattr(pk_value._meta, "pk") and hasattr(pk_value._meta.pk, "name"):
|
||||
the_class = pk_value._meta.object_name
|
||||
pk_name = pk_value._meta.pk.name
|
||||
pk_value = getattr(pk_value, pk_name)
|
||||
|
||||
clean_dict = make_clean_dict(orm_obj.__dict__)
|
||||
|
||||
for key in clean_dict:
|
||||
v = clean_dict[key]
|
||||
if v is not None and not isinstance(v, (six.string_types, six.integer_types, float, datetime.datetime)):
|
||||
clean_dict[key] = six.u("%s" % v)
|
||||
|
||||
output = """ importer.locate_object(%s, "%s", %s, "%s", %s, %s ) """ % (
|
||||
original_class, original_pk_name,
|
||||
the_class, pk_name, pk_value, clean_dict
|
||||
)
|
||||
return output
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Dumps the data as a customised python script.'
|
||||
args = '[appname ...]'
|
||||
|
||||
def handle(self, *app_labels, **options):
|
||||
|
||||
# Get the models we want to export
|
||||
models = get_models(app_labels)
|
||||
|
||||
# A dictionary is created to keep track of all the processed objects,
|
||||
# so that foreign key references can be made using python variable names.
|
||||
# This variable "context" will be passed around like the town bicycle.
|
||||
context = {}
|
||||
|
||||
# Create a dumpscript object and let it format itself as a string
|
||||
self.stdout.write(str(Script(models=models, context=context, stdout=self.stdout, stderr=self.stderr)))
|
||||
self.stdout.write("\n")
|
||||
|
||||
|
||||
def get_models(app_labels):
|
||||
""" Gets a list of models for the given app labels, with some exceptions.
|
||||
TODO: If a required model is referenced, it should also be included.
|
||||
Or at least discovered with a get_or_create() call.
|
||||
"""
|
||||
|
||||
from django.db.models import get_app, get_apps, get_model
|
||||
from django.db.models import get_models as get_all_models
|
||||
|
||||
# These models are not to be output, e.g. because they can be generated automatically
|
||||
# TODO: This should be "appname.modelname" string
|
||||
EXCLUDED_MODELS = (ContentType, )
|
||||
|
||||
models = []
|
||||
|
||||
# If no app labels are given, return all
|
||||
if not app_labels:
|
||||
for app in get_apps():
|
||||
models += [m for m in get_all_models(app) if m not in EXCLUDED_MODELS]
|
||||
|
||||
# Get all relevant apps
|
||||
for app_label in app_labels:
|
||||
# If a specific model is mentioned, get only that model
|
||||
if "." in app_label:
|
||||
app_label, model_name = app_label.split(".", 1)
|
||||
models.append(get_model(app_label, model_name))
|
||||
# Get all models for a given app
|
||||
else:
|
||||
models += [m for m in get_all_models(get_app(app_label)) if m not in EXCLUDED_MODELS]
|
||||
|
||||
return models
|
||||
|
||||
|
||||
class Code(object):
|
||||
""" A snippet of python script.
|
||||
This keeps track of import statements and can be output to a string.
|
||||
In the future, other features such as custom indentation might be included
|
||||
in this class.
|
||||
"""
|
||||
|
||||
def __init__(self, indent=-1, stdout=None, stderr=None):
|
||||
|
||||
if not stdout:
|
||||
stdout = sys.stdout
|
||||
if not stderr:
|
||||
stderr = sys.stderr
|
||||
|
||||
self.indent = indent
|
||||
self.stdout = stdout
|
||||
self.stderr = stderr
|
||||
|
||||
def __str__(self):
|
||||
""" Returns a string representation of this script.
|
||||
"""
|
||||
if self.imports:
|
||||
self.stderr.write(repr(self.import_lines))
|
||||
return flatten_blocks([""] + self.import_lines + [""] + self.lines, num_indents=self.indent)
|
||||
else:
|
||||
return flatten_blocks(self.lines, num_indents=self.indent)
|
||||
|
||||
def get_import_lines(self):
|
||||
""" Takes the stored imports and converts them to lines
|
||||
"""
|
||||
if self.imports:
|
||||
return ["from %s import %s" % (value, key) for key, value in self.imports.items()]
|
||||
else:
|
||||
return []
|
||||
import_lines = property(get_import_lines)
|
||||
|
||||
|
||||
class ModelCode(Code):
|
||||
" Produces a python script that can recreate data for a given model class. "
|
||||
|
||||
def __init__(self, model, context=None, stdout=None, stderr=None):
|
||||
super(ModelCode, self).__init__(indent=0, stdout=stdout, stderr=stderr)
|
||||
self.model = model
|
||||
if context is None:
|
||||
context = {}
|
||||
self.context = context
|
||||
self.instances = []
|
||||
|
||||
def get_imports(self):
|
||||
""" Returns a dictionary of import statements, with the variable being
|
||||
defined as the key.
|
||||
"""
|
||||
return {self.model.__name__: smart_unicode(self.model.__module__)}
|
||||
imports = property(get_imports)
|
||||
|
||||
def get_lines(self):
|
||||
""" Returns a list of lists or strings, representing the code body.
|
||||
Each list is a block, each string is a statement.
|
||||
"""
|
||||
code = []
|
||||
|
||||
for counter, item in enumerate(self.model._default_manager.all()):
|
||||
instance = InstanceCode(instance=item, id=counter + 1, context=self.context, stdout=self.stdout, stderr=self.stderr)
|
||||
self.instances.append(instance)
|
||||
if instance.waiting_list:
|
||||
code += instance.lines
|
||||
|
||||
# After each instance has been processed, try again.
|
||||
# This allows self referencing fields to work.
|
||||
for instance in self.instances:
|
||||
if instance.waiting_list:
|
||||
code += instance.lines
|
||||
|
||||
return code
|
||||
|
||||
lines = property(get_lines)
|
||||
|
||||
|
||||
class InstanceCode(Code):
|
||||
" Produces a python script that can recreate data for a given model instance. "
|
||||
|
||||
def __init__(self, instance, id, context=None, stdout=None, stderr=None):
|
||||
""" We need the instance in question and an id """
|
||||
|
||||
super(InstanceCode, self).__init__(indent=0, stdout=stdout, stderr=stderr)
|
||||
self.imports = {}
|
||||
|
||||
self.instance = instance
|
||||
self.model = self.instance.__class__
|
||||
if context is None:
|
||||
context = {}
|
||||
self.context = context
|
||||
self.variable_name = "%s_%s" % (self.instance._meta.db_table, id)
|
||||
self.skip_me = None
|
||||
self.instantiated = False
|
||||
|
||||
self.waiting_list = list(self.model._meta.fields)
|
||||
|
||||
self.many_to_many_waiting_list = {}
|
||||
for field in self.model._meta.many_to_many:
|
||||
self.many_to_many_waiting_list[field] = list(getattr(self.instance, field.name).all())
|
||||
|
||||
def get_lines(self, force=False):
|
||||
""" Returns a list of lists or strings, representing the code body.
|
||||
Each list is a block, each string is a statement.
|
||||
|
||||
force (True or False): if an attribute object cannot be included,
|
||||
it is usually skipped to be processed later. With 'force' set, there
|
||||
will be no waiting: a get_or_create() call is written instead.
|
||||
"""
|
||||
code_lines = []
|
||||
|
||||
# Don't return anything if this is an instance that should be skipped
|
||||
if self.skip():
|
||||
return []
|
||||
|
||||
# Initialise our new object
|
||||
# e.g. model_name_35 = Model()
|
||||
code_lines += self.instantiate()
|
||||
|
||||
# Add each field
|
||||
# e.g. model_name_35.field_one = 1034.91
|
||||
# model_name_35.field_two = "text"
|
||||
code_lines += self.get_waiting_list()
|
||||
|
||||
if force:
|
||||
# TODO: Check that M2M are not affected
|
||||
code_lines += self.get_waiting_list(force=force)
|
||||
|
||||
# Print the save command for our new object
|
||||
# e.g. model_name_35.save()
|
||||
if code_lines:
|
||||
code_lines.append("%s = importer.save_or_locate(%s)\n" % (self.variable_name, self.variable_name))
|
||||
|
||||
code_lines += self.get_many_to_many_lines(force=force)
|
||||
|
||||
return code_lines
|
||||
lines = property(get_lines)
|
||||
|
||||
def skip(self):
|
||||
""" Determine whether or not this object should be skipped.
|
||||
If this model instance is a parent of a single subclassed
|
||||
instance, skip it. The subclassed instance will create this
|
||||
parent instance for us.
|
||||
|
||||
TODO: Allow the user to force its creation?
|
||||
"""
|
||||
|
||||
if self.skip_me is not None:
|
||||
return self.skip_me
|
||||
|
||||
def get_skip_version():
|
||||
""" Return which version of the skip code should be run
|
||||
|
||||
Django's deletion code was refactored in r14507 which
|
||||
was just two days before 1.3 alpha 1 (r14519)
|
||||
"""
|
||||
if not hasattr(self, '_SKIP_VERSION'):
|
||||
version = django.VERSION
|
||||
# no, it isn't lisp. I swear.
|
||||
self._SKIP_VERSION = (
|
||||
version[0] > 1 or ( # django 2k... someday :)
|
||||
version[0] == 1 and ( # 1.x
|
||||
version[1] >= 4 or # 1.4+
|
||||
version[1] == 3 and not ( # 1.3.x
|
||||
(version[3] == 'alpha' and version[1] == 0)
|
||||
)
|
||||
)
|
||||
)
|
||||
) and 2 or 1 # NOQA
|
||||
return self._SKIP_VERSION
|
||||
|
||||
if get_skip_version() == 1:
|
||||
try:
|
||||
# Django trunk since r7722 uses CollectedObjects instead of dict
|
||||
from django.db.models.query import CollectedObjects
|
||||
sub_objects = CollectedObjects()
|
||||
except ImportError:
|
||||
# previous versions don't have CollectedObjects
|
||||
sub_objects = {}
|
||||
self.instance._collect_sub_objects(sub_objects)
|
||||
sub_objects = sub_objects.keys()
|
||||
|
||||
elif get_skip_version() == 2:
|
||||
from django.db.models.deletion import Collector
|
||||
from django.db import router
|
||||
cls = self.instance.__class__
|
||||
using = router.db_for_write(cls, instance=self.instance)
|
||||
collector = Collector(using=using)
|
||||
collector.collect([self.instance], collect_related=False)
|
||||
|
||||
# collector stores its instances in two places. I *think* we
|
||||
# only need collector.data, but using the batches is needed
|
||||
# to perfectly emulate the old behaviour
|
||||
# TODO: check if batches are really needed. If not, remove them.
|
||||
sub_objects = sum([list(i) for i in collector.data.values()], [])
|
||||
|
||||
for batch in collector.batches.values():
|
||||
# batch.values can be sets, which must be converted to lists
|
||||
sub_objects += sum([list(i) for i in batch.values()], [])
|
||||
|
||||
sub_objects_parents = [so._meta.parents for so in sub_objects]
|
||||
if [self.model in p for p in sub_objects_parents].count(True) == 1:
|
||||
# since this instance isn't explicitly created, it's variable name
|
||||
# can't be referenced in the script, so record None in context dict
|
||||
pk_name = self.instance._meta.pk.name
|
||||
key = '%s_%s' % (self.model.__name__, getattr(self.instance, pk_name))
|
||||
self.context[key] = None
|
||||
self.skip_me = True
|
||||
else:
|
||||
self.skip_me = False
|
||||
|
||||
return self.skip_me
|
||||
|
||||
def instantiate(self):
|
||||
" Write lines for instantiation "
|
||||
# e.g. model_name_35 = Model()
|
||||
code_lines = []
|
||||
|
||||
if not self.instantiated:
|
||||
code_lines.append("%s = %s()" % (self.variable_name, self.model.__name__))
|
||||
self.instantiated = True
|
||||
|
||||
# Store our variable name for future foreign key references
|
||||
pk_name = self.instance._meta.pk.name
|
||||
key = '%s_%s' % (self.model.__name__, getattr(self.instance, pk_name))
|
||||
self.context[key] = self.variable_name
|
||||
|
||||
return code_lines
|
||||
|
||||
def get_waiting_list(self, force=False):
|
||||
" Add lines for any waiting fields that can be completed now. "
|
||||
|
||||
code_lines = []
|
||||
|
||||
# Process normal fields
|
||||
for field in list(self.waiting_list):
|
||||
try:
|
||||
# Find the value, add the line, remove from waiting list and move on
|
||||
value = get_attribute_value(self.instance, field, self.context, force=force)
|
||||
code_lines.append('%s.%s = %s' % (self.variable_name, field.name, value))
|
||||
self.waiting_list.remove(field)
|
||||
except SkipValue:
|
||||
# Remove from the waiting list and move on
|
||||
self.waiting_list.remove(field)
|
||||
continue
|
||||
except DoLater:
|
||||
# Move on, maybe next time
|
||||
continue
|
||||
|
||||
return code_lines
|
||||
|
||||
def get_many_to_many_lines(self, force=False):
|
||||
""" Generates lines that define many to many relations for this instance. """
|
||||
|
||||
lines = []
|
||||
|
||||
for field, rel_items in self.many_to_many_waiting_list.items():
|
||||
for rel_item in list(rel_items):
|
||||
try:
|
||||
pk_name = rel_item._meta.pk.name
|
||||
key = '%s_%s' % (rel_item.__class__.__name__, getattr(rel_item, pk_name))
|
||||
value = "%s" % self.context[key]
|
||||
lines.append('%s.%s.add(%s)' % (self.variable_name, field.name, value))
|
||||
self.many_to_many_waiting_list[field].remove(rel_item)
|
||||
except KeyError:
|
||||
if force:
|
||||
item_locator = orm_item_locator(rel_item)
|
||||
self.context["__extra_imports"][rel_item._meta.object_name] = rel_item.__module__
|
||||
lines.append('%s.%s.add( %s )' % (self.variable_name, field.name, item_locator))
|
||||
self.many_to_many_waiting_list[field].remove(rel_item)
|
||||
|
||||
if lines:
|
||||
lines.append("")
|
||||
|
||||
return lines
|
||||
|
||||
|
||||
class Script(Code):
|
||||
" Produces a complete python script that can recreate data for the given apps. "
|
||||
|
||||
def __init__(self, models, context=None, stdout=None, stderr=None):
|
||||
super(Script, self).__init__(stdout=stdout, stderr=stderr)
|
||||
self.imports = {}
|
||||
|
||||
self.models = models
|
||||
if context is None:
|
||||
context = {}
|
||||
self.context = context
|
||||
|
||||
self.context["__avaliable_models"] = set(models)
|
||||
self.context["__extra_imports"] = {}
|
||||
|
||||
def _queue_models(self, models, context):
|
||||
""" Works an an appropriate ordering for the models.
|
||||
This isn't essential, but makes the script look nicer because
|
||||
more instances can be defined on their first try.
|
||||
"""
|
||||
|
||||
# Max number of cycles allowed before we call it an infinite loop.
|
||||
MAX_CYCLES = 5
|
||||
|
||||
model_queue = []
|
||||
number_remaining_models = len(models)
|
||||
allowed_cycles = MAX_CYCLES
|
||||
|
||||
while number_remaining_models > 0:
|
||||
previous_number_remaining_models = number_remaining_models
|
||||
|
||||
model = models.pop(0)
|
||||
|
||||
# If the model is ready to be processed, add it to the list
|
||||
if check_dependencies(model, model_queue, context["__avaliable_models"]):
|
||||
model_class = ModelCode(model=model, context=context, stdout=self.stdout, stderr=self.stderr)
|
||||
model_queue.append(model_class)
|
||||
|
||||
# Otherwise put the model back at the end of the list
|
||||
else:
|
||||
models.append(model)
|
||||
|
||||
# Check for infinite loops.
|
||||
# This means there is a cyclic foreign key structure
|
||||
# That cannot be resolved by re-ordering
|
||||
number_remaining_models = len(models)
|
||||
if number_remaining_models == previous_number_remaining_models:
|
||||
allowed_cycles -= 1
|
||||
if allowed_cycles <= 0:
|
||||
# Add the remaining models, but do not remove them from the model list
|
||||
missing_models = [ModelCode(model=m, context=context, stdout=self.stdout, stderr=self.stderr) for m in models]
|
||||
model_queue += missing_models
|
||||
# Replace the models with the model class objects
|
||||
# (sure, this is a little bit of hackery)
|
||||
models[:] = missing_models
|
||||
break
|
||||
else:
|
||||
allowed_cycles = MAX_CYCLES
|
||||
|
||||
return model_queue
|
||||
|
||||
def get_lines(self):
|
||||
""" Returns a list of lists or strings, representing the code body.
|
||||
Each list is a block, each string is a statement.
|
||||
"""
|
||||
code = [self.FILE_HEADER.strip()]
|
||||
|
||||
# Queue and process the required models
|
||||
for model_class in self._queue_models(self.models, context=self.context):
|
||||
msg = 'Processing model: %s\n' % model_class.model.__name__
|
||||
self.stderr.write(msg)
|
||||
code.append(" #" + msg)
|
||||
code.append(model_class.import_lines)
|
||||
code.append("")
|
||||
code.append(model_class.lines)
|
||||
|
||||
# Process left over foreign keys from cyclic models
|
||||
for model in self.models:
|
||||
msg = 'Re-processing model: %s\n' % model.model.__name__
|
||||
self.stderr.write(msg)
|
||||
code.append(" #" + msg)
|
||||
for instance in model.instances:
|
||||
if instance.waiting_list or instance.many_to_many_waiting_list:
|
||||
code.append(instance.get_lines(force=True))
|
||||
|
||||
code.insert(1, " #initial imports")
|
||||
code.insert(2, "")
|
||||
for key, value in self.context["__extra_imports"].items():
|
||||
code.insert(2, " from %s import %s" % (value, key))
|
||||
|
||||
return code
|
||||
|
||||
lines = property(get_lines)
|
||||
|
||||
# A user-friendly file header
|
||||
FILE_HEADER = """
|
||||
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# This file has been automatically generated.
|
||||
# Instead of changing it, create a file called import_helper.py
|
||||
# and put there a class called ImportHelper(object) in it.
|
||||
#
|
||||
# This class will be specially casted so that instead of extending object,
|
||||
# it will actually extend the class BasicImportHelper()
|
||||
#
|
||||
# That means you just have to overload the methods you want to
|
||||
# change, leaving the other ones inteact.
|
||||
#
|
||||
# Something that you might want to do is use transactions, for example.
|
||||
#
|
||||
# Also, don't forget to add the necessary Django imports.
|
||||
#
|
||||
# This file was generated with the following command:
|
||||
# %s
|
||||
#
|
||||
# to restore it, run
|
||||
# manage.py runscript module_name.this_script_name
|
||||
#
|
||||
# example: if manage.py is at ./manage.py
|
||||
# and the script is at ./some_folder/some_script.py
|
||||
# you must make sure ./some_folder/__init__.py exists
|
||||
# and run ./manage.py runscript some_folder.some_script
|
||||
|
||||
from django.db import transaction
|
||||
|
||||
class BasicImportHelper(object):
|
||||
|
||||
def pre_import(self):
|
||||
pass
|
||||
|
||||
# You probably want to uncomment on of these two lines
|
||||
# @transaction.atomic # Django 1.6
|
||||
# @transaction.commit_on_success # Django <1.6
|
||||
def run_import(self, import_data):
|
||||
import_data()
|
||||
|
||||
def post_import(self):
|
||||
pass
|
||||
|
||||
def locate_similar(self, current_object, search_data):
|
||||
#you will probably want to call this method from save_or_locate()
|
||||
#example:
|
||||
#new_obj = self.locate_similar(the_obj, {"national_id": the_obj.national_id } )
|
||||
|
||||
the_obj = current_object.__class__.objects.get(**search_data)
|
||||
return the_obj
|
||||
|
||||
def locate_object(self, original_class, original_pk_name, the_class, pk_name, pk_value, obj_content):
|
||||
#You may change this function to do specific lookup for specific objects
|
||||
#
|
||||
#original_class class of the django orm's object that needs to be located
|
||||
#original_pk_name the primary key of original_class
|
||||
#the_class parent class of original_class which contains obj_content
|
||||
#pk_name the primary key of original_class
|
||||
#pk_value value of the primary_key
|
||||
#obj_content content of the object which was not exported.
|
||||
#
|
||||
#you should use obj_content to locate the object on the target db
|
||||
#
|
||||
#and example where original_class and the_class are different is
|
||||
#when original_class is Farmer and
|
||||
#the_class is Person. The table may refer to a Farmer but you will actually
|
||||
#need to locate Person in order to instantiate that Farmer
|
||||
#
|
||||
#example:
|
||||
#if the_class == SurveyResultFormat or the_class == SurveyType or the_class == SurveyState:
|
||||
# pk_name="name"
|
||||
# pk_value=obj_content[pk_name]
|
||||
#if the_class == StaffGroup:
|
||||
# pk_value=8
|
||||
|
||||
search_data = { pk_name: pk_value }
|
||||
the_obj = the_class.objects.get(**search_data)
|
||||
#print(the_obj)
|
||||
return the_obj
|
||||
|
||||
|
||||
def save_or_locate(self, the_obj):
|
||||
#change this if you want to locate the object in the database
|
||||
try:
|
||||
the_obj.save()
|
||||
except:
|
||||
print("---------------")
|
||||
print("Error saving the following object:")
|
||||
print(the_obj.__class__)
|
||||
print(" ")
|
||||
print(the_obj.__dict__)
|
||||
print(" ")
|
||||
print(the_obj)
|
||||
print(" ")
|
||||
print("---------------")
|
||||
|
||||
raise
|
||||
return the_obj
|
||||
|
||||
|
||||
importer = None
|
||||
try:
|
||||
import import_helper
|
||||
#we need this so ImportHelper can extend BasicImportHelper, although import_helper.py
|
||||
#has no knowlodge of this class
|
||||
importer = type("DynamicImportHelper", (import_helper.ImportHelper, BasicImportHelper ) , {} )()
|
||||
except ImportError as e:
|
||||
if str(e) == "No module named import_helper":
|
||||
importer = BasicImportHelper()
|
||||
else:
|
||||
raise
|
||||
|
||||
import datetime
|
||||
from decimal import Decimal
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
|
||||
def run():
|
||||
importer.pre_import()
|
||||
importer.run_import(import_data)
|
||||
importer.post_import()
|
||||
|
||||
def import_data():
|
||||
|
||||
""" % " ".join(sys.argv)
|
||||
|
||||
|
||||
# HELPER FUNCTIONS
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
def flatten_blocks(lines, num_indents=-1):
|
||||
""" Takes a list (block) or string (statement) and flattens it into a string
|
||||
with indentation.
|
||||
"""
|
||||
|
||||
# The standard indent is four spaces
|
||||
INDENTATION = " " * 4
|
||||
|
||||
if not lines:
|
||||
return ""
|
||||
|
||||
# If this is a string, add the indentation and finish here
|
||||
if isinstance(lines, six.string_types):
|
||||
return INDENTATION * num_indents + lines
|
||||
|
||||
# If this is not a string, join the lines and recurse
|
||||
return "\n".join([flatten_blocks(line, num_indents + 1) for line in lines])
|
||||
|
||||
|
||||
def get_attribute_value(item, field, context, force=False):
|
||||
""" Gets a string version of the given attribute's value, like repr() might. """
|
||||
|
||||
# Find the value of the field, catching any database issues
|
||||
try:
|
||||
value = getattr(item, field.name)
|
||||
except ObjectDoesNotExist:
|
||||
raise SkipValue('Could not find object for %s.%s, ignoring.\n' % (item.__class__.__name__, field.name))
|
||||
|
||||
# AutoField: We don't include the auto fields, they'll be automatically recreated
|
||||
if isinstance(field, AutoField):
|
||||
raise SkipValue()
|
||||
|
||||
# Some databases (eg MySQL) might store boolean values as 0/1, this needs to be cast as a bool
|
||||
elif isinstance(field, BooleanField) and value is not None:
|
||||
return repr(bool(value))
|
||||
|
||||
# Post file-storage-refactor, repr() on File/ImageFields no longer returns the path
|
||||
elif isinstance(field, FileField):
|
||||
return repr(force_unicode(value))
|
||||
|
||||
# ForeignKey fields, link directly using our stored python variable name
|
||||
elif isinstance(field, ForeignKey) and value is not None:
|
||||
|
||||
# Special case for contenttype foreign keys: no need to output any
|
||||
# content types in this script, as they can be generated again
|
||||
# automatically.
|
||||
# NB: Not sure if "is" will always work
|
||||
if field.rel.to is ContentType:
|
||||
return 'ContentType.objects.get(app_label="%s", model="%s")' % (value.app_label, value.model)
|
||||
|
||||
# Generate an identifier (key) for this foreign object
|
||||
pk_name = value._meta.pk.name
|
||||
key = '%s_%s' % (value.__class__.__name__, getattr(value, pk_name))
|
||||
|
||||
if key in context:
|
||||
variable_name = context[key]
|
||||
# If the context value is set to None, this should be skipped.
|
||||
# This identifies models that have been skipped (inheritance)
|
||||
if variable_name is None:
|
||||
raise SkipValue()
|
||||
# Return the variable name listed in the context
|
||||
return "%s" % variable_name
|
||||
elif value.__class__ not in context["__avaliable_models"] or force:
|
||||
context["__extra_imports"][value._meta.object_name] = value.__module__
|
||||
item_locator = orm_item_locator(value)
|
||||
return item_locator
|
||||
else:
|
||||
raise DoLater('(FK) %s.%s\n' % (item.__class__.__name__, field.name))
|
||||
|
||||
# A normal field (e.g. a python built-in)
|
||||
else:
|
||||
return repr(value)
|
||||
|
||||
|
||||
def make_clean_dict(the_dict):
|
||||
if "_state" in the_dict:
|
||||
clean_dict = the_dict.copy()
|
||||
del clean_dict["_state"]
|
||||
return clean_dict
|
||||
return the_dict
|
||||
|
||||
|
||||
def check_dependencies(model, model_queue, avaliable_models):
|
||||
" Check that all the depenedencies for this model are already in the queue. "
|
||||
|
||||
# A list of allowed links: existing fields, itself and the special case ContentType
|
||||
allowed_links = [m.model.__name__ for m in model_queue] + [model.__name__, 'ContentType']
|
||||
|
||||
# For each ForeignKey or ManyToMany field, check that a link is possible
|
||||
|
||||
for field in model._meta.fields:
|
||||
if field.rel and field.rel.to.__name__ not in allowed_links:
|
||||
if field.rel.to not in avaliable_models:
|
||||
continue
|
||||
return False
|
||||
|
||||
for field in model._meta.many_to_many:
|
||||
if field.rel and field.rel.to.__name__ not in allowed_links:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
# EXCEPTIONS
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
class SkipValue(Exception):
|
||||
""" Value could not be parsed or should simply be skipped. """
|
||||
|
||||
|
||||
class DoLater(Exception):
|
||||
""" Value could not be parsed or should simply be skipped. """
|
|
@ -0,0 +1,133 @@
|
|||
from django.core.management.base import BaseCommand, CommandError
|
||||
try:
|
||||
from django.contrib.auth import get_user_model # Django 1.5
|
||||
except ImportError:
|
||||
from django_extensions.future_1_5 import get_user_model
|
||||
from django.contrib.auth.models import Group
|
||||
from optparse import make_option
|
||||
from sys import stdout
|
||||
from csv import writer
|
||||
import six
|
||||
|
||||
FORMATS = [
|
||||
'address',
|
||||
'emails',
|
||||
'google',
|
||||
'outlook',
|
||||
'linkedin',
|
||||
'vcard',
|
||||
]
|
||||
|
||||
|
||||
def full_name(first_name, last_name, username, **extra):
|
||||
name = six.u(" ").join(n for n in [first_name, last_name] if n)
|
||||
if not name:
|
||||
return username
|
||||
return name
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
option_list = BaseCommand.option_list + (
|
||||
make_option('--group', '-g', action='store', dest='group', default=None,
|
||||
help='Limit to users which are part of the supplied group name'),
|
||||
make_option('--format', '-f', action='store', dest='format', default=FORMATS[0],
|
||||
help="output format. May be one of '" + "', '".join(FORMATS) + "'."),
|
||||
)
|
||||
|
||||
help = ("Export user email address list in one of a number of formats.")
|
||||
args = "[output file]"
|
||||
label = 'filename to save to'
|
||||
|
||||
requires_model_validation = True
|
||||
can_import_settings = True
|
||||
encoding = 'utf-8' # RED_FLAG: add as an option -DougN
|
||||
|
||||
def handle(self, *args, **options):
|
||||
if len(args) > 1:
|
||||
raise CommandError("extra arguments supplied")
|
||||
group = options['group']
|
||||
if group and not Group.objects.filter(name=group).count() == 1:
|
||||
names = six.u("', '").join(g['name'] for g in Group.objects.values('name')).encode('utf-8')
|
||||
if names:
|
||||
names = "'" + names + "'."
|
||||
raise CommandError("Unknown group '" + group + "'. Valid group names are: " + names)
|
||||
if len(args) and args[0] != '-':
|
||||
outfile = open(args[0], 'w')
|
||||
else:
|
||||
outfile = stdout
|
||||
|
||||
User = get_user_model()
|
||||
qs = User.objects.all().order_by('last_name', 'first_name', 'username', 'email')
|
||||
if group:
|
||||
qs = qs.filter(group__name=group).distinct()
|
||||
qs = qs.values('last_name', 'first_name', 'username', 'email')
|
||||
getattr(self, options['format'])(qs, outfile)
|
||||
|
||||
def address(self, qs, out):
|
||||
"""simple single entry per line in the format of:
|
||||
"full name" <my@address.com>;
|
||||
"""
|
||||
out.write(six.u("\n").join(six.u('"%s" <%s>;' % (full_name(**ent), ent['email']))
|
||||
for ent in qs).encode(self.encoding))
|
||||
out.write("\n")
|
||||
|
||||
def emails(self, qs, out):
|
||||
"""simpler single entry with email only in the format of:
|
||||
my@address.com,
|
||||
"""
|
||||
out.write(six.u(",\n").join(six.u('%s' % (ent['email'])) for ent in qs).encode(self.encoding))
|
||||
out.write("\n")
|
||||
|
||||
def google(self, qs, out):
|
||||
"""CSV format suitable for importing into google GMail
|
||||
"""
|
||||
csvf = writer(out)
|
||||
csvf.writerow(['Name', 'Email'])
|
||||
for ent in qs:
|
||||
csvf.writerow([full_name(**ent).encode(self.encoding),
|
||||
ent['email'].encode(self.encoding)])
|
||||
|
||||
def outlook(self, qs, out):
|
||||
"""CSV format suitable for importing into outlook
|
||||
"""
|
||||
csvf = writer(out)
|
||||
columns = ['Name', 'E-mail Address', 'Notes', 'E-mail 2 Address', 'E-mail 3 Address',
|
||||
'Mobile Phone', 'Pager', 'Company', 'Job Title', 'Home Phone', 'Home Phone 2',
|
||||
'Home Fax', 'Home Address', 'Business Phone', 'Business Phone 2',
|
||||
'Business Fax', 'Business Address', 'Other Phone', 'Other Fax', 'Other Address']
|
||||
csvf.writerow(columns)
|
||||
empty = [''] * (len(columns) - 2)
|
||||
for ent in qs:
|
||||
csvf.writerow([full_name(**ent).encode(self.encoding),
|
||||
ent['email'].encode(self.encoding)] + empty)
|
||||
|
||||
def linkedin(self, qs, out):
|
||||
"""CSV format suitable for importing into linkedin Groups.
|
||||
perfect for pre-approving members of a linkedin group.
|
||||
"""
|
||||
csvf = writer(out)
|
||||
csvf.writerow(['First Name', 'Last Name', 'Email'])
|
||||
for ent in qs:
|
||||
csvf.writerow([ent['first_name'].encode(self.encoding),
|
||||
ent['last_name'].encode(self.encoding),
|
||||
ent['email'].encode(self.encoding)])
|
||||
|
||||
def vcard(self, qs, out):
|
||||
try:
|
||||
import vobject
|
||||
except ImportError:
|
||||
print(self.style.ERROR("Please install python-vobject to use the vcard export format."))
|
||||
import sys
|
||||
sys.exit(1)
|
||||
for ent in qs:
|
||||
card = vobject.vCard()
|
||||
card.add('fn').value = full_name(**ent)
|
||||
if not ent['last_name'] and not ent['first_name']:
|
||||
# fallback to fullname, if both first and lastname are not declared
|
||||
card.add('n').value = vobject.vcard.Name(full_name(**ent))
|
||||
else:
|
||||
card.add('n').value = vobject.vcard.Name(ent['last_name'], ent['first_name'])
|
||||
emailpart = card.add('email')
|
||||
emailpart.value = ent['email']
|
||||
emailpart.type_param = 'INTERNET'
|
||||
out.write(card.serialize().encode(self.encoding))
|
|
@ -0,0 +1,35 @@
|
|||
from django.core.management.base import LabelCommand
|
||||
from django.template import loader
|
||||
from django.template import TemplateDoesNotExist
|
||||
import sys
|
||||
|
||||
|
||||
def get_template_path(path):
|
||||
try:
|
||||
template = loader.find_template(path)
|
||||
if template[1]:
|
||||
return template[1].name
|
||||
# work arround https://code.djangoproject.com/ticket/17199 issue
|
||||
for template_loader in loader.template_source_loaders:
|
||||
try:
|
||||
source, origin = template_loader.load_template_source(path)
|
||||
return origin
|
||||
except TemplateDoesNotExist:
|
||||
pass
|
||||
raise TemplateDoesNotExist(path)
|
||||
except TemplateDoesNotExist:
|
||||
return None
|
||||
|
||||
|
||||
class Command(LabelCommand):
|
||||
help = "Finds the location of the given template by resolving its path"
|
||||
args = "[template_path]"
|
||||
label = 'template path'
|
||||
|
||||
def handle_label(self, template_path, **options):
|
||||
path = get_template_path(template_path)
|
||||
if path is None:
|
||||
sys.stderr.write("No template found\n")
|
||||
sys.exit(1)
|
||||
else:
|
||||
print(path)
|
|
@ -0,0 +1,11 @@
|
|||
from random import choice
|
||||
from django.core.management.base import NoArgsCommand
|
||||
|
||||
|
||||
class Command(NoArgsCommand):
|
||||
help = "Generates a new SECRET_KEY that can be used in a project settings file."
|
||||
|
||||
requires_model_validation = False
|
||||
|
||||
def handle_noargs(self, **options):
|
||||
return ''.join([choice('abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)') for i in range(50)])
|
|
@ -0,0 +1,143 @@
|
|||
import sys
|
||||
from optparse import make_option, NO_DEFAULT
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.conf import settings
|
||||
from django_extensions.management.modelviz import generate_dot
|
||||
|
||||
|
||||
try:
|
||||
import pygraphviz
|
||||
HAS_PYGRAPHVIZ = True
|
||||
except ImportError:
|
||||
HAS_PYGRAPHVIZ = False
|
||||
|
||||
try:
|
||||
import pydot
|
||||
HAS_PYDOT = True
|
||||
except ImportError:
|
||||
HAS_PYDOT = False
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
graph_models_options = (
|
||||
make_option('--pygraphviz', action='store_true', dest='pygraphviz',
|
||||
help='Use PyGraphViz to generate the image.'),
|
||||
make_option('--pydot', action='store_true', dest='pydot',
|
||||
help='Use PyDot to generate the image.'),
|
||||
make_option('--disable-fields', '-d', action='store_true', dest='disable_fields',
|
||||
help='Do not show the class member fields'),
|
||||
make_option('--group-models', '-g', action='store_true', dest='group_models',
|
||||
help='Group models together respective to their application'),
|
||||
make_option('--all-applications', '-a', action='store_true', dest='all_applications',
|
||||
help='Automatically include all applications from INSTALLED_APPS'),
|
||||
make_option('--output', '-o', action='store', dest='outputfile',
|
||||
help='Render output file. Type of output dependend on file extensions. Use png or jpg to render graph to image.'),
|
||||
make_option('--layout', '-l', action='store', dest='layout', default='dot',
|
||||
help='Layout to be used by GraphViz for visualization. Layouts: circo dot fdp neato nop nop1 nop2 twopi'),
|
||||
make_option('--verbose-names', '-n', action='store_true', dest='verbose_names',
|
||||
help='Use verbose_name of models and fields'),
|
||||
make_option('--language', '-L', action='store', dest='language',
|
||||
help='Specify language used for verbose_name localization'),
|
||||
make_option('--exclude-columns', '-x', action='store', dest='exclude_columns',
|
||||
help='Exclude specific column(s) from the graph. Can also load exclude list from file.'),
|
||||
make_option('--exclude-models', '-X', action='store', dest='exclude_models',
|
||||
help='Exclude specific model(s) from the graph. Can also load exclude list from file.'),
|
||||
make_option('--inheritance', '-e', action='store_true', dest='inheritance', default=True,
|
||||
help='Include inheritance arrows (default)'),
|
||||
make_option('--no-inheritance', '-E', action='store_false', dest='inheritance',
|
||||
help='Include inheritance arrows'),
|
||||
make_option('--hide-relations-from-fields', '-R', action='store_false', dest="relations_as_fields",
|
||||
default=True, help="Do not show relations as fields in the graph."),
|
||||
make_option('--disable-sort-fields', '-S', action="store_false", dest="sort_fields",
|
||||
default=True, help="Do not sort fields"),
|
||||
)
|
||||
option_list = BaseCommand.option_list + graph_models_options
|
||||
|
||||
help = "Creates a GraphViz dot file for the specified app names. You can pass multiple app names and they will all be combined into a single model. Output is usually directed to a dot file."
|
||||
args = "[appname]"
|
||||
label = 'application name'
|
||||
|
||||
requires_model_validation = True
|
||||
can_import_settings = True
|
||||
|
||||
def handle(self, *args, **options):
|
||||
self.options_from_settings(options)
|
||||
|
||||
if len(args) < 1 and not options['all_applications']:
|
||||
raise CommandError("need one or more arguments for appname")
|
||||
|
||||
use_pygraphviz = options.get('pygraphviz', False)
|
||||
use_pydot = options.get('pydot', False)
|
||||
cli_options = ' '.join(sys.argv[2:])
|
||||
dotdata = generate_dot(args, cli_options=cli_options, **options)
|
||||
dotdata = dotdata.encode('utf-8')
|
||||
if options['outputfile']:
|
||||
if not use_pygraphviz and not use_pydot:
|
||||
if HAS_PYGRAPHVIZ:
|
||||
use_pygraphviz = True
|
||||
elif HAS_PYDOT:
|
||||
use_pydot = True
|
||||
if use_pygraphviz:
|
||||
self.render_output_pygraphviz(dotdata, **options)
|
||||
elif use_pydot:
|
||||
self.render_output_pydot(dotdata, **options)
|
||||
else:
|
||||
raise CommandError("Neither pygraphviz nor pydot could be found to generate the image")
|
||||
else:
|
||||
self.print_output(dotdata)
|
||||
|
||||
def options_from_settings(self, options):
|
||||
defaults = getattr(settings, 'GRAPH_MODELS', None)
|
||||
if defaults:
|
||||
for option in self.graph_models_options:
|
||||
long_opt = option._long_opts[0]
|
||||
if long_opt:
|
||||
long_opt = long_opt.lstrip("-").replace("-", "_")
|
||||
if long_opt in defaults:
|
||||
default_value = None
|
||||
if not option.default == NO_DEFAULT:
|
||||
default_value = option.default
|
||||
if options[option.dest] == default_value:
|
||||
options[option.dest] = defaults[long_opt]
|
||||
|
||||
def print_output(self, dotdata):
|
||||
print(dotdata)
|
||||
|
||||
def render_output_pygraphviz(self, dotdata, **kwargs):
|
||||
"""Renders the image using pygraphviz"""
|
||||
if not HAS_PYGRAPHVIZ:
|
||||
raise CommandError("You need to install pygraphviz python module")
|
||||
|
||||
version = pygraphviz.__version__.rstrip("-svn")
|
||||
try:
|
||||
if tuple(int(v) for v in version.split('.')) < (0, 36):
|
||||
# HACK around old/broken AGraph before version 0.36 (ubuntu ships with this old version)
|
||||
import tempfile
|
||||
tmpfile = tempfile.NamedTemporaryFile()
|
||||
tmpfile.write(dotdata)
|
||||
tmpfile.seek(0)
|
||||
dotdata = tmpfile.name
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
graph = pygraphviz.AGraph(dotdata)
|
||||
graph.layout(prog=kwargs['layout'])
|
||||
graph.draw(kwargs['outputfile'])
|
||||
|
||||
def render_output_pydot(self, dotdata, **kwargs):
|
||||
"""Renders the image using pydot"""
|
||||
if not HAS_PYDOT:
|
||||
raise CommandError("You need to install pydot python module")
|
||||
|
||||
graph = pydot.graph_from_dot_data(dotdata)
|
||||
if not graph:
|
||||
raise CommandError("pydot returned an error")
|
||||
output_file = kwargs['outputfile']
|
||||
formats = ['bmp', 'canon', 'cmap', 'cmapx', 'cmapx_np', 'dot', 'dia', 'emf',
|
||||
'em', 'fplus', 'eps', 'fig', 'gd', 'gd2', 'gif', 'gv', 'imap',
|
||||
'imap_np', 'ismap', 'jpe', 'jpeg', 'jpg', 'metafile', 'pdf',
|
||||
'pic', 'plain', 'plain-ext', 'png', 'pov', 'ps', 'ps2', 'svg',
|
||||
'svgz', 'tif', 'tiff', 'tk', 'vml', 'vmlz', 'vrml', 'wbmp', 'xdot']
|
||||
ext = output_file[output_file.rfind('.') + 1:]
|
||||
format = ext if ext in formats else 'raw'
|
||||
graph.write(output_file, format=format)
|
|
@ -0,0 +1,80 @@
|
|||
from django_extensions.management.utils import setup_logger
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from optparse import make_option
|
||||
from smtpd import SMTPServer
|
||||
import sys
|
||||
import asyncore
|
||||
from logging import getLogger
|
||||
|
||||
|
||||
logger = getLogger(__name__)
|
||||
|
||||
|
||||
class ExtensionDebuggingServer(SMTPServer):
|
||||
"""Duplication of smtpd.DebuggingServer, but using logging instead of print."""
|
||||
# Do something with the gathered message
|
||||
def process_message(self, peer, mailfrom, rcpttos, data):
|
||||
"""Output will be sent to the module logger at INFO level."""
|
||||
inheaders = 1
|
||||
lines = data.split('\n')
|
||||
logger.info('---------- MESSAGE FOLLOWS ----------')
|
||||
for line in lines:
|
||||
# headers first
|
||||
if inheaders and not line:
|
||||
logger.info('X-Peer: %s' % peer[0])
|
||||
inheaders = 0
|
||||
logger.info(line)
|
||||
logger.info('------------ END MESSAGE ------------')
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
option_list = BaseCommand.option_list + (
|
||||
make_option('--output', dest='output_file', default=None,
|
||||
help='Specifies an output file to send a copy of all messages (not flushed immediately).'),
|
||||
make_option('--use-settings', dest='use_settings',
|
||||
action='store_true', default=False,
|
||||
help='Uses EMAIL_HOST and HOST_PORT from Django settings.'),
|
||||
)
|
||||
help = "Starts a test mail server for development."
|
||||
args = '[optional port number or ippaddr:port]'
|
||||
|
||||
requires_model_validation = False
|
||||
|
||||
def handle(self, addrport='', *args, **options):
|
||||
if args:
|
||||
raise CommandError('Usage is mail_debug %s' % self.args)
|
||||
if not addrport:
|
||||
if options.get('use_settings', False):
|
||||
from django.conf import settings
|
||||
addr = getattr(settings, 'EMAIL_HOST', '')
|
||||
port = str(getattr(settings, 'EMAIL_PORT', '1025'))
|
||||
else:
|
||||
addr = ''
|
||||
port = '1025'
|
||||
else:
|
||||
try:
|
||||
addr, port = addrport.split(':')
|
||||
except ValueError:
|
||||
addr, port = '', addrport
|
||||
if not addr:
|
||||
addr = '127.0.0.1'
|
||||
|
||||
if not port.isdigit():
|
||||
raise CommandError("%r is not a valid port number." % port)
|
||||
else:
|
||||
port = int(port)
|
||||
|
||||
# Add console handler
|
||||
setup_logger(logger, stream=self.stdout, filename=options.get('output_file', None))
|
||||
|
||||
def inner_run():
|
||||
quit_command = (sys.platform == 'win32') and 'CTRL-BREAK' or 'CONTROL-C'
|
||||
print("Now accepting mail at %s:%s -- use %s to quit" % (addr, port, quit_command))
|
||||
|
||||
ExtensionDebuggingServer((addr, port), None)
|
||||
asyncore.loop()
|
||||
|
||||
try:
|
||||
inner_run()
|
||||
except KeyboardInterrupt:
|
||||
pass
|
|
@ -0,0 +1,48 @@
|
|||
from __future__ import with_statement
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.conf import settings
|
||||
import os
|
||||
import re
|
||||
|
||||
ANNOTATION_RE = re.compile("\{?#[\s]*?(TODO|FIXME|BUG|HACK|WARNING|NOTE|XXX)[\s:]?(.+)")
|
||||
ANNOTATION_END_RE = re.compile("(.*)#\}(.*)")
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Show all annotations like TODO, FIXME, BUG, HACK, WARNING, NOTE or XXX in your py and HTML files.'
|
||||
args = 'tag'
|
||||
label = 'annotation tag (TODO, FIXME, BUG, HACK, WARNING, NOTE, XXX)'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
# don't add django internal code
|
||||
apps = filter(lambda app: not app.startswith('django.contrib'), settings.INSTALLED_APPS)
|
||||
template_dirs = getattr(settings, 'TEMPLATE_DIRS', [])
|
||||
if template_dirs:
|
||||
apps += template_dirs
|
||||
for app_dir in apps:
|
||||
app_dir = app_dir.replace(".", "/")
|
||||
for top, dirs, files in os.walk(app_dir):
|
||||
for f in files:
|
||||
if os.path.splitext(f)[1] in ('.py', '.html'):
|
||||
fpath = os.path.join(top, f)
|
||||
annotation_lines = []
|
||||
with open(fpath, 'r') as f:
|
||||
i = 0
|
||||
for line in f.readlines():
|
||||
i += 1
|
||||
if ANNOTATION_RE.search(line):
|
||||
tag, msg = ANNOTATION_RE.findall(line)[0]
|
||||
if len(args) == 1:
|
||||
search_for_tag = args[0].upper()
|
||||
if not search_for_tag == tag:
|
||||
break
|
||||
|
||||
if ANNOTATION_END_RE.search(msg.strip()):
|
||||
msg = ANNOTATION_END_RE.findall(msg.strip())[0][0]
|
||||
|
||||
annotation_lines.append("[%3s] %-5s %s" % (i, tag, msg.strip()))
|
||||
if annotation_lines:
|
||||
print("%s:" % fpath)
|
||||
for annotation in annotation_lines:
|
||||
print(" * %s" % annotation)
|
||||
print("")
|
|
@ -0,0 +1,42 @@
|
|||
from django.core.management.base import BaseCommand, CommandError
|
||||
try:
|
||||
from django.contrib.auth import get_user_model # Django 1.5
|
||||
except ImportError:
|
||||
from django_extensions.future_1_5 import get_user_model
|
||||
import getpass
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Clone of the UNIX program ``passwd'', for django.contrib.auth."
|
||||
|
||||
requires_model_validation = False
|
||||
|
||||
def handle(self, *args, **options):
|
||||
if len(args) > 1:
|
||||
raise CommandError("need exactly one or zero arguments for username")
|
||||
|
||||
if args:
|
||||
username, = args
|
||||
else:
|
||||
username = getpass.getuser()
|
||||
|
||||
User = get_user_model()
|
||||
try:
|
||||
u = User.objects.get(username=username)
|
||||
except User.DoesNotExist:
|
||||
raise CommandError("user %s does not exist" % username)
|
||||
|
||||
print("Changing password for user: %s" % u.username)
|
||||
p1 = p2 = ""
|
||||
while "" in (p1, p2) or p1 != p2:
|
||||
p1 = getpass.getpass()
|
||||
p2 = getpass.getpass("Password (again): ")
|
||||
if p1 != p2:
|
||||
print("Passwords do not match, try again")
|
||||
elif "" in (p1, p2):
|
||||
raise CommandError("aborted")
|
||||
|
||||
u.set_password(p1)
|
||||
u.save()
|
||||
|
||||
return "Password changed successfully for user %s\n" % u.username
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue