This commit is contained in:
Iliyan Angelov
2025-09-19 11:58:53 +03:00
parent 306b20e24a
commit 6b247e5b9f
11423 changed files with 1500615 additions and 778 deletions

View File

@@ -0,0 +1,6 @@
# -*- coding: utf-8 -*-
from django.utils.version import get_version
VERSION = (4, 1, 0, "final", 0)
__version__ = get_version(VERSION)

View File

@@ -0,0 +1,195 @@
# -*- coding: utf-8 -*-
#
# Autocomplete feature for admin panel
#
import operator
from functools import update_wrapper, reduce
from typing import Tuple, Dict, Callable # NOQA
from django.apps import apps
from django.http import HttpResponse, HttpResponseNotFound
from django.conf import settings
from django.db import models
from django.db.models.query import QuerySet
from django.utils.encoding import smart_str
from django.utils.translation import gettext as _
from django.utils.text import get_text_list
from django.contrib import admin
from django_extensions.admin.widgets import ForeignKeySearchInput
class ForeignKeyAutocompleteAdminMixin:
"""
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.
And also an optional additional field to set the limit on the
results returned by the autocomplete query. You can set this integer
value in your settings file using FOREIGNKEY_AUTOCOMPLETE_LIMIT or
you can set this per ForeignKeyAutocompleteAdmin basis. If any value
is set the results will not be limited.
"""
related_search_fields = {} # type: Dict[str, Tuple[str]]
related_string_functions = {} # type: Dict[str, Callable]
autocomplete_limit = getattr(settings, "FOREIGNKEY_AUTOCOMPLETE_LIMIT", None)
def get_urls(self):
from django.urls import path
def wrap(view):
def wrapper(*args, **kwargs):
return self.admin_site.admin_view(view)(*args, **kwargs)
return update_wrapper(wrapper, view)
return [
path(
"foreignkey_autocomplete/",
wrap(self.foreignkey_autocomplete),
name="%s_%s_autocomplete"
% (self.model._meta.app_label, self.model._meta.model_name),
)
] + super().get_urls()
def foreignkey_autocomplete(self, request):
"""
Search 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.__str__()
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 = apps.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.query.select_related = queryset.query.select_related
other_qs = other_qs.filter(reduce(operator.or_, or_queries))
queryset = queryset & other_qs
additional_filter = self.get_related_filter(model, request)
if additional_filter:
queryset = queryset.filter(additional_filter)
if self.autocomplete_limit:
queryset = queryset[: self.autocomplete_limit]
data = "".join(
[str("%s|%s\n") % (to_string_function(f), f.pk) for f in queryset]
)
elif object_pk:
try:
obj = queryset.get(pk=object_pk)
except Exception: # FIXME: use stricter exception checking
pass
else:
data = to_string_function(obj)
return HttpResponse(data, content_type="text/plain")
return HttpResponseNotFound()
def get_related_filter(self, model, request):
"""
Given a model class and current request return an optional Q object
that should be applied as an additional filter for autocomplete query.
If no additional filtering is needed, this method should return
None.
"""
return None
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, request, **kwargs):
"""
Override 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
):
help_text = self.get_help_text(
db_field.name, db_field.remote_field.model._meta.object_name
)
if kwargs.get("help_text"):
help_text = str("%s %s") % (kwargs["help_text"], help_text)
kwargs["widget"] = ForeignKeySearchInput(
db_field.remote_field, self.related_search_fields[db_field.name]
)
kwargs["help_text"] = help_text
return super().formfield_for_dbfield(db_field, request, **kwargs)
class ForeignKeyAutocompleteAdmin(ForeignKeyAutocompleteAdminMixin, admin.ModelAdmin):
pass
class ForeignKeyAutocompleteTabularInline(
ForeignKeyAutocompleteAdminMixin, admin.TabularInline
):
pass
class ForeignKeyAutocompleteStackedInline(
ForeignKeyAutocompleteAdminMixin, admin.StackedInline
):
pass

View File

@@ -0,0 +1,57 @@
# -*- coding: utf-8 -*-
from django.contrib.admin import FieldListFilter
from django.contrib.admin.utils import prepare_lookup_value
from django.utils.translation import gettext_lazy as _
class NullFieldListFilter(FieldListFilter):
def __init__(self, field, request, params, model, model_admin, field_path):
self.lookup_kwarg = "{0}__isnull".format(field_path)
super().__init__(field, request, params, model, model_admin, field_path)
lookup_choices = self.lookups(request, model_admin)
self.lookup_choices = () if lookup_choices is None else list(lookup_choices)
def expected_parameters(self):
return [self.lookup_kwarg]
def value(self):
return self.used_parameters.get(self.lookup_kwarg, None)
def lookups(self, request, model_admin):
return (
("1", _("Yes")),
("0", _("No")),
)
def choices(self, cl):
yield {
"selected": self.value() is None,
"query_string": cl.get_query_string({}, [self.lookup_kwarg]),
"display": _("All"),
}
for lookup, title in self.lookup_choices:
yield {
"selected": self.value()
== prepare_lookup_value(self.lookup_kwarg, lookup),
"query_string": cl.get_query_string(
{
self.lookup_kwarg: lookup,
},
[],
),
"display": title,
}
def queryset(self, request, queryset):
if self.value() is not None:
kwargs = {self.lookup_kwarg: self.value()}
return queryset.filter(**kwargs)
return queryset
class NotNullFieldListFilter(NullFieldListFilter):
def lookups(self, request, model_admin):
return (
("0", _("Yes")),
("1", _("No")),
)

View File

@@ -0,0 +1,100 @@
# -*- coding: utf-8 -*-
import urllib
from django import forms
from django.contrib.admin.sites import site
from django.contrib.admin.widgets import ForeignKeyRawIdWidget
from django.template.loader import render_to_string
from django.templatetags.static import static
from django.urls import reverse
from django.utils.safestring import mark_safe
from django.utils.text import Truncator
class ForeignKeySearchInput(ForeignKeyRawIdWidget):
"""
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 = None
@property
def media(self):
js_files = [
static("django_extensions/js/jquery.bgiframe.js"),
static("django_extensions/js/jquery.ajaxQueue.js"),
static("django_extensions/js/jquery.autocomplete.js"),
]
return forms.Media(
css={"all": (static("django_extensions/css/jquery.autocomplete.css"),)},
js=js_files,
)
def label_for_value(self, value):
key = self.rel.get_related_field().name
obj = self.rel.model._default_manager.get(**{key: value})
return Truncator(obj).words(14, truncate="...")
def __init__(self, rel, search_fields, attrs=None):
self.search_fields = search_fields
super().__init__(rel, site, attrs)
def render(self, name, value, attrs=None, renderer=None):
if attrs is None:
attrs = {}
opts = self.rel.model._meta
app_label = opts.app_label
model_name = opts.object_name.lower()
related_url = reverse("admin:%s_%s_changelist" % (app_label, model_name))
if not self.search_path:
self.search_path = urllib.parse.urljoin(
related_url, "foreignkey_autocomplete/"
)
params = self.url_parameters()
if params:
url = "?" + "&amp;".join(["%s=%s" % (k, v) for k, v in params.items()])
else:
url = ""
if "class" not 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 = ""
context = {
"url": url,
"related_url": related_url,
"search_path": self.search_path,
"search_fields": ",".join(self.search_fields),
"app_label": app_label,
"model_name": model_name,
"label": label,
"name": name,
}
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("".join(output))

View File

@@ -0,0 +1,7 @@
# -*- coding: utf-8 -*-
from django.apps import AppConfig
class DjangoExtensionsConfig(AppConfig):
name = "django_extensions"
verbose_name = "Django Extensions"

View File

@@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-
from django.contrib.auth.mixins import UserPassesTestMixin
class ModelUserFieldPermissionMixin(UserPassesTestMixin):
model_permission_user_field = "user"
def get_model_permission_user_field(self):
return self.model_permission_user_field
def test_func(self):
model_attr = self.get_model_permission_user_field()
current_user = self.request.user
return current_user == getattr(self.get_queryset().first(), model_attr)

View File

@@ -0,0 +1,294 @@
# -*- coding: utf-8 -*-
import inspect
import sys
from abc import abstractmethod, ABCMeta
from typing import ( # NOQA
Dict,
List,
Optional,
Tuple,
)
from django.utils.module_loading import import_string
class BaseCR(metaclass=ABCMeta):
"""
Abstract base collision resolver. All collision resolvers needs to inherit from this class.
To write custom collision resolver you need to overwrite resolve_collisions function.
It receives Dict[str, List[str]], where key is model name and values are full model names
(full model name means: module + model_name).
You should return Dict[str, str], where key is model name and value is full model name.
""" # noqa: E501
@classmethod
def get_app_name_and_model(cls, full_model_path): # type: (str) -> Tuple[str, str]
model_class = import_string(full_model_path)
return model_class._meta.app_config.name, model_class.__name__
@abstractmethod
def resolve_collisions(self, namespace): # type: (Dict[str, List[str]]) -> Dict[str, str]
pass
class LegacyCR(BaseCR):
"""
Default collision resolver.
Model from last application in alphabetical order is selected.
"""
def resolve_collisions(self, namespace):
result = {}
for name, models in namespace.items():
result[name] = models[-1]
return result
class AppsOrderCR(LegacyCR, metaclass=ABCMeta):
APP_PRIORITIES = None # type: List[str]
def resolve_collisions(self, namespace):
assert self.APP_PRIORITIES is not None, (
"You must define APP_PRIORITIES in your resolver class!"
)
result = {}
for name, models in namespace.items():
if len(models) > 0:
sorted_models = self._sort_models_depending_on_priorities(models)
result[name] = sorted_models[0][1]
return result
def _sort_models_depending_on_priorities(self, models): # type: (List[str]) -> List[Tuple[int, str]]
models_with_priorities = []
for model in models:
try:
app_name, _ = self.get_app_name_and_model(model)
position = self.APP_PRIORITIES.index(app_name)
except (ImportError, ValueError):
position = sys.maxsize
models_with_priorities.append((position, model))
return sorted(models_with_priorities)
class InstalledAppsOrderCR(AppsOrderCR):
"""
Collision resolver which selects first model from INSTALLED_APPS.
You can set your own app priorities list by subclassing him and overwriting APP_PRIORITIES field.
This collision resolver will select model from first app on this list.
If both app's are absent on this list, resolver will choose model from first app in alphabetical order.
""" # noqa: E501
@property
def APP_PRIORITIES(self):
from django.conf import settings
return getattr(settings, "INSTALLED_APPS", [])
class PathBasedCR(LegacyCR, metaclass=ABCMeta):
"""
Abstract resolver which transforms full model name into alias.
To use him you need to overwrite transform_import function
which should have one parameter. It will be full model name.
It should return valid alias as str instance.
"""
@abstractmethod
def transform_import(self, module_path): # type: (str) -> str
pass
def resolve_collisions(self, namespace):
base_imports = super(PathBasedCR, self).resolve_collisions(namespace)
for name, models in namespace.items():
if len(models) <= 1:
continue
for model in models:
new_name = self.transform_import(model)
assert isinstance(new_name, str), (
"result of transform_import must be str!"
)
base_imports[new_name] = model
return base_imports
class FullPathCR(PathBasedCR):
"""
Collision resolver which transform full model name to alias by changing dots to underscores.
He also removes 'models' part of alias, because all models are in models.py files.
Model from last application in alphabetical order is selected.
""" # noqa: E501
def transform_import(self, module_path):
module, model = module_path.rsplit(".models", 1)
module_path = module + model
return module_path.replace(".", "_")
class AppNameCR(PathBasedCR, metaclass=ABCMeta):
"""
Abstract collision resolver which transform pair (app name, model_name) to alias by changing dots to underscores.
You must define MODIFICATION_STRING which should be string to format with two keyword arguments:
app_name and model_name. For example: "{app_name}_{model_name}".
Model from last application in alphabetical order is selected.
""" # noqa: E501
MODIFICATION_STRING = None # type: Optional[str]
def transform_import(self, module_path):
assert self.MODIFICATION_STRING is not None, (
"You must define MODIFICATION_STRING in your resolver class!"
)
app_name, model_name = self.get_app_name_and_model(module_path)
app_name = app_name.replace(".", "_")
return self.MODIFICATION_STRING.format(app_name=app_name, model_name=model_name)
class AppNamePrefixCR(AppNameCR):
"""
Collision resolver which transform pair (app name, model_name) to alias "{app_name}_{model_name}".
Model from last application in alphabetical order is selected.
Result is different than FullPathCR, when model has app_label other than current app.
""" # noqa: E501
MODIFICATION_STRING = "{app_name}_{model_name}"
class AppNameSuffixCR(AppNameCR):
"""
Collision resolver which transform pair (app name, model_name) to alias "{model_name}_{app_name}"
Model from last application in alphabetical order is selected.
""" # noqa: E501
MODIFICATION_STRING = "{model_name}_{app_name}"
class AppNamePrefixCustomOrderCR(AppNamePrefixCR, InstalledAppsOrderCR):
"""
Collision resolver which is mixin of AppNamePrefixCR and InstalledAppsOrderCR.
In case of collisions he sets aliases like AppNamePrefixCR, but sets default model using InstalledAppsOrderCR.
""" # noqa: E501
pass
class AppNameSuffixCustomOrderCR(AppNameSuffixCR, InstalledAppsOrderCR):
"""
Collision resolver which is mixin of AppNameSuffixCR and InstalledAppsOrderCR.
In case of collisions he sets aliases like AppNameSuffixCR, but sets default model using InstalledAppsOrderCR.
""" # noqa: E501
pass
class FullPathCustomOrderCR(FullPathCR, InstalledAppsOrderCR):
"""
Collision resolver which is mixin of FullPathCR and InstalledAppsOrderCR.
In case of collisions he sets aliases like FullPathCR, but sets default model using InstalledAppsOrderCR.
""" # noqa: E501
pass
class AppLabelCR(PathBasedCR, metaclass=ABCMeta):
"""
Abstract collision resolver which transform pair (app_label, model_name) to alias.
You must define MODIFICATION_STRING which should be string to format with two keyword arguments:
app_label and model_name. For example: "{app_label}_{model_name}".
This is different from AppNameCR when the app is nested with several level of namespace:
Gives sites_Site instead of django_contrib_sites_Site
Model from last application in alphabetical order is selected.
""" # noqa: E501
MODIFICATION_STRING = None # type: Optional[str]
def transform_import(self, module_path):
assert self.MODIFICATION_STRING is not None, (
"You must define MODIFICATION_STRING in your resolver class!"
)
model_class = import_string(module_path)
app_label, model_name = model_class._meta.app_label, model_class.__name__
return self.MODIFICATION_STRING.format(
app_label=app_label, model_name=model_name
)
class AppLabelPrefixCR(AppLabelCR):
"""
Collision resolver which transform pair (app_label, model_name) to alias "{app_label}_{model_name}".
Model from last application in alphabetical order is selected.
""" # noqa: E501
MODIFICATION_STRING = "{app_label}_{model_name}"
class AppLabelSuffixCR(AppLabelCR):
"""
Collision resolver which transform pair (app_label, model_name) to alias "{model_name}_{app_label}".
Model from last application in alphabetical order is selected.
""" # noqa: E501
MODIFICATION_STRING = "{model_name}_{app_label}"
class CollisionResolvingRunner:
def __init__(self):
pass
def run_collision_resolver(self, models_to_import):
# type: (Dict[str, List[str]]) -> Dict[str, List[Tuple[str, str]]]
dictionary_of_names = self._get_dictionary_of_names(models_to_import) # type: Dict[str, str]
return self._get_dictionary_of_modules(dictionary_of_names)
@classmethod
def _get_dictionary_of_names(cls, models_to_import): # type: (Dict[str, List[str]]) -> (Dict[str, str])
from django.conf import settings
collision_resolver_class = import_string(
getattr(
settings,
"SHELL_PLUS_MODEL_IMPORTS_RESOLVER",
"django_extensions.collision_resolvers.LegacyCR",
)
)
cls._assert_is_collision_resolver_class_correct(collision_resolver_class)
result = collision_resolver_class().resolve_collisions(models_to_import)
cls._assert_is_collision_resolver_result_correct(result)
return result
@classmethod
def _assert_is_collision_resolver_result_correct(cls, result):
assert isinstance(result, dict), (
"Result of resolve_collisions function must be a dict!"
)
for key, value in result.items():
assert isinstance(key, str), (
"key in collision resolver result should be str not %s" % key
)
assert isinstance(value, str), (
"value in collision resolver result should be str not %s" % value
)
@classmethod
def _assert_is_collision_resolver_class_correct(cls, collision_resolver_class):
assert inspect.isclass(collision_resolver_class) and issubclass(
collision_resolver_class, BaseCR
), "SHELL_PLUS_MODEL_IMPORTS_RESOLVER must be subclass of BaseCR!"
assert (
len(
inspect.getfullargspec(collision_resolver_class.resolve_collisions).args
)
== 2
), "resolve_collisions function must take one argument!"
@classmethod
def _get_dictionary_of_modules(cls, dictionary_of_names):
# type: (Dict[str, str]) -> Dict[str, List[Tuple[str, str]]]
dictionary_of_modules = {} # type: Dict[str, List[Tuple[str, str]]]
for alias, model in dictionary_of_names.items():
module_path, model_name = model.rsplit(".", 1)
dictionary_of_modules.setdefault(module_path, [])
dictionary_of_modules[module_path].append((model_name, alias))
return dictionary_of_modules

View File

@@ -0,0 +1,68 @@
# -*- coding: utf-8 -*-
from io import BytesIO
import csv
import codecs
import importlib
from django.conf import settings
#
# Django compatibility
#
def load_tag_library(libname):
"""
Load a templatetag library on multiple Django versions.
Returns None if the library isn't loaded.
"""
from django.template.backends.django import get_installed_libraries
from django.template.library import InvalidTemplateLibrary
try:
lib = get_installed_libraries()[libname]
lib = importlib.import_module(lib).register
return lib
except (InvalidTemplateLibrary, KeyError):
return None
def get_template_setting(template_key, default=None):
"""Read template settings"""
templates_var = getattr(settings, "TEMPLATES", None)
if templates_var:
for tdict in templates_var:
if template_key in tdict:
return tdict[template_key]
return default
class UnicodeWriter:
"""
CSV writer which will write rows to CSV file "f",
which is encoded in the given encoding.
We are using this custom UnicodeWriter for python versions 2.x
"""
def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds):
self.queue = BytesIO()
self.writer = csv.writer(self.queue, dialect=dialect, **kwds)
self.stream = f
self.encoder = codecs.getincrementalencoder(encoding)()
def writerow(self, row):
self.writer.writerow([s.encode("utf-8") for s in row])
# Fetch UTF-8 output from the queue ...
data = self.queue.getvalue()
data = data.decode("utf-8")
# ... and reencode it into the target encoding
data = self.encoder.encode(data)
# write to the target stream
self.stream.write(data)
# empty queue
self.queue.truncate(0)
def writerows(self, rows):
for row in rows:
self.writerow(row)

View File

@@ -0,0 +1,3 @@
from django import forms
# place form definition here

View File

@@ -0,0 +1,3 @@
from django.db import models
# Create your models here.

View File

@@ -0,0 +1,3 @@
from django.urls import include, path
# place app url patterns here

View File

@@ -0,0 +1 @@
# Create your views here.

View File

@@ -0,0 +1,11 @@
from django.core.management.base import {{ base_command }}
class Command({{ base_command }}):
help = "My shiny new management command."
def add_arguments(self, parser):
parser.add_argument('sample', nargs='+')
def handle(self, *args, **options):
raise NotImplementedError()

View File

@@ -0,0 +1,9 @@
from django_extensions.management.jobs import BaseJob
class Job(BaseJob):
help = "My sample job."
def execute(self):
# executing empty sample job
pass

View File

@@ -0,0 +1,3 @@
from django import template
register = template.Library()

View File

@@ -0,0 +1,638 @@
# -*- coding: utf-8 -*-
"""
Django Extensions additional model fields
Some fields might require additional dependencies to be installed.
"""
import re
import string
try:
import uuid
HAS_UUID = True
except ImportError:
HAS_UUID = False
try:
import shortuuid
HAS_SHORT_UUID = True
except ImportError:
HAS_SHORT_UUID = False
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.db.models import DateTimeField, CharField, SlugField, Q, UniqueConstraint
from django.db.models.constants import LOOKUP_SEP
from django.template.defaultfilters import slugify
from django.utils.crypto import get_random_string
from django.utils.encoding import force_str
MAX_UNIQUE_QUERY_ATTEMPTS = getattr(
settings, "EXTENSIONS_MAX_UNIQUE_QUERY_ATTEMPTS", 100
)
class UniqueFieldMixin:
def check_is_bool(self, attrname):
if not isinstance(getattr(self, attrname), bool):
raise ValueError("'{}' argument must be True or False".format(attrname))
@staticmethod
def _get_fields(model_cls):
return [
(f, f.model if f.model != model_cls else None)
for f in model_cls._meta.get_fields()
if not f.is_relation or f.one_to_one or (f.many_to_one and f.related_model)
]
def get_queryset(self, model_cls, slug_field):
for field, model in self._get_fields(model_cls):
if model and field == slug_field:
return model._default_manager.all()
return model_cls._default_manager.all()
def find_unique(self, model_instance, field, iterator, *args):
# exclude the current model instance from the queryset used in finding
# next valid hash
queryset = self.get_queryset(model_instance.__class__, field)
if model_instance.pk:
queryset = queryset.exclude(pk=model_instance.pk)
# form a kwarg dict used to implement any unique_together constraints
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)
# for support django 2.2+
query = Q()
constraints = getattr(model_instance._meta, "constraints", None)
if constraints:
unique_constraints = filter(
lambda c: isinstance(c, UniqueConstraint), constraints
)
for unique_constraint in unique_constraints:
if self.attname in unique_constraint.fields:
condition = {
field: getattr(model_instance, field, None)
for field in unique_constraint.fields
if field != self.attname
}
query &= Q(**condition)
new = next(iterator)
kwargs[self.attname] = new
while not new or queryset.filter(query, **kwargs):
new = next(iterator)
kwargs[self.attname] = new
setattr(model_instance, self.attname, new)
return new
class AutoSlugField(UniqueFieldMixin, SlugField):
"""
AutoSlugField
By default, sets editable=False, blank=True.
Required arguments:
populate_from
Specifies which field, list of fields, or model method
the slug will be populated from.
populate_from can traverse a ForeignKey relationship
by using Django ORM syntax:
populate_from = 'related_model__field'
Optional arguments:
separator
Defines the used separator (default: '-')
overwrite
If set to True, overwrites the slug on every save (default: False)
slugify_function
Defines the function which will be used to "slugify" a content
(default: :py:func:`~django.template.defaultfilters.slugify` )
It is possible to provide custom "slugify" function with
the ``slugify_function`` function in a model class.
``slugify_function`` function in a model class takes priority over
``slugify_function`` given as an argument to :py:class:`~AutoSlugField`.
Example
.. code-block:: python
# models.py
from django.db import models
from django_extensions.db.fields import AutoSlugField
class MyModel(models.Model):
def slugify_function(self, content):
return content.replace('_', '-').lower()
title = models.CharField(max_length=42)
slug = AutoSlugField(populate_from='title')
Inspired by SmileyChris' Unique Slugify snippet:
https://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
if not callable(populate_from):
if not isinstance(populate_from, (list, tuple)):
populate_from = (populate_from,)
if not all(isinstance(e, str) for e in populate_from):
raise TypeError(
"'populate_from' must be str or list[str] or tuple[str], found `%s`"
% populate_from
)
self.slugify_function = kwargs.pop("slugify_function", slugify)
self.separator = kwargs.pop("separator", "-")
self.overwrite = kwargs.pop("overwrite", False)
self.check_is_bool("overwrite")
self.overwrite_on_add = kwargs.pop("overwrite_on_add", True)
self.check_is_bool("overwrite_on_add")
self.allow_duplicates = kwargs.pop("allow_duplicates", False)
self.check_is_bool("allow_duplicates")
self.max_unique_query_attempts = kwargs.pop(
"max_unique_query_attempts", MAX_UNIQUE_QUERY_ATTEMPTS
)
super().__init__(*args, **kwargs)
def _slug_strip(self, value):
"""
Clean 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)
@staticmethod
def slugify_func(content, slugify_function):
if content:
return slugify_function(content)
return ""
def slug_generator(self, original_slug, start):
yield original_slug
for i in range(start, self.max_unique_query_attempts):
slug = original_slug
end = "%s%s" % (self.separator, i)
end_len = len(end)
if self.slug_len and len(slug) + end_len > self.slug_len:
slug = slug[: self.slug_len - end_len]
slug = self._slug_strip(slug)
slug = "%s%s" % (slug, end)
yield slug
raise RuntimeError(
"max slug attempts for %s exceeded (%s)"
% (original_slug, self.max_unique_query_attempts)
)
def create_slug(self, model_instance, add):
slug = getattr(model_instance, self.attname)
use_existing_slug = False
if slug and not self.overwrite:
# Existing slug and not configured to overwrite - Short-circuit
# here to prevent slug generation when not required.
use_existing_slug = True
if self.overwrite_on_add and add:
use_existing_slug = False
if use_existing_slug:
return slug
# get fields to populate from and slug field to set
populate_from = self._populate_from
if not isinstance(populate_from, (list, tuple)):
populate_from = (populate_from,)
slug_field = model_instance._meta.get_field(self.attname)
slugify_function = getattr(
model_instance, "slugify_function", self.slugify_function
)
# slugify the original field content and set next step to 2
slug_for_field = lambda lookup_value: self.slugify_func(
self.get_slug_fields(model_instance, lookup_value),
slugify_function=slugify_function,
)
slug = self.separator.join(map(slug_for_field, populate_from))
start = 2
# strip slug depending on max_length attribute of the slug field
# and clean-up
self.slug_len = slug_field.max_length
if self.slug_len:
slug = slug[: self.slug_len]
slug = self._slug_strip(slug)
original_slug = slug
if self.allow_duplicates:
setattr(model_instance, self.attname, slug)
return slug
return self.find_unique(
model_instance, slug_field, self.slug_generator(original_slug, start)
)
def get_slug_fields(self, model_instance, lookup_value):
if callable(lookup_value):
# A function has been provided
return "%s" % lookup_value(model_instance)
lookup_value_path = lookup_value.split(LOOKUP_SEP)
attr = model_instance
for elem in lookup_value_path:
try:
attr = getattr(attr, elem)
except AttributeError:
raise AttributeError(
"value {} in AutoSlugField's 'populate_from' argument {} returned an error - {} has no attribute {}".format( # noqa: E501
elem, lookup_value, attr, elem
)
)
if callable(attr):
return "%s" % attr()
return attr
def pre_save(self, model_instance, add):
value = force_str(self.create_slug(model_instance, add))
return value
def get_internal_type(self):
return "SlugField"
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
kwargs["populate_from"] = self._populate_from
if not self.separator == "-":
kwargs["separator"] = self.separator
if self.overwrite is not False:
kwargs["overwrite"] = True
if self.allow_duplicates is not False:
kwargs["allow_duplicates"] = True
return name, path, args, kwargs
class RandomCharField(UniqueFieldMixin, CharField):
"""
RandomCharField
By default, sets editable=False, blank=True, unique=False.
Required arguments:
length
Specifies the length of the field
Optional arguments:
unique
If set to True, duplicate entries are not allowed (default: False)
lowercase
If set to True, lowercase the alpha characters (default: False)
uppercase
If set to True, uppercase the alpha characters (default: False)
include_alpha
If set to True, include alpha characters (default: True)
include_digits
If set to True, include digit characters (default: True)
include_punctuation
If set to True, include punctuation characters (default: False)
keep_default
If set to True, keeps the default initialization value (default: False)
"""
def __init__(self, *args, **kwargs):
kwargs.setdefault("blank", True)
kwargs.setdefault("editable", False)
self.length = kwargs.pop("length", None)
if self.length is None:
raise ValueError("missing 'length' argument")
kwargs["max_length"] = self.length
self.lowercase = kwargs.pop("lowercase", False)
self.check_is_bool("lowercase")
self.uppercase = kwargs.pop("uppercase", False)
self.check_is_bool("uppercase")
if self.uppercase and self.lowercase:
raise ValueError(
"the 'lowercase' and 'uppercase' arguments are mutually exclusive"
)
self.include_digits = kwargs.pop("include_digits", True)
self.check_is_bool("include_digits")
self.include_alpha = kwargs.pop("include_alpha", True)
self.check_is_bool("include_alpha")
self.include_punctuation = kwargs.pop("include_punctuation", False)
self.keep_default = kwargs.pop("keep_default", False)
self.check_is_bool("include_punctuation")
self.max_unique_query_attempts = kwargs.pop(
"max_unique_query_attempts", MAX_UNIQUE_QUERY_ATTEMPTS
)
# Set unique=False unless it's been set manually.
if "unique" not in kwargs:
kwargs["unique"] = False
super().__init__(*args, **kwargs)
def random_char_generator(self, chars):
for i in range(self.max_unique_query_attempts):
yield "".join(get_random_string(self.length, chars))
raise RuntimeError(
"max random character attempts exceeded (%s)"
% self.max_unique_query_attempts
)
def in_unique_together(self, model_instance):
for params in model_instance._meta.unique_together:
if self.attname in params:
return True
return False
def pre_save(self, model_instance, add):
if (not add or self.keep_default) and getattr(
model_instance, self.attname
) != "":
return getattr(model_instance, self.attname)
population = ""
if self.include_alpha:
if self.lowercase:
population += string.ascii_lowercase
elif self.uppercase:
population += string.ascii_uppercase
else:
population += string.ascii_letters
if self.include_digits:
population += string.digits
if self.include_punctuation:
population += string.punctuation
random_chars = self.random_char_generator(population)
if not self.unique and not self.in_unique_together(model_instance):
new = next(random_chars)
setattr(model_instance, self.attname, new)
return new
return self.find_unique(
model_instance,
model_instance._meta.get_field(self.attname),
random_chars,
)
def internal_type(self):
return "CharField"
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
kwargs["length"] = self.length
del kwargs["max_length"]
if self.lowercase is True:
kwargs["lowercase"] = self.lowercase
if self.uppercase is True:
kwargs["uppercase"] = self.uppercase
if self.include_alpha is False:
kwargs["include_alpha"] = self.include_alpha
if self.include_digits is False:
kwargs["include_digits"] = self.include_digits
if self.include_punctuation is True:
kwargs["include_punctuation"] = self.include_punctuation
if self.unique is True:
kwargs["unique"] = self.unique
return name, path, args, kwargs
class CreationDateTimeField(DateTimeField):
"""
CreationDateTimeField
By default, sets editable=False, blank=True, auto_now_add=True
"""
def __init__(self, *args, **kwargs):
kwargs.setdefault("editable", False)
kwargs.setdefault("blank", True)
kwargs.setdefault("auto_now_add", True)
DateTimeField.__init__(self, *args, **kwargs)
def get_internal_type(self):
return "DateTimeField"
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
if self.editable is not False:
kwargs["editable"] = True
if self.blank is not True:
kwargs["blank"] = False
if self.auto_now_add is not False:
kwargs["auto_now_add"] = True
return name, path, args, kwargs
class ModificationDateTimeField(CreationDateTimeField):
"""
ModificationDateTimeField
By default, sets editable=False, blank=True, auto_now=True
Sets value to now every time the object is saved.
"""
def __init__(self, *args, **kwargs):
kwargs.setdefault("auto_now", True)
DateTimeField.__init__(self, *args, **kwargs)
def get_internal_type(self):
return "DateTimeField"
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
if self.auto_now is not False:
kwargs["auto_now"] = True
return name, path, args, kwargs
def pre_save(self, model_instance, add):
if not getattr(model_instance, "update_modified", True):
return getattr(model_instance, self.attname)
return super().pre_save(model_instance, add)
class UUIDVersionError(Exception):
pass
class UUIDFieldMixin:
"""
UUIDFieldMixin
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: https://docs.python.org/lib/module-uuid.html
""" # noqa: E501
DEFAULT_MAX_LENGTH = 36
def __init__(
self,
verbose_name=None,
name=None,
auto=True,
version=4,
node=None,
clock_seq=None,
namespace=None,
uuid_name=None,
*args,
**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", self.DEFAULT_MAX_LENGTH)
if auto:
self.empty_strings_allowed = False
kwargs["blank"] = True
kwargs.setdefault("editable", False)
self.auto = auto
self.version = version
self.node = node
self.clock_seq = clock_seq
self.namespace = namespace
self.uuid_name = uuid_name or name
super().__init__(verbose_name=verbose_name, *args, **kwargs)
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.uuid_name)
elif self.version == 5:
return uuid.uuid5(self.namespace, self.uuid_name)
else:
raise UUIDVersionError("UUID version %s is not valid." % self.version)
def pre_save(self, model_instance, add):
value = super().pre_save(model_instance, add)
if self.auto and add and value is None:
value = force_str(self.create_uuid())
setattr(model_instance, self.attname, value)
return value
else:
if self.auto and not value:
value = force_str(self.create_uuid())
setattr(model_instance, self.attname, value)
return value
def formfield(self, form_class=None, choices_form_class=None, **kwargs):
if self.auto:
return None
return super().formfield(form_class, choices_form_class, **kwargs)
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
if kwargs.get("max_length", None) == self.DEFAULT_MAX_LENGTH:
del kwargs["max_length"]
if self.auto is not True:
kwargs["auto"] = self.auto
if self.version != 4:
kwargs["version"] = self.version
if self.node is not None:
kwargs["node"] = self.node
if self.clock_seq is not None:
kwargs["clock_seq"] = self.clock_seq
if self.namespace is not None:
kwargs["namespace"] = self.namespace
if self.uuid_name is not None:
kwargs["uuid_name"] = self.name
return name, path, args, kwargs
class ShortUUIDField(UUIDFieldMixin, CharField):
"""
ShortUUIDFied
Generates concise (22 characters instead of 36), unambiguous, URL-safe UUIDs.
Based on `shortuuid`: https://github.com/stochastic-technologies/shortuuid
"""
DEFAULT_MAX_LENGTH = 22
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if not HAS_SHORT_UUID:
raise ImproperlyConfigured(
"'shortuuid' module is required for ShortUUIDField. "
"(Do you have Python 2.5 or higher installed ?)"
)
kwargs.setdefault("max_length", self.DEFAULT_MAX_LENGTH)
def create_uuid(self):
if not self.version or self.version == 4:
return shortuuid.uuid()
elif self.version == 1:
return shortuuid.uuid()
elif self.version == 2:
raise UUIDVersionError("UUID version 2 is not supported.")
elif self.version == 3:
raise UUIDVersionError("UUID version 3 is not supported.")
elif self.version == 5:
return shortuuid.uuid(name=self.namespace)
else:
raise UUIDVersionError("UUID version %s is not valid." % self.version)

View File

@@ -0,0 +1,115 @@
# -*- coding: utf-8 -*-
"""
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 json
from django.core.serializers.json import DjangoJSONEncoder
from django.db import models
from django.db.models import expressions
def dumps(value):
return DjangoJSONEncoder().encode(value)
def loads(txt):
return json.loads(txt)
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):
"""
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 JSONField(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):
kwargs["default"] = kwargs.get("default", dict)
models.TextField.__init__(self, *args, **kwargs)
def get_default(self):
if self.has_default():
default = self.default
if callable(default):
default = default()
return self.to_python(default)
return super().get_default()
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 {}
if isinstance(value, str):
res = loads(value)
else:
res = value
if isinstance(res, dict):
return JSONDict(**res)
elif isinstance(res, list):
return JSONList(res)
return res
def get_prep_value(self, value):
if not isinstance(value, str):
return dumps(value)
return super(models.TextField, self).get_prep_value(value)
def from_db_value(self, value, expression, connection): # type: ignore
return self.to_python(value)
def get_db_prep_save(self, value, connection, **kwargs):
"""Convert our JSON object to a string before we save"""
if value is None and self.null:
return None
# default values come in as strings; only non-strings should be
# run through `dumps`
if (
not isinstance(value, str)
# https://github.com/django-extensions/django-extensions/issues/1924
# https://code.djangoproject.com/ticket/35167
and not isinstance(value, expressions.Expression)
):
value = dumps(value)
return super().get_db_prep_save(value, connection)
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
if self.default == "{}":
del kwargs["default"]
return name, path, args, kwargs

View File

@@ -0,0 +1,150 @@
# -*- coding: utf-8 -*-
from django.db import models
from django.utils.timezone import now
from django.utils.translation import gettext_lazy as _
from django_extensions.db.fields import (
AutoSlugField,
CreationDateTimeField,
ModificationDateTimeField,
)
class TimeStampedModel(models.Model):
"""
TimeStampedModel
An abstract base class model that provides self-managed "created" and
"modified" fields.
"""
created = CreationDateTimeField(_("created"))
modified = ModificationDateTimeField(_("modified"))
def save(self, **kwargs):
self.update_modified = kwargs.pop(
"update_modified", getattr(self, "update_modified", True)
)
super().save(**kwargs)
class Meta:
get_latest_by = "modified"
abstract = True
class TitleDescriptionModel(models.Model):
"""
TitleDescriptionModel
An abstract base class model that provides title and description fields.
"""
title = models.CharField(_("title"), max_length=255)
description = models.TextField(_("description"), blank=True, null=True)
class Meta:
abstract = True
class TitleSlugDescriptionModel(TitleDescriptionModel):
"""
TitleSlugDescriptionModel
An abstract base class model that provides title and description fields
and a self-managed "slug" field that populates from the title.
.. note ::
If you want to use custom "slugify" function, you could
define ``slugify_function`` which then will be used
in :py:class:`AutoSlugField` to slugify ``populate_from`` field.
See :py:class:`AutoSlugField` for more details.
"""
slug = AutoSlugField(_("slug"), populate_from="title")
class Meta:
abstract = True
class ActivatorQuerySet(models.query.QuerySet):
"""
ActivatorQuerySet
Query set that returns statused results
"""
def active(self):
"""Return active query set"""
return self.filter(status=ActivatorModel.ACTIVE_STATUS)
def inactive(self):
"""Return inactive query set"""
return self.filter(status=ActivatorModel.INACTIVE_STATUS)
class ActivatorModelManager(models.Manager):
"""
ActivatorModelManager
Manager to return instances of ActivatorModel:
SomeModel.objects.active() / .inactive()
"""
def get_queryset(self):
"""Use ActivatorQuerySet for all results"""
return ActivatorQuerySet(model=self.model, using=self._db)
def active(self):
"""
Return active instances of ActivatorModel:
SomeModel.objects.active(), proxy to ActivatorQuerySet.active
"""
return self.get_queryset().active()
def inactive(self):
"""
Return inactive instances of ActivatorModel:
SomeModel.objects.inactive(), proxy to ActivatorQuerySet.inactive
"""
return self.get_queryset().inactive()
class ActivatorModel(models.Model):
"""
ActivatorModel
An abstract base class model that provides activate and deactivate fields.
"""
INACTIVE_STATUS = 0
ACTIVE_STATUS = 1
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 = now()
super().save(*args, **kwargs)

View File

@@ -0,0 +1,61 @@
# -*- coding: utf-8 -*-
from importlib import import_module
from inspect import (
getmembers,
isclass,
)
from pkgutil import walk_packages
from typing import ( # NOQA
Dict,
List,
Tuple,
Union,
)
from django.conf import settings
from django.utils.module_loading import import_string
class SubclassesFinder:
def __init__(self, base_classes_from_settings):
self.base_classes = []
for element in base_classes_from_settings:
if isinstance(element, str):
element = import_string(element)
self.base_classes.append(element)
def _should_be_imported(self, candidate_to_import): # type: (Tuple[str, type]) -> bool
for base_class in self.base_classes:
if issubclass(candidate_to_import[1], base_class):
return True
return False
def collect_subclasses(self): # type: () -> Dict[str, List[Tuple[str, str]]]
"""
Collect all subclasses of user-defined base classes from project.
:return: Dictionary from module name to list of tuples.
First element of tuple is model name and second is alias.
Currently we set alias equal to model name,
but in future functionality of aliasing subclasses can be added.
"""
result = {} # type: Dict[str, List[Tuple[str, str]]]
for loader, module_name, is_pkg in walk_packages(path=[str(settings.BASE_DIR)]):
subclasses_from_module = self._collect_classes_from_module(module_name)
if subclasses_from_module:
result[module_name] = subclasses_from_module
return result
def _collect_classes_from_module(self, module_name): # type: (str) -> List[Tuple[str, str]]
for excluded_module in getattr(
settings, "SHELL_PLUS_SUBCLASSES_IMPORT_MODULES_BLACKLIST", []
):
if module_name.startswith(excluded_module):
return []
imported_module = import_module(module_name)
classes_to_import = getmembers(
imported_module,
lambda element: isclass(element)
and element.__module__ == imported_module.__name__,
)
classes_to_import = list(filter(self._should_be_imported, classes_to_import))
return [(name, name) for name, _ in classes_to_import]

View File

@@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
"""
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.conf import settings
from django.core.cache import caches
from django_extensions.management.jobs import DailyJob
class Job(DailyJob):
help = "Cache (db) cleanup Job"
def execute(self):
if hasattr(settings, "CACHES"):
for cache_name, cache_options in settings.CACHES.items():
if cache_options["BACKEND"].endswith("DatabaseCache"):
cache = caches[cache_name]
cache.clear()
return

View File

@@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
"""
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("clearsessions")

View File

@@ -0,0 +1,109 @@
# 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: 2020-06-06 11:44+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:139
msgid "and"
msgstr "و"
#: admin/__init__.py:141
#, 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 "
#: admin/filter.py:24 admin/filter.py:53
msgid "Yes"
msgstr "نعم"
#: admin/filter.py:25 admin/filter.py:54
msgid "No"
msgstr "لا"
#: admin/filter.py:32
msgid "All"
msgstr "كل"
#: db/models.py:18
msgid "created"
msgstr "تم تكونه"
#: db/models.py:19
msgid "modified"
msgstr "تم تعديله"
#: db/models.py:37
msgid "title"
msgstr "عنوان"
#: db/models.py:38
msgid "description"
msgstr "وصف"
#: db/models.py:59
msgid "slug"
msgstr "رابط "
#: db/models.py:120 mongodb/models.py:76
msgid "Inactive"
msgstr "غير نشط"
#: db/models.py:121 mongodb/models.py:77
msgid "Active"
msgstr "نشط"
#: db/models.py:123
msgid "status"
msgstr "الحالة"
#: db/models.py:124 mongodb/models.py:80
msgid "keep empty for an immediate activation"
msgstr "أترك الحقل فارغ ليتم التنشيط مباشرة"
#: db/models.py:125 mongodb/models.py:81
msgid "keep empty for indefinite activation"
msgstr "أترك الحقل فارغ لتنشيط لمدة غير محددة"
#: mongodb/fields/__init__.py:22
#, python-format
msgid "String (up to %(max_length)s)"
msgstr "سلسلة الإحرف (طولها يصل إلى %(max_length)s)"
#: validators.py:14
msgid "Control Characters like new lines or tabs are not allowed."
msgstr "لا يسمح إستعمال أحرف تحكم مثل حرف العودة إلى السطر أو علامات التبويب"
#: validators.py:48
msgid "Leading and Trailing whitespaces are not allowed."
msgstr "المسافات البيضاء الزائدة عند البداية أو نهاية غير مسموح بها"
#: validators.py:74
msgid "Only a hex string is allowed."
msgstr "مسموح إستعمال سلسلة أحرف hex فقط"
#: validators.py:75
#, python-format
msgid "Invalid length. Must be %(length)d characters."
msgstr "الطول غير مقبول, يجب أن لا يكون أطول من %(length)d"
#: validators.py:76
#, python-format
msgid "Ensure that there are more than %(min)s characters."
msgstr "تأكد أن طول سلسلة الإحرف أطول من %(min)s "
#: validators.py:77
#, python-format
msgid "Ensure that there are no more than %(max)s characters."
msgstr "تأكد أن طول سلسلة الأحرف لا تتجوز %(max)s "

View File

@@ -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"

View File

@@ -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"

View File

@@ -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 "Αναζήτηση"

View File

@@ -0,0 +1,112 @@
# 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: 2020-02-10 20:37+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"
"Language: en\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: admin/__init__.py:142
msgid "and"
msgstr ""
#: admin/__init__.py:144
#, python-format
msgid ""
"Use the left field to do %(model_name)s lookups in the fields %(field_list)s."
msgstr ""
#: admin/filter.py:24 admin/filter.py:53
msgid "Yes"
msgstr ""
#: admin/filter.py:25 admin/filter.py:54
msgid "No"
msgstr ""
#: admin/filter.py:32
msgid "All"
msgstr ""
#: db/models.py:18
msgid "created"
msgstr ""
#: db/models.py:19
msgid "modified"
msgstr ""
#: db/models.py:38
msgid "title"
msgstr ""
#: db/models.py:39
msgid "description"
msgstr ""
#: db/models.py:60
msgid "slug"
msgstr ""
#: db/models.py:121 mongodb/models.py:76
msgid "Inactive"
msgstr ""
#: db/models.py:122 mongodb/models.py:77
msgid "Active"
msgstr ""
#: db/models.py:124
msgid "status"
msgstr ""
#: db/models.py:125 mongodb/models.py:80
msgid "keep empty for an immediate activation"
msgstr ""
#: db/models.py:126 mongodb/models.py:81
msgid "keep empty for indefinite activation"
msgstr ""
#: mongodb/fields/__init__.py:22
#, python-format
msgid "String (up to %(max_length)s)"
msgstr ""
#: validators.py:14
msgid "Control Characters like new lines or tabs are not allowed."
msgstr ""
#: validators.py:48
msgid "Leading and Trailing whitespaces are not allowed."
msgstr ""
#: validators.py:74
msgid "Only a hex string is allowed."
msgstr ""
#: validators.py:75
#, python-format
msgid "Invalid length. Must be %(length)d characters."
msgstr ""
#: validators.py:76
#, python-format
msgid "Ensure that there are more than %(min)s characters."
msgstr ""
#: validators.py:77
#, python-format
msgid "Ensure that there are no more than %(max)s characters."
msgstr ""

View File

@@ -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"

View File

@@ -0,0 +1,81 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# mathiasuk, 2014
# mathiasuk, 2014
# stevandoh <stevandoh@gmail.com>, 2013
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: 2014-01-11 11:14+0000\n"
"Last-Translator: mathiasuk\n"
"Language-Team: French (https://www.transifex.com/projects/p/django-extensions/language/fr/)\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
#, 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 "mis à 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 "Actif"
#: db/models.py:53
msgid "status"
msgstr "état"
#: db/models.py:56
msgid "keep empty for an immediate activation"
msgstr "laisser vide pour activation immédiate"
#: db/models.py:58
msgid "keep empty for indefinite activation"
msgstr "laisser vide pour activation indéterminée"
#: management/commands/show_urls.py:34
#, python-format
msgid "%s does not appear to be a urlpattern object"
msgstr "%s ne semble pas etre un object urlpattern"
#: templates/django_extensions/widgets/foreignkey_searchinput.html:4
msgid "Lookup"
msgstr "Recherche"

View File

@@ -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"

View File

@@ -0,0 +1,98 @@
# 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: django-extensions\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-07-27 22:25+0700\n"
"PO-Revision-Date: 2020-07-28 10:48+0700\n"
"Last-Translator: Sutrisno Efendi <kangfend@gmail.com>\n"
"Language-Team: LANGUAGE <LL@li.org>\n\n"
"Language: id\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#: admin/__init__.py:139
msgid "and"
msgstr "dan"
#: admin/__init__.py:141
#, python-format
msgid ""
"Use the left field to do %(model_name)s lookups in the fields %(field_list)s."
msgstr ""
"Gunakan bidang sebelah kiri untuk pencarian %(model_name)s pada bidang %(field_list)s."
#: admin/filter.py:24 admin/filter.py:53
msgid "Yes"
msgstr "Ya"
#: admin/filter.py:25 admin/filter.py:54
msgid "No"
msgstr "Tidak"
#: admin/filter.py:32
msgid "All"
msgstr "Semua"
#: db/models.py:18
msgid "created"
msgstr "dibuat"
#: db/models.py:19
msgid "modified"
msgstr "diubah"
#: db/models.py:37
msgid "title"
msgstr "judul"
#: db/models.py:38
msgid "description"
msgstr "deskripsi"
#: db/models.py:59
msgid "slug"
msgstr "slug"
#: db/models.py:120 mongodb/models.py:76
msgid "Inactive"
msgstr "Nonaktif"
#: db/models.py:121 mongodb/models.py:77
msgid "Active"
msgstr "Aktif"
#: db/models.py:123
msgid "status"
msgstr "status"
#: mongodb/fields/__init__.py:22
#, python-format
msgid "String (up to %(max_length)s)"
msgstr "String (hingga %(max_length)s)"
#: validators.py:74
msgid "Only a hex string is allowed."
msgstr "Hanya string hex yang diizinkan."
#: validators.py:75
#, python-format
msgid "Invalid length. Must be %(length)d characters."
msgstr "Panjang tidak valid. Harus %(length)d karakter."
#: validators.py:76
#, python-format
msgid "Ensure that there are more than %(min)s characters."
msgstr "Pastikan lebih dari %(min)s karakter."
#: validators.py:77
#, python-format
msgid "Ensure that there are no more than %(max)s characters."
msgstr "Pastikan tidak lebih dari %(max)s karakter."

View File

@@ -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"

View File

@@ -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 "検索"

View File

@@ -0,0 +1,109 @@
# 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"
#: mongodb/fields/__init__.py:22
#, python-format
msgid "String (up to %(max_length)s)"
msgstr "String (do %(max_length)s znaków)"
#: 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"
#: validators.py:14
msgid "Control Characters like new lines or tabs are not allowed."
msgstr "Znaki nowej linii i tabulatory nie są dozwolone."
#: validators.py:48
msgid "Leading and Trailing whitespaces are not allowed."
msgstr "Białe znaki na początku i końcu wiersza nie są dozwolone."
#: validators.py:74
msgid "Only a hex string is allowed."
msgstr "Tylko wartość hex jest dozwolona."
#: validators.py:75
#, python-format
msgid "Invalid length. Must be %(length)d characters."
msgstr "Niewłaściwa długość. Musi być %(length)d znaków."
#: validators.py:76
#, python-format
msgid "Ensure that there are more than %(min)s characters."
msgstr "Upewnij się, że jest więcej niż %(min)s znaków."
#: validators.py:77
#, python-format
msgid "Ensure that there are no more than %(max)s characters."
msgstr "Upewnij się, że nie ma więcej niż %(max)s znaków."

View File

@@ -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"

View File

@@ -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: pt_BR\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"

View File

@@ -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"

View File

@@ -0,0 +1,126 @@
# django_extentions in Russian.
# django_extensions на Русском.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# Sasha Simkin <sashasimkin@gmail.com>, 2014.
#
msgid ""
msgstr ""
"Project-Id-Version: django-extensions\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-05-30 14:51-0500\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"
"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\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:142
msgid "and"
msgstr "и"
#: admin/__init__.py:144
#, 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."
#: admin/filter.py:24 admin/filter.py:53
msgid "Yes"
msgstr "Да"
#: admin/filter.py:25 admin/filter.py:54
msgid "No"
msgstr "Нет"
#: admin/filter.py:32
msgid "All"
msgstr "Все"
#: db/models.py:18
msgid "created"
msgstr "создан"
#: db/models.py:19
msgid "modified"
msgstr "изменён"
#: db/models.py:38
msgid "title"
msgstr "заголовок"
#: db/models.py:39
msgid "description"
msgstr "описание"
#: db/models.py:60
msgid "slug"
msgstr "название-метка (Для URL)"
#: db/models.py:121 mongodb/models.py:76
msgid "Inactive"
msgstr "Неактивен"
#: db/models.py:122 mongodb/models.py:77
msgid "Active"
msgstr "Активен"
#: db/models.py:124
msgid "status"
msgstr "статус"
#: db/models.py:125 mongodb/models.py:80
msgid "keep empty for an immediate activation"
msgstr "оставьте пустым для немедленной активации"
#: db/models.py:126 mongodb/models.py:81
msgid "keep empty for indefinite activation"
msgstr "оставьте пустым для бессрочной активности"
#: mongodb/fields/__init__.py:22
#, python-format
msgid "String (up to %(max_length)s)"
msgstr "Строка (Не длиннее: %(max_length)s)"
#: validators.py:14
msgid "Control Characters like new lines or tabs are not allowed."
msgstr ""
"Управляющие символы, такие как символ новой строки и символ табуляции "
"недопустимы."
#: validators.py:48
#, fuzzy
#| msgid "Leading and Trailing whitespace is not allowed."
msgid "Leading and Trailing whitespaces are not allowed."
msgstr "Пробел в начале или в конце недопустим."
#: validators.py:74
msgid "Only a hex string is allowed."
msgstr "Допустимо использование только шестнадцатеричных строк."
#: validators.py:75
#, fuzzy, python-format
#| msgid "Invalid length must be %(length)d characters."
msgid "Invalid length. Must be %(length)d characters."
msgstr "Недопустимая длина, должно быть %(length)d символов."
#: validators.py:76
#, fuzzy, python-format
#| msgid "Ensure that there are more then %(min)s characters."
msgid "Ensure that there are more than %(min)s characters."
msgstr "Убедитесь, что длина строки больше %(min)s символов."
#: validators.py:77
#, fuzzy, python-format
#| msgid "Ensure that there are no more then %(max)s characters."
msgid "Ensure that there are no more than %(max)s characters."
msgstr "Убедитесь, что длина строки не больше %(max)s символов."
#~ msgid "Lookup"
#~ msgstr "Поиск"

Some files were not shown because too many files have changed in this diff Show More