Fixed E128 flake8 warnings in django/.

This commit is contained in:
Tim Graham 2016-03-28 18:33:29 -04:00
parent 2956e2f5e3
commit df8d8d4292
136 changed files with 1641 additions and 1212 deletions

View File

@ -297,8 +297,10 @@ class Apps(object):
available = set(available) available = set(available)
installed = set(app_config.name for app_config in self.get_app_configs()) installed = set(app_config.name for app_config in self.get_app_configs())
if not available.issubset(installed): if not available.issubset(installed):
raise ValueError("Available apps isn't a subset of installed " raise ValueError(
"apps, extra apps: %s" % ", ".join(available - installed)) "Available apps isn't a subset of installed apps, extra apps: %s"
% ", ".join(available - installed)
)
self.stored_app_configs.append(self.app_configs) self.stored_app_configs.append(self.app_configs)
self.app_configs = OrderedDict( self.app_configs = OrderedDict(

View File

@ -108,8 +108,7 @@ class Settings(BaseSettings):
if (setting in tuple_settings and if (setting in tuple_settings and
not isinstance(setting_value, (list, tuple))): not isinstance(setting_value, (list, tuple))):
raise ImproperlyConfigured("The %s setting must be a list or a tuple. " raise ImproperlyConfigured("The %s setting must be a list or a tuple. " % setting)
"Please fix your settings." % setting)
setattr(self, setting, setting_value) setattr(self, setting, setting_value)
self._explicit_settings.add(setting) self._explicit_settings.add(setting)

View File

@ -20,12 +20,12 @@ compress all jQuery-based files of the admin app. Requires the Google Closure
Compiler library and Java version 6 or later.""" Compiler library and Java version 6 or later."""
parser = argparse.ArgumentParser(description=description) parser = argparse.ArgumentParser(description=description)
parser.add_argument('file', nargs='*') parser.add_argument('file', nargs='*')
parser.add_argument("-c", dest="compiler", default="~/bin/compiler.jar", parser.add_argument(
help="path to Closure Compiler jar file") "-c", dest="compiler", default="~/bin/compiler.jar",
parser.add_argument("-v", "--verbose", help="path to Closure Compiler jar file",
action="store_true", dest="verbose") )
parser.add_argument("-q", "--quiet", parser.add_argument("-v", "--verbose", action="store_true", dest="verbose")
action="store_false", dest="verbose") parser.add_argument("-q", "--quiet", action="store_false", dest="verbose")
options = parser.parse_args() options = parser.parse_args()
compiler = closure_compiler if closure_compiler else os.path.expanduser(options.compiler) compiler = closure_compiler if closure_compiler else os.path.expanduser(options.compiler)
@ -38,8 +38,10 @@ Compiler library and Java version 6 or later."""
if not options.file: if not options.file:
if options.verbose: if options.verbose:
sys.stdout.write("No filenames given; defaulting to admin scripts\n") sys.stdout.write("No filenames given; defaulting to admin scripts\n")
files = [os.path.join(js_path, f) for f in [ files = [
"actions.js", "collapse.js", "inlines.js", "prepopulate.js"]] os.path.join(js_path, f) for f in
["actions.js", "collapse.js", "inlines.js", "prepopulate.js"]
]
else: else:
files = options.file files = options.file

View File

@ -155,8 +155,7 @@ class FieldListFilter(ListFilter):
for test, list_filter_class in cls._field_list_filters: for test, list_filter_class in cls._field_list_filters:
if not test(field): if not test(field):
continue continue
return list_filter_class(field, request, params, return list_filter_class(field, request, params, model, model_admin, field_path=field_path)
model, model_admin, field_path=field_path)
class RelatedFieldListFilter(FieldListFilter): class RelatedFieldListFilter(FieldListFilter):
@ -200,8 +199,10 @@ class RelatedFieldListFilter(FieldListFilter):
def choices(self, changelist): def choices(self, changelist):
yield { yield {
'selected': self.lookup_val is None and not self.lookup_val_isnull, 'selected': self.lookup_val is None and not self.lookup_val_isnull,
'query_string': changelist.get_query_string({}, 'query_string': changelist.get_query_string(
[self.lookup_kwarg, self.lookup_kwarg_isnull]), {},
[self.lookup_kwarg, self.lookup_kwarg_isnull]
),
'display': _('All'), 'display': _('All'),
} }
for pk_val, val in self.lookup_choices: for pk_val, val in self.lookup_choices:
@ -230,8 +231,7 @@ class BooleanFieldListFilter(FieldListFilter):
self.lookup_kwarg2 = '%s__isnull' % field_path self.lookup_kwarg2 = '%s__isnull' % field_path
self.lookup_val = request.GET.get(self.lookup_kwarg) self.lookup_val = request.GET.get(self.lookup_kwarg)
self.lookup_val2 = request.GET.get(self.lookup_kwarg2) self.lookup_val2 = request.GET.get(self.lookup_kwarg2)
super(BooleanFieldListFilter, self).__init__(field, super(BooleanFieldListFilter, self).__init__(field, request, params, model, model_admin, field_path)
request, params, model, model_admin, field_path)
def expected_parameters(self): def expected_parameters(self):
return [self.lookup_kwarg, self.lookup_kwarg2] return [self.lookup_kwarg, self.lookup_kwarg2]
@ -257,8 +257,10 @@ class BooleanFieldListFilter(FieldListFilter):
'display': _('Unknown'), 'display': _('Unknown'),
} }
FieldListFilter.register(lambda f: isinstance(f, FieldListFilter.register(
(models.BooleanField, models.NullBooleanField)), BooleanFieldListFilter) lambda f: isinstance(f, (models.BooleanField, models.NullBooleanField)),
BooleanFieldListFilter
)
class ChoicesFieldListFilter(FieldListFilter): class ChoicesFieldListFilter(FieldListFilter):
@ -290,8 +292,7 @@ FieldListFilter.register(lambda f: bool(f.choices), ChoicesFieldListFilter)
class DateFieldListFilter(FieldListFilter): class DateFieldListFilter(FieldListFilter):
def __init__(self, field, request, params, model, model_admin, field_path): def __init__(self, field, request, params, model, model_admin, field_path):
self.field_generic = '%s__' % field_path self.field_generic = '%s__' % field_path
self.date_params = {k: v for k, v in params.items() self.date_params = {k: v for k, v in params.items() if k.startswith(self.field_generic)}
if k.startswith(self.field_generic)}
now = timezone.now() now = timezone.now()
# When time zone support is enabled, convert "now" to the user's time # When time zone support is enabled, convert "now" to the user's time
@ -387,8 +388,7 @@ class AllValuesFieldListFilter(FieldListFilter):
def choices(self, changelist): def choices(self, changelist):
yield { yield {
'selected': self.lookup_val is None and self.lookup_val_isnull is None, 'selected': self.lookup_val is None and self.lookup_val_isnull is None,
'query_string': changelist.get_query_string({}, 'query_string': changelist.get_query_string({}, [self.lookup_kwarg, self.lookup_kwarg_isnull]),
[self.lookup_kwarg, self.lookup_kwarg_isnull]),
'display': _('All'), 'display': _('All'),
} }
include_none = False include_none = False

View File

@ -10,9 +10,10 @@ class AdminAuthenticationForm(AuthenticationForm):
A custom authentication form used in the admin app. A custom authentication form used in the admin app.
""" """
error_messages = { error_messages = {
'invalid_login': _("Please enter the correct %(username)s and password " 'invalid_login': _(
"for a staff account. Note that both fields may be " "Please enter the correct %(username)s and password for a staff "
"case-sensitive."), "account. Note that both fields may be case-sensitive."
),
} }
required_css_class = 'required' required_css_class = 'required'

View File

@ -25,8 +25,12 @@ ACTION_CHECKBOX_NAME = '_selected_action'
class ActionForm(forms.Form): class ActionForm(forms.Form):
action = forms.ChoiceField(label=_('Action:')) action = forms.ChoiceField(label=_('Action:'))
select_across = forms.BooleanField(label='', required=False, initial=0, select_across = forms.BooleanField(
widget=forms.HiddenInput({'class': 'select-across'})) label='',
required=False,
initial=0,
widget=forms.HiddenInput({'class': 'select-across'}),
)
checkbox = forms.CheckboxInput({'class': 'action-select'}, lambda value: False) checkbox = forms.CheckboxInput({'class': 'action-select'}, lambda value: False)
@ -62,7 +66,7 @@ class AdminForm(object):
class Fieldset(object): class Fieldset(object):
def __init__(self, form, name=None, readonly_fields=(), fields=(), classes=(), def __init__(self, form, name=None, readonly_fields=(), fields=(), classes=(),
description=None, model_admin=None): description=None, model_admin=None):
self.form = form self.form = form
self.name, self.fields = name, fields self.name, self.fields = name, fields
self.classes = ' '.join(classes) self.classes = ' '.join(classes)
@ -73,9 +77,11 @@ class Fieldset(object):
def _media(self): def _media(self):
if 'collapse' in self.classes: if 'collapse' in self.classes:
extra = '' if settings.DEBUG else '.min' extra = '' if settings.DEBUG else '.min'
js = ['vendor/jquery/jquery%s.js' % extra, js = [
'jquery.init.js', 'vendor/jquery/jquery%s.js' % extra,
'collapse%s.js' % extra] 'jquery.init.js',
'collapse%s.js' % extra,
]
return forms.Media(js=['admin/js/%s' % url for url in js]) return forms.Media(js=['admin/js/%s' % url for url in js])
return forms.Media() return forms.Media()
media = property(_media) media = property(_media)
@ -92,9 +98,10 @@ class Fieldline(object):
self.fields = [field] self.fields = [field]
else: else:
self.fields = field self.fields = field
self.has_visible_field = not all(field in self.form.fields and self.has_visible_field = not all(
self.form.fields[field].widget.is_hidden field in self.form.fields and self.form.fields[field].widget.is_hidden
for field in self.fields) for field in self.fields
)
self.model_admin = model_admin self.model_admin = model_admin
if readonly_fields is None: if readonly_fields is None:
readonly_fields = () readonly_fields = ()
@ -103,15 +110,15 @@ class Fieldline(object):
def __iter__(self): def __iter__(self):
for i, field in enumerate(self.fields): for i, field in enumerate(self.fields):
if field in self.readonly_fields: if field in self.readonly_fields:
yield AdminReadonlyField(self.form, field, is_first=(i == 0), yield AdminReadonlyField(self.form, field, is_first=(i == 0), model_admin=self.model_admin)
model_admin=self.model_admin)
else: else:
yield AdminField(self.form, field, is_first=(i == 0)) yield AdminField(self.form, field, is_first=(i == 0))
def errors(self): def errors(self):
return mark_safe( return mark_safe(
'\n'.join(self.form[f].errors.as_ul() '\n'.join(
for f in self.fields if f not in self.readonly_fields).strip('\n') self.form[f].errors.as_ul() for f in self.fields if f not in self.readonly_fields
).strip('\n')
) )
@ -135,8 +142,10 @@ class AdminField(object):
attrs = {'class': ' '.join(classes)} if classes else {} attrs = {'class': ' '.join(classes)} if classes else {}
# checkboxes should not have a label suffix as the checkbox appears # checkboxes should not have a label suffix as the checkbox appears
# to the left of the label. # to the left of the label.
return self.field.label_tag(contents=mark_safe(contents), attrs=attrs, return self.field.label_tag(
label_suffix='' if self.is_checkbox else None) contents=mark_safe(contents), attrs=attrs,
label_suffix='' if self.is_checkbox else None,
)
def errors(self): def errors(self):
return mark_safe(self.field.errors.as_ul()) return mark_safe(self.field.errors.as_ul())
@ -225,7 +234,7 @@ class InlineAdminFormSet(object):
A wrapper around an inline formset for use in the admin system. A wrapper around an inline formset for use in the admin system.
""" """
def __init__(self, inline, formset, fieldsets, prepopulated_fields=None, def __init__(self, inline, formset, fieldsets, prepopulated_fields=None,
readonly_fields=None, model_admin=None): readonly_fields=None, model_admin=None):
self.opts = inline self.opts = inline
self.formset = formset self.formset = formset
self.fieldsets = fieldsets self.fieldsets = fieldsets
@ -241,16 +250,21 @@ class InlineAdminFormSet(object):
def __iter__(self): def __iter__(self):
for form, original in zip(self.formset.initial_forms, self.formset.get_queryset()): for form, original in zip(self.formset.initial_forms, self.formset.get_queryset()):
view_on_site_url = self.opts.get_view_on_site_url(original) view_on_site_url = self.opts.get_view_on_site_url(original)
yield InlineAdminForm(self.formset, form, self.fieldsets, yield InlineAdminForm(
self.prepopulated_fields, original, self.readonly_fields, self.formset, form, self.fieldsets, self.prepopulated_fields,
model_admin=self.opts, view_on_site_url=view_on_site_url) original, self.readonly_fields, model_admin=self.opts,
view_on_site_url=view_on_site_url,
)
for form in self.formset.extra_forms: for form in self.formset.extra_forms:
yield InlineAdminForm(self.formset, form, self.fieldsets, yield InlineAdminForm(
self.prepopulated_fields, None, self.readonly_fields, self.formset, form, self.fieldsets, self.prepopulated_fields,
model_admin=self.opts) None, self.readonly_fields, model_admin=self.opts,
yield InlineAdminForm(self.formset, self.formset.empty_form, )
yield InlineAdminForm(
self.formset, self.formset.empty_form,
self.fieldsets, self.prepopulated_fields, None, self.fieldsets, self.prepopulated_fields, None,
self.readonly_fields, model_admin=self.opts) self.readonly_fields, model_admin=self.opts,
)
def fields(self): def fields(self):
fk = getattr(self.formset, "fk", None) fk = getattr(self.formset, "fk", None)
@ -260,9 +274,7 @@ class InlineAdminFormSet(object):
if field_name in self.readonly_fields: if field_name in self.readonly_fields:
yield { yield {
'label': label_for_field(field_name, self.opts.model, self.opts), 'label': label_for_field(field_name, self.opts.model, self.opts),
'widget': { 'widget': {'is_hidden': False},
'is_hidden': False
},
'required': False, 'required': False,
'help_text': help_text_for_field(field_name, self.opts.model), 'help_text': help_text_for_field(field_name, self.opts.model),
} }
@ -304,19 +316,20 @@ class InlineAdminForm(AdminForm):
A wrapper around an inline form for use in the admin system. A wrapper around an inline form for use in the admin system.
""" """
def __init__(self, formset, form, fieldsets, prepopulated_fields, original, def __init__(self, formset, form, fieldsets, prepopulated_fields, original,
readonly_fields=None, model_admin=None, view_on_site_url=None): readonly_fields=None, model_admin=None, view_on_site_url=None):
self.formset = formset self.formset = formset
self.model_admin = model_admin self.model_admin = model_admin
self.original = original self.original = original
self.show_url = original and view_on_site_url is not None self.show_url = original and view_on_site_url is not None
self.absolute_url = view_on_site_url self.absolute_url = view_on_site_url
super(InlineAdminForm, self).__init__(form, fieldsets, prepopulated_fields, super(InlineAdminForm, self).__init__(form, fieldsets, prepopulated_fields, readonly_fields, model_admin)
readonly_fields, model_admin)
def __iter__(self): def __iter__(self):
for name, options in self.fieldsets: for name, options in self.fieldsets:
yield InlineFieldset(self.formset, self.form, name, yield InlineFieldset(
self.readonly_fields, model_admin=self.model_admin, **options) self.formset, self.form, name, self.readonly_fields,
model_admin=self.model_admin, **options
)
def needs_explicit_pk_field(self): def needs_explicit_pk_field(self):
# Auto fields are editable (oddly), so need to check for auto or non-editable pk # Auto fields are editable (oddly), so need to check for auto or non-editable pk
@ -358,8 +371,7 @@ class InlineFieldset(Fieldset):
for field in self.fields: for field in self.fields:
if fk and fk.name == field: if fk and fk.name == field:
continue continue
yield Fieldline(self.form, field, self.readonly_fields, yield Fieldline(self.form, field, self.readonly_fields, model_admin=self.model_admin)
model_admin=self.model_admin)
class AdminErrorList(forms.utils.ErrorList): class AdminErrorList(forms.utils.ErrorList):

View File

@ -214,8 +214,7 @@ class BaseModelAdmin(six.with_metaclass(forms.MediaDefiningClass)):
""" """
db = kwargs.get('using') db = kwargs.get('using')
if db_field.name in self.raw_id_fields: if db_field.name in self.raw_id_fields:
kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.remote_field, kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.remote_field, self.admin_site, using=db)
self.admin_site, using=db)
elif db_field.name in self.radio_fields: elif db_field.name in self.radio_fields:
kwargs['widget'] = widgets.AdminRadioSelect(attrs={ kwargs['widget'] = widgets.AdminRadioSelect(attrs={
'class': get_ul_class(self.radio_fields[db_field.name]), 'class': get_ul_class(self.radio_fields[db_field.name]),
@ -240,8 +239,7 @@ class BaseModelAdmin(six.with_metaclass(forms.MediaDefiningClass)):
db = kwargs.get('using') db = kwargs.get('using')
if db_field.name in self.raw_id_fields: if db_field.name in self.raw_id_fields:
kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.remote_field, kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.remote_field, self.admin_site, using=db)
self.admin_site, using=db)
elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)): elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)):
kwargs['widget'] = widgets.FilteredSelectMultiple( kwargs['widget'] = widgets.FilteredSelectMultiple(
db_field.verbose_name, db_field.verbose_name,
@ -639,8 +637,10 @@ class ModelAdmin(BaseModelAdmin):
try: try:
return modelform_factory(self.model, **defaults) return modelform_factory(self.model, **defaults)
except FieldError as e: except FieldError as e:
raise FieldError('%s. Check fields/fieldsets/exclude attributes of class %s.' raise FieldError(
% (e, self.__class__.__name__)) '%s. Check fields/fieldsets/exclude attributes of class %s.'
% (e, self.__class__.__name__)
)
def get_changelist(self, request, **kwargs): def get_changelist(self, request, **kwargs):
""" """
@ -686,9 +686,10 @@ class ModelAdmin(BaseModelAdmin):
"formfield_callback": partial(self.formfield_for_dbfield, request=request), "formfield_callback": partial(self.formfield_for_dbfield, request=request),
} }
defaults.update(kwargs) defaults.update(kwargs)
return modelformset_factory(self.model, return modelformset_factory(
self.get_changelist_form(request), extra=0, self.model, self.get_changelist_form(request), extra=0,
fields=self.list_editable, **defaults) fields=self.list_editable, **defaults
)
def get_formsets_with_inlines(self, request, obj=None): def get_formsets_with_inlines(self, request, obj=None):
""" """
@ -974,7 +975,6 @@ class ModelAdmin(BaseModelAdmin):
compatibility. For convenience, it accepts the `level` argument as compatibility. For convenience, it accepts the `level` argument as
a string rather than the usual level number. a string rather than the usual level number.
""" """
if not isinstance(level, int): if not isinstance(level, int):
# attempt to get the level if passed a string # attempt to get the level if passed a string
try: try:
@ -982,11 +982,12 @@ class ModelAdmin(BaseModelAdmin):
except AttributeError: except AttributeError:
levels = messages.constants.DEFAULT_TAGS.values() levels = messages.constants.DEFAULT_TAGS.values()
levels_repr = ', '.join('`%s`' % l for l in levels) levels_repr = ', '.join('`%s`' % l for l in levels)
raise ValueError('Bad message level string: `%s`. ' raise ValueError(
'Possible values are: %s' % (level, levels_repr)) 'Bad message level string: `%s`. Possible values are: %s'
% (level, levels_repr)
)
messages.add_message(request, level, message, extra_tags=extra_tags, messages.add_message(request, level, message, extra_tags=extra_tags, fail_silently=fail_silently)
fail_silently=fail_silently)
def save_form(self, request, form, change): def save_form(self, request, form, change):
""" """
@ -1323,23 +1324,26 @@ class ModelAdmin(BaseModelAdmin):
'popup_response_data': popup_response_data, 'popup_response_data': popup_response_data,
}) })
self.message_user(request, self.message_user(
request,
_('The %(name)s "%(obj)s" was deleted successfully.') % { _('The %(name)s "%(obj)s" was deleted successfully.') % {
'name': force_text(opts.verbose_name), 'name': force_text(opts.verbose_name),
'obj': force_text(obj_display), 'obj': force_text(obj_display),
}, messages.SUCCESS) },
messages.SUCCESS,
)
if self.has_change_permission(request, None): if self.has_change_permission(request, None):
post_url = reverse('admin:%s_%s_changelist' % post_url = reverse(
(opts.app_label, opts.model_name), 'admin:%s_%s_changelist' % (opts.app_label, opts.model_name),
current_app=self.admin_site.name) current_app=self.admin_site.name,
)
preserved_filters = self.get_preserved_filters(request) preserved_filters = self.get_preserved_filters(request)
post_url = add_preserved_filters( post_url = add_preserved_filters(
{'preserved_filters': preserved_filters, 'opts': opts}, post_url {'preserved_filters': preserved_filters, 'opts': opts}, post_url
) )
else: else:
post_url = reverse('admin:index', post_url = reverse('admin:index', current_app=self.admin_site.name)
current_app=self.admin_site.name)
return HttpResponseRedirect(post_url) return HttpResponseRedirect(post_url)
def render_delete_form(self, request, context): def render_delete_form(self, request, context):
@ -1353,22 +1357,26 @@ class ModelAdmin(BaseModelAdmin):
media=self.media, media=self.media,
) )
return TemplateResponse(request, return TemplateResponse(
request,
self.delete_confirmation_template or [ self.delete_confirmation_template or [
"admin/{}/{}/delete_confirmation.html".format(app_label, opts.model_name), "admin/{}/{}/delete_confirmation.html".format(app_label, opts.model_name),
"admin/{}/delete_confirmation.html".format(app_label), "admin/{}/delete_confirmation.html".format(app_label),
"admin/delete_confirmation.html" "admin/delete_confirmation.html",
], context) ],
context,
)
def get_inline_formsets(self, request, formsets, inline_instances, def get_inline_formsets(self, request, formsets, inline_instances, obj=None):
obj=None):
inline_admin_formsets = [] inline_admin_formsets = []
for inline, formset in zip(inline_instances, formsets): for inline, formset in zip(inline_instances, formsets):
fieldsets = list(inline.get_fieldsets(request, obj)) fieldsets = list(inline.get_fieldsets(request, obj))
readonly = list(inline.get_readonly_fields(request, obj)) readonly = list(inline.get_readonly_fields(request, obj))
prepopulated = dict(inline.get_prepopulated_fields(request, obj)) prepopulated = dict(inline.get_prepopulated_fields(request, obj))
inline_admin_formset = helpers.InlineAdminFormSet(inline, formset, inline_admin_formset = helpers.InlineAdminFormSet(
fieldsets, prepopulated, readonly, model_admin=self) inline, formset, fieldsets, prepopulated, readonly,
model_admin=self,
)
inline_admin_formsets.append(inline_admin_formset) inline_admin_formsets.append(inline_admin_formset)
return inline_admin_formsets return inline_admin_formsets
@ -1462,7 +1470,8 @@ class ModelAdmin(BaseModelAdmin):
for inline_formset in inline_formsets: for inline_formset in inline_formsets:
media = media + inline_formset.media media = media + inline_formset.media
context = dict(self.admin_site.each_context(request), context = dict(
self.admin_site.each_context(request),
title=(_('Add %s') if add else _('Change %s')) % force_text(opts.verbose_name), title=(_('Add %s') if add else _('Change %s')) % force_text(opts.verbose_name),
adminform=adminForm, adminform=adminForm,
object_id=object_id, object_id=object_id,
@ -1519,11 +1528,12 @@ class ModelAdmin(BaseModelAdmin):
ChangeList = self.get_changelist(request) ChangeList = self.get_changelist(request)
try: try:
cl = ChangeList(request, self.model, list_display, cl = ChangeList(
request, self.model, list_display,
list_display_links, list_filter, self.date_hierarchy, list_display_links, list_filter, self.date_hierarchy,
search_fields, list_select_related, self.list_per_page, search_fields, list_select_related, self.list_per_page,
self.list_max_show_all, self.list_editable, self) self.list_max_show_all, self.list_editable, self,
)
except IncorrectLookupParameters: except IncorrectLookupParameters:
# Wacky lookup parameters were given, so redirect to the main # Wacky lookup parameters were given, so redirect to the main
# changelist page, without parameters, and pass an 'invalid=1' # changelist page, without parameters, and pass an 'invalid=1'
@ -1596,11 +1606,15 @@ class ModelAdmin(BaseModelAdmin):
name = force_text(opts.verbose_name) name = force_text(opts.verbose_name)
else: else:
name = force_text(opts.verbose_name_plural) name = force_text(opts.verbose_name_plural)
msg = ungettext("%(count)s %(name)s was changed successfully.", msg = ungettext(
"%(count)s %(name)s were changed successfully.", "%(count)s %(name)s was changed successfully.",
changecount) % {'count': changecount, "%(count)s %(name)s were changed successfully.",
'name': name, changecount
'obj': force_text(obj)} ) % {
'count': changecount,
'name': name,
'obj': force_text(obj),
}
self.message_user(request, msg, messages.SUCCESS) self.message_user(request, msg, messages.SUCCESS)
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
@ -1623,8 +1637,11 @@ class ModelAdmin(BaseModelAdmin):
else: else:
action_form = None action_form = None
selection_note_all = ungettext('%(total_count)s selected', selection_note_all = ungettext(
'All %(total_count)s selected', cl.result_count) '%(total_count)s selected',
'All %(total_count)s selected',
cl.result_count
)
context = dict( context = dict(
self.admin_site.each_context(request), self.admin_site.each_context(request),
@ -1744,7 +1761,8 @@ class ModelAdmin(BaseModelAdmin):
content_type=get_content_type_for_model(model) content_type=get_content_type_for_model(model)
).select_related().order_by('action_time') ).select_related().order_by('action_time')
context = dict(self.admin_site.each_context(request), context = dict(
self.admin_site.each_context(request),
title=_('Change history: %s') % force_text(obj), title=_('Change history: %s') % force_text(obj),
action_list=action_list, action_list=action_list,
module_name=capfirst(force_text(opts.verbose_name_plural)), module_name=capfirst(force_text(opts.verbose_name_plural)),

View File

@ -84,8 +84,9 @@ class AdminSite(object):
model_or_iterable = [model_or_iterable] model_or_iterable = [model_or_iterable]
for model in model_or_iterable: for model in model_or_iterable:
if model._meta.abstract: if model._meta.abstract:
raise ImproperlyConfigured('The model %s is abstract, so it ' raise ImproperlyConfigured(
'cannot be registered with admin.' % model.__name__) 'The model %s is abstract, so it cannot be registered with admin.' % model.__name__
)
if model in self._registry: if model in self._registry:
raise AlreadyRegistered('The model %s is already registered' % model.__name__) raise AlreadyRegistered('The model %s is already registered' % model.__name__)
@ -362,7 +363,8 @@ class AdminSite(object):
# it cannot import models from other applications at the module level, # it cannot import models from other applications at the module level,
# and django.contrib.admin.forms eventually imports User. # and django.contrib.admin.forms eventually imports User.
from django.contrib.admin.forms import AdminAuthenticationForm from django.contrib.admin.forms import AdminAuthenticationForm
context = dict(self.each_context(request), context = dict(
self.each_context(request),
title=_('Log in'), title=_('Log in'),
app_path=request.get_full_path(), app_path=request.get_full_path(),
) )
@ -479,8 +481,7 @@ class AdminSite(object):
request.current_app = self.name request.current_app = self.name
return TemplateResponse(request, self.index_template or return TemplateResponse(request, self.index_template or 'admin/index.html', context)
'admin/index.html', context)
def app_index(self, request, app_label, extra_context=None): def app_index(self, request, app_label, extra_context=None):
app_dict = self._build_app_dict(request, app_label) app_dict = self._build_app_dict(request, app_label)
@ -489,7 +490,8 @@ class AdminSite(object):
# Sort the models alphabetically within each app. # Sort the models alphabetically within each app.
app_dict['models'].sort(key=lambda x: x['name']) app_dict['models'].sort(key=lambda x: x['name'])
app_name = apps.get_app_config(app_label).verbose_name app_name = apps.get_app_config(app_label).verbose_name
context = dict(self.each_context(request), context = dict(
self.each_context(request),
title=_('%(app)s administration') % {'app': app_name}, title=_('%(app)s administration') % {'app': app_name},
app_list=[app_dict], app_list=[app_dict],
app_label=app_label, app_label=app_label,

View File

@ -36,8 +36,8 @@ IGNORED_PARAMS = (
class ChangeList(object): class ChangeList(object):
def __init__(self, request, model, list_display, list_display_links, def __init__(self, request, model, list_display, list_display_links,
list_filter, date_hierarchy, search_fields, list_select_related, list_filter, date_hierarchy, search_fields, list_select_related,
list_per_page, list_max_show_all, list_editable, model_admin): list_per_page, list_max_show_all, list_editable, model_admin):
self.model = model self.model = model
self.opts = model._meta self.opts = model._meta
self.lookup_opts = self.opts self.lookup_opts = self.opts
@ -111,8 +111,7 @@ class ChangeList(object):
for list_filter in self.list_filter: for list_filter in self.list_filter:
if callable(list_filter): if callable(list_filter):
# This is simply a custom list filter class. # This is simply a custom list filter class.
spec = list_filter(request, lookup_params, spec = list_filter(request, lookup_params, self.model, self.model_admin)
self.model, self.model_admin)
else: else:
field_path = None field_path = None
if isinstance(list_filter, (tuple, list)): if isinstance(list_filter, (tuple, list)):
@ -126,12 +125,12 @@ class ChangeList(object):
if not isinstance(field, models.Field): if not isinstance(field, models.Field):
field_path = field field_path = field
field = get_fields_from_path(self.model, field_path)[-1] field = get_fields_from_path(self.model, field_path)[-1]
spec = field_list_filter_class(field, request, lookup_params, spec = field_list_filter_class(
self.model, self.model_admin, field_path=field_path) field, request, lookup_params,
self.model, self.model_admin, field_path=field_path
)
# Check if we need to use distinct() # Check if we need to use distinct()
use_distinct = (use_distinct or use_distinct = use_distinct or lookup_needs_distinct(self.lookup_opts, field_path)
lookup_needs_distinct(self.lookup_opts,
field_path))
if spec and spec.has_output(): if spec and spec.has_output():
filter_specs.append(spec) filter_specs.append(spec)
@ -144,8 +143,7 @@ class ChangeList(object):
try: try:
for key, value in lookup_params.items(): for key, value in lookup_params.items():
lookup_params[key] = prepare_lookup_value(key, value) lookup_params[key] = prepare_lookup_value(key, value)
use_distinct = (use_distinct or use_distinct = use_distinct or lookup_needs_distinct(self.lookup_opts, key)
lookup_needs_distinct(self.lookup_opts, key))
return filter_specs, bool(filter_specs), lookup_params, use_distinct return filter_specs, bool(filter_specs), lookup_params, use_distinct
except FieldDoesNotExist as e: except FieldDoesNotExist as e:
six.reraise(IncorrectLookupParameters, IncorrectLookupParameters(e), sys.exc_info()[2]) six.reraise(IncorrectLookupParameters, IncorrectLookupParameters(e), sys.exc_info()[2])
@ -345,8 +343,7 @@ class ChangeList(object):
qs = qs.order_by(*ordering) qs = qs.order_by(*ordering)
# Apply search results # Apply search results
qs, search_use_distinct = self.model_admin.get_search_results( qs, search_use_distinct = self.model_admin.get_search_results(request, qs, self.query)
request, qs, self.query)
# Remove duplicates from results, if necessary # Remove duplicates from results, if necessary
if filters_use_distinct | search_use_distinct: if filters_use_distinct | search_use_distinct:

View File

@ -106,10 +106,12 @@ class AdminRadioSelect(forms.RadioSelect):
class AdminFileWidget(forms.ClearableFileInput): class AdminFileWidget(forms.ClearableFileInput):
template_with_initial = ('<p class="file-upload">%s</p>' template_with_initial = (
% forms.ClearableFileInput.template_with_initial) '<p class="file-upload">%s</p>' % forms.ClearableFileInput.template_with_initial
template_with_clear = ('<span class="clearable-file-input">%s</span>' )
% forms.ClearableFileInput.template_with_clear) template_with_clear = (
'<span class="clearable-file-input">%s</span>' % forms.ClearableFileInput.template_with_clear
)
def url_params_from_lookup_dict(lookups): def url_params_from_lookup_dict(lookups):
@ -170,8 +172,10 @@ class ForeignKeyRawIdWidget(forms.TextInput):
attrs['class'] = 'vForeignKeyRawIdAdminField' # The JavaScript code looks for this hook. attrs['class'] = 'vForeignKeyRawIdAdminField' # The JavaScript code looks for this hook.
# TODO: "lookup_id_" is hard-coded here. This should instead use # TODO: "lookup_id_" is hard-coded here. This should instead use
# the correct API to determine the ID dynamically. # the correct API to determine the ID dynamically.
extra.append('<a href="%s%s" class="related-lookup" id="lookup_id_%s" title="%s"></a>' % extra.append(
(related_url, url, name, _('Lookup'))) '<a href="%s%s" class="related-lookup" id="lookup_id_%s" title="%s"></a>'
% (related_url, url, name, _('Lookup'))
)
output = [super(ForeignKeyRawIdWidget, self).render(name, value, attrs)] + extra output = [super(ForeignKeyRawIdWidget, self).render(name, value, attrs)] + extra
if value: if value:
output.append(self.label_for_value(value)) output.append(self.label_for_value(value))

View File

@ -82,9 +82,11 @@ def parse_rst(text, default_reference_context, thing_being_parsed=None):
.. default-role:: .. default-role::
""" """
parts = docutils.core.publish_parts(source % text, parts = docutils.core.publish_parts(
source_path=thing_being_parsed, destination_path=None, source % text,
writer_name='html', settings_overrides=overrides) source_path=thing_being_parsed, destination_path=None,
writer_name='html', settings_overrides=overrides,
)
return mark_safe(parts['fragment']) return mark_safe(parts['fragment'])
# #

View File

@ -82,8 +82,7 @@ def authenticate(**credentials):
return user return user
# The credentials supplied are invalid to all backends, fire signal # The credentials supplied are invalid to all backends, fire signal
user_login_failed.send(sender=__name__, user_login_failed.send(sender=__name__, credentials=_clean_credentials(credentials))
credentials=_clean_credentials(credentials))
def login(request, user, backend=None): def login(request, user, backend=None):

View File

@ -183,10 +183,12 @@ class UserAdmin(admin.ModelAdmin):
request.current_app = self.admin_site.name request.current_app = self.admin_site.name
return TemplateResponse(request, return TemplateResponse(
request,
self.change_user_password_template or self.change_user_password_template or
'admin/auth/user/change_password.html', 'admin/auth/user/change_password.html',
context) context,
)
def response_add(self, request, obj, post_url_continue=None): def response_add(self, request, obj, post_url_continue=None):
""" """

View File

@ -12,7 +12,9 @@ class AuthConfig(AppConfig):
verbose_name = _("Authentication and Authorization") verbose_name = _("Authentication and Authorization")
def ready(self): def ready(self):
post_migrate.connect(create_permissions, post_migrate.connect(
dispatch_uid="django.contrib.auth.management.create_permissions") create_permissions,
dispatch_uid="django.contrib.auth.management.create_permissions"
)
checks.register(check_user_model, checks.Tags.models) checks.register(check_user_model, checks.Tags.models)
checks.register(check_models_permissions, checks.Tags.models) checks.register(check_models_permissions, checks.Tags.models)

View File

@ -33,13 +33,13 @@ class ReadOnlyPasswordHashWidget(forms.Widget):
hasher = identify_hasher(encoded) hasher = identify_hasher(encoded)
except ValueError: except ValueError:
summary = mark_safe("<strong>%s</strong>" % ugettext( summary = mark_safe("<strong>%s</strong>" % ugettext(
"Invalid password format or unknown hashing algorithm.")) "Invalid password format or unknown hashing algorithm."
))
else: else:
summary = format_html_join('', summary = format_html_join(
"<strong>{}</strong>: {} ", '', '<strong>{}</strong>: {} ',
((ugettext(key), value) ((ugettext(key), value) for key, value in hasher.safe_summary(encoded).items())
for key, value in hasher.safe_summary(encoded).items()) )
)
return format_html("<div{}>{}</div>", flatatt(final_attrs), summary) return format_html("<div{}>{}</div>", flatatt(final_attrs), summary)
@ -68,13 +68,17 @@ class UserCreationForm(forms.ModelForm):
error_messages = { error_messages = {
'password_mismatch': _("The two password fields didn't match."), 'password_mismatch': _("The two password fields didn't match."),
} }
password1 = forms.CharField(label=_("Password"), password1 = forms.CharField(
label=_("Password"),
strip=False, strip=False,
widget=forms.PasswordInput) widget=forms.PasswordInput,
password2 = forms.CharField(label=_("Password confirmation"), )
password2 = forms.CharField(
label=_("Password confirmation"),
widget=forms.PasswordInput, widget=forms.PasswordInput,
strip=False, strip=False,
help_text=_("Enter the same password as before, for verification.")) help_text=_("Enter the same password as before, for verification."),
)
class Meta: class Meta:
model = User model = User
@ -105,10 +109,14 @@ class UserCreationForm(forms.ModelForm):
class UserChangeForm(forms.ModelForm): class UserChangeForm(forms.ModelForm):
password = ReadOnlyPasswordHashField(label=_("Password"), password = ReadOnlyPasswordHashField(
help_text=_("Raw passwords are not stored, so there is no way to see " label=_("Password"),
"this user's password, but you can change the password " help_text=_(
"using <a href=\"../password/\">this form</a>.")) "Raw passwords are not stored, so there is no way to see this "
"user's password, but you can change the password using "
"<a href=\"../password/\">this form</a>."
),
)
class Meta: class Meta:
model = User model = User
@ -136,11 +144,17 @@ class AuthenticationForm(forms.Form):
max_length=254, max_length=254,
widget=forms.TextInput(attrs={'autofocus': ''}), widget=forms.TextInput(attrs={'autofocus': ''}),
) )
password = forms.CharField(label=_("Password"), strip=False, widget=forms.PasswordInput) password = forms.CharField(
label=_("Password"),
strip=False,
widget=forms.PasswordInput,
)
error_messages = { error_messages = {
'invalid_login': _("Please enter a correct %(username)s and password. " 'invalid_login': _(
"Note that both fields may be case-sensitive."), "Please enter a correct %(username)s and password. Note that both "
"fields may be case-sensitive."
),
'inactive': _("This account is inactive."), 'inactive': _("This account is inactive."),
} }
@ -164,8 +178,7 @@ class AuthenticationForm(forms.Form):
password = self.cleaned_data.get('password') password = self.cleaned_data.get('password')
if username and password: if username and password:
self.user_cache = authenticate(username=username, self.user_cache = authenticate(username=username, password=password)
password=password)
if self.user_cache is None: if self.user_cache is None:
raise forms.ValidationError( raise forms.ValidationError(
self.error_messages['invalid_login'], self.error_messages['invalid_login'],
@ -263,9 +276,10 @@ class PasswordResetForm(forms.Form):
} }
if extra_email_context is not None: if extra_email_context is not None:
context.update(extra_email_context) context.update(extra_email_context)
self.send_mail(subject_template_name, email_template_name, self.send_mail(
context, from_email, user.email, subject_template_name, email_template_name, context, from_email,
html_email_template_name=html_email_template_name) user.email, html_email_template_name=html_email_template_name,
)
class SetPasswordForm(forms.Form): class SetPasswordForm(forms.Form):
@ -276,13 +290,17 @@ class SetPasswordForm(forms.Form):
error_messages = { error_messages = {
'password_mismatch': _("The two password fields didn't match."), 'password_mismatch': _("The two password fields didn't match."),
} }
new_password1 = forms.CharField(label=_("New password"), new_password1 = forms.CharField(
widget=forms.PasswordInput, label=_("New password"),
strip=False, widget=forms.PasswordInput,
help_text=password_validation.password_validators_help_text_html()) strip=False,
new_password2 = forms.CharField(label=_("New password confirmation"), help_text=password_validation.password_validators_help_text_html(),
strip=False, )
widget=forms.PasswordInput) new_password2 = forms.CharField(
label=_("New password confirmation"),
strip=False,
widget=forms.PasswordInput,
)
def __init__(self, user, *args, **kwargs): def __init__(self, user, *args, **kwargs):
self.user = user self.user = user
@ -314,8 +332,7 @@ class PasswordChangeForm(SetPasswordForm):
password. password.
""" """
error_messages = dict(SetPasswordForm.error_messages, **{ error_messages = dict(SetPasswordForm.error_messages, **{
'password_incorrect': _("Your old password was entered incorrectly. " 'password_incorrect': _("Your old password was entered incorrectly. Please enter it again."),
"Please enter it again."),
}) })
old_password = forms.CharField( old_password = forms.CharField(
label=_("Old password"), label=_("Old password"),

View File

@ -30,8 +30,10 @@ def _get_builtin_permissions(opts):
""" """
perms = [] perms = []
for action in opts.default_permissions: for action in opts.default_permissions:
perms.append((get_permission_codename(action, opts), perms.append((
'Can %s %s' % (action, opts.verbose_name_raw))) get_permission_codename(action, opts),
'Can %s %s' % (action, opts.verbose_name_raw)
))
return perms return perms
@ -125,9 +127,11 @@ def get_default_username(check_db=True):
default_username = get_system_username() default_username = get_system_username()
try: try:
default_username = (unicodedata.normalize('NFKD', default_username) default_username = (
.encode('ascii', 'ignore').decode('ascii') unicodedata.normalize('NFKD', default_username)
.replace(' ', '').lower()) .encode('ascii', 'ignore').decode('ascii')
.replace(' ', '').lower()
)
except UnicodeDecodeError: except UnicodeDecodeError:
return '' return ''

View File

@ -22,11 +22,15 @@ class Command(BaseCommand):
return p return p
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument('username', nargs='?', parser.add_argument(
help='Username to change password for; by default, it\'s the current username.') 'username', nargs='?',
parser.add_argument('--database', action='store', dest='database', help='Username to change password for; by default, it\'s the current username.',
)
parser.add_argument(
'--database', action='store', dest='database',
default=DEFAULT_DB_ALIAS, default=DEFAULT_DB_ALIAS,
help='Specifies the database to use. Default is "default".') help='Specifies the database to use. Default is "default".',
)
def handle(self, *args, **options): def handle(self, *args, **options):
if options['username']: if options['username']:

View File

@ -31,22 +31,32 @@ class Command(BaseCommand):
self.username_field = self.UserModel._meta.get_field(self.UserModel.USERNAME_FIELD) self.username_field = self.UserModel._meta.get_field(self.UserModel.USERNAME_FIELD)
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument('--%s' % self.UserModel.USERNAME_FIELD, parser.add_argument(
'--%s' % self.UserModel.USERNAME_FIELD,
dest=self.UserModel.USERNAME_FIELD, default=None, dest=self.UserModel.USERNAME_FIELD, default=None,
help='Specifies the login for the superuser.') help='Specifies the login for the superuser.',
parser.add_argument('--noinput', '--no-input', )
parser.add_argument(
'--noinput', '--no-input',
action='store_false', dest='interactive', default=True, action='store_false', dest='interactive', default=True,
help=('Tells Django to NOT prompt the user for input of any kind. ' help=(
'You must use --%s with --noinput, along with an option for ' 'Tells Django to NOT prompt the user for input of any kind. '
'any other required field. Superusers created with --noinput will ' 'You must use --%s with --noinput, along with an option for '
' not be able to log in until they\'re given a valid password.' % 'any other required field. Superusers created with --noinput will '
self.UserModel.USERNAME_FIELD)) 'not be able to log in until they\'re given a valid password.' %
parser.add_argument('--database', action='store', dest='database', self.UserModel.USERNAME_FIELD
default=DEFAULT_DB_ALIAS, ),
help='Specifies the database to use. Default is "default".') )
parser.add_argument(
'--database', action='store', dest='database',
default=DEFAULT_DB_ALIAS,
help='Specifies the database to use. Default is "default".',
)
for field in self.UserModel.REQUIRED_FIELDS: for field in self.UserModel.REQUIRED_FIELDS:
parser.add_argument('--%s' % field, dest=field, default=None, parser.add_argument(
help='Specifies the %s for the superuser.' % field) '--%s' % field, dest=field, default=None,
help='Specifies the %s for the superuser.' % field,
)
def execute(self, *args, **options): def execute(self, *args, **options):
self.stdin = options.get('stdin', sys.stdin) # Used for testing self.stdin = options.get('stdin', sys.stdin) # Used for testing
@ -67,8 +77,7 @@ class Command(BaseCommand):
if not options['interactive']: if not options['interactive']:
try: try:
if not username: if not username:
raise CommandError("You must use --%s with --noinput." % raise CommandError("You must use --%s with --noinput." % self.UserModel.USERNAME_FIELD)
self.UserModel.USERNAME_FIELD)
username = self.username_field.clean(username, None) username = self.username_field.clean(username, None)
for field_name in self.UserModel.REQUIRED_FIELDS: for field_name in self.UserModel.REQUIRED_FIELDS:

View File

@ -15,10 +15,10 @@ def check_generic_foreign_keys(app_configs=None, **kwargs):
else: else:
models = chain.from_iterable(app_config.get_models() for app_config in app_configs) models = chain.from_iterable(app_config.get_models() for app_config in app_configs)
errors = [] errors = []
fields = (obj fields = (
for model in models obj for model in models for obj in six.itervalues(vars(model))
for obj in six.itervalues(vars(model)) if isinstance(obj, GenericForeignKey)
if isinstance(obj, GenericForeignKey)) )
for field in fields: for field in fields:
errors.extend(field.check()) errors.extend(field.check())
return errors return errors

View File

@ -299,7 +299,7 @@ class GenericRelation(ForeignObject):
rel_class = GenericRel rel_class = GenericRel
def __init__(self, to, object_id_field='object_id', content_type_field='content_type', def __init__(self, to, object_id_field='object_id', content_type_field='content_type',
for_concrete_model=True, related_query_name=None, limit_choices_to=None, **kwargs): for_concrete_model=True, related_query_name=None, limit_choices_to=None, **kwargs):
kwargs['rel'] = self.rel_class( kwargs['rel'] = self.rel_class(
self, to, self, to,
related_query_name=related_query_name, related_query_name=related_query_name,

View File

@ -38,16 +38,11 @@ class BaseGenericInlineFormSet(BaseModelFormSet):
@classmethod @classmethod
def get_default_prefix(cls): def get_default_prefix(cls):
opts = cls.model._meta opts = cls.model._meta
return '-'.join( return '-'.join((opts.app_label, opts.model_name, cls.ct_field.name, cls.ct_fk_field.name))
(opts.app_label, opts.model_name,
cls.ct_field.name, cls.ct_fk_field.name)
)
def save_new(self, form, commit=True): def save_new(self, form, commit=True):
setattr(form.instance, self.ct_field.get_attname(), setattr(form.instance, self.ct_field.get_attname(), ContentType.objects.get_for_model(self.instance).pk)
ContentType.objects.get_for_model(self.instance).pk) setattr(form.instance, self.ct_fk_field.get_attname(), self.instance.pk)
setattr(form.instance, self.ct_fk_field.get_attname(),
self.instance.pk)
return form.save(commit=commit) return form.save(commit=commit)
@ -76,13 +71,12 @@ def generic_inlineformset_factory(model, form=ModelForm,
exclude.extend([ct_field.name, fk_field.name]) exclude.extend([ct_field.name, fk_field.name])
else: else:
exclude = [ct_field.name, fk_field.name] exclude = [ct_field.name, fk_field.name]
FormSet = modelformset_factory(model, form=form, FormSet = modelformset_factory(
formfield_callback=formfield_callback, model, form=form, formfield_callback=formfield_callback,
formset=formset, formset=formset, extra=extra, can_delete=can_delete,
extra=extra, can_delete=can_delete, can_order=can_order, can_order=can_order, fields=fields, exclude=exclude, max_num=max_num,
fields=fields, exclude=exclude, max_num=max_num, validate_max=validate_max, min_num=min_num, validate_min=validate_min,
validate_max=validate_max, min_num=min_num, )
validate_min=validate_min)
FormSet.ct_field = ct_field FormSet.ct_field = ct_field
FormSet.ct_fk_field = fk_field FormSet.ct_fk_field = fk_field
FormSet.for_concrete_model = for_concrete_model FormSet.for_concrete_model = for_concrete_model

View File

@ -22,9 +22,11 @@ class FlatPage(models.Model):
"the system will use 'flatpages/default.html'." "the system will use 'flatpages/default.html'."
), ),
) )
registration_required = models.BooleanField(_('registration required'), registration_required = models.BooleanField(
_('registration required'),
help_text=_("If this is checked, only logged-in users will be able to view the page."), help_text=_("If this is checked, only logged-in users will be able to view the page."),
default=False) default=False,
)
sites = models.ManyToManyField(Site, verbose_name=_('sites')) sites = models.ManyToManyField(Site, verbose_name=_('sites'))
class Meta: class Meta:

View File

@ -34,13 +34,11 @@ def flatpage(request, url):
url = '/' + url url = '/' + url
site_id = get_current_site(request).id site_id = get_current_site(request).id
try: try:
f = get_object_or_404(FlatPage, f = get_object_or_404(FlatPage, url=url, sites=site_id)
url=url, sites=site_id)
except Http404: except Http404:
if not url.endswith('/') and settings.APPEND_SLASH: if not url.endswith('/') and settings.APPEND_SLASH:
url += '/' url += '/'
f = get_object_or_404(FlatPage, f = get_object_or_404(FlatPage, url=url, sites=site_id)
url=url, sites=site_id)
return HttpResponsePermanentRedirect('%s/' % request.path) return HttpResponsePermanentRedirect('%s/' % request.path)
else: else:
raise raise

View File

@ -26,8 +26,7 @@ elif os.name == 'nt':
lib_names = ['gdal111', 'gdal110', 'gdal19', 'gdal18', 'gdal17'] lib_names = ['gdal111', 'gdal110', 'gdal19', 'gdal18', 'gdal17']
elif os.name == 'posix': elif os.name == 'posix':
# *NIX library names. # *NIX library names.
lib_names = ['gdal', 'GDAL', 'gdal1.11.0', 'gdal1.10.0', 'gdal1.9.0', lib_names = ['gdal', 'GDAL', 'gdal1.11.0', 'gdal1.10.0', 'gdal1.9.0', 'gdal1.8.0', 'gdal1.7.0']
'gdal1.8.0', 'gdal1.7.0']
else: else:
raise GDALException('Unsupported OS "%s"' % os.name) raise GDALException('Unsupported OS "%s"' % os.name)
@ -40,9 +39,10 @@ if lib_names:
break break
if lib_path is None: if lib_path is None:
raise GDALException('Could not find the GDAL library (tried "%s"). ' raise GDALException(
'Try setting GDAL_LIBRARY_PATH in your settings.' % 'Could not find the GDAL library (tried "%s"). Try setting '
'", "'.join(lib_names)) 'GDAL_LIBRARY_PATH in your settings.' % '", "'.join(lib_names)
)
# This loads the GDAL/OGR C library # This loads the GDAL/OGR C library
lgdal = CDLL(lib_path) lgdal = CDLL(lib_path)

View File

@ -42,7 +42,8 @@ reset_reading = void_output(lgdal.OGR_L_ResetReading, [c_void_p], errcheck=False
test_capability = int_output(lgdal.OGR_L_TestCapability, [c_void_p, c_char_p]) test_capability = int_output(lgdal.OGR_L_TestCapability, [c_void_p, c_char_p])
get_spatial_filter = geom_output(lgdal.OGR_L_GetSpatialFilter, [c_void_p]) get_spatial_filter = geom_output(lgdal.OGR_L_GetSpatialFilter, [c_void_p])
set_spatial_filter = void_output(lgdal.OGR_L_SetSpatialFilter, [c_void_p, c_void_p], errcheck=False) set_spatial_filter = void_output(lgdal.OGR_L_SetSpatialFilter, [c_void_p, c_void_p], errcheck=False)
set_spatial_filter_rect = void_output(lgdal.OGR_L_SetSpatialFilterRect, set_spatial_filter_rect = void_output(
lgdal.OGR_L_SetSpatialFilterRect,
[c_void_p, c_double, c_double, c_double, c_double], errcheck=False [c_void_p, c_double, c_double, c_double, c_double], errcheck=False
) )
@ -61,7 +62,8 @@ get_feat_geom_ref = geom_output(lgdal.OGR_F_GetGeometryRef, [c_void_p])
get_feat_field_count = int_output(lgdal.OGR_F_GetFieldCount, [c_void_p]) get_feat_field_count = int_output(lgdal.OGR_F_GetFieldCount, [c_void_p])
get_feat_field_defn = voidptr_output(lgdal.OGR_F_GetFieldDefnRef, [c_void_p, c_int]) get_feat_field_defn = voidptr_output(lgdal.OGR_F_GetFieldDefnRef, [c_void_p, c_int])
get_fid = int_output(lgdal.OGR_F_GetFID, [c_void_p]) get_fid = int_output(lgdal.OGR_F_GetFID, [c_void_p])
get_field_as_datetime = int_output(lgdal.OGR_F_GetFieldAsDateTime, get_field_as_datetime = int_output(
lgdal.OGR_F_GetFieldAsDateTime,
[c_void_p, c_int, c_int_p, c_int_p, c_int_p, c_int_p, c_int_p, c_int_p] [c_void_p, c_int, c_int_p, c_int_p, c_int_p, c_int_p, c_int_p, c_int_p]
) )
get_field_as_double = double_output(lgdal.OGR_F_GetFieldAsDouble, [c_void_p, c_int]) get_field_as_double = double_output(lgdal.OGR_F_GetFieldAsDouble, [c_void_p, c_int])

View File

@ -112,8 +112,7 @@ def string_output(func, argtypes, offset=-1, str_result=False, decoding=None):
# Dynamically defining our error-checking function with the # Dynamically defining our error-checking function with the
# given offset. # given offset.
def _check_str(result, func, cargs): def _check_str(result, func, cargs):
res = check_string(result, func, cargs, res = check_string(result, func, cargs, offset=offset, str_result=str_result)
offset=offset, str_result=str_result)
if res and decoding: if res and decoding:
res = res.decode(decoding) res = res.decode(decoding)
return res return res

View File

@ -82,7 +82,8 @@ get_geom_count = int_output(lgdal.OGR_G_GetGeometryCount, [c_void_p])
get_geom_name = const_string_output(lgdal.OGR_G_GetGeometryName, [c_void_p], decoding='ascii') get_geom_name = const_string_output(lgdal.OGR_G_GetGeometryName, [c_void_p], decoding='ascii')
get_geom_type = int_output(lgdal.OGR_G_GetGeometryType, [c_void_p]) get_geom_type = int_output(lgdal.OGR_G_GetGeometryType, [c_void_p])
get_point_count = int_output(lgdal.OGR_G_GetPointCount, [c_void_p]) get_point_count = int_output(lgdal.OGR_G_GetPointCount, [c_void_p])
get_point = void_output(lgdal.OGR_G_GetPoint, get_point = void_output(
lgdal.OGR_G_GetPoint,
[c_void_p, c_int, POINTER(c_double), POINTER(c_double), POINTER(c_double)], errcheck=False [c_void_p, c_int, POINTER(c_double), POINTER(c_double), POINTER(c_double)], errcheck=False
) )
geom_close_rings = void_output(lgdal.OGR_G_CloseRings, [c_void_p], errcheck=False) geom_close_rings = void_output(lgdal.OGR_G_CloseRings, [c_void_p], errcheck=False)

View File

@ -35,7 +35,8 @@ if GDAL_VERSION >= (2, 0):
else: else:
close_ds = void_output(std_call('GDALClose'), [c_void_p]) close_ds = void_output(std_call('GDALClose'), [c_void_p])
flush_ds = int_output(std_call('GDALFlushCache'), [c_void_p]) flush_ds = int_output(std_call('GDALFlushCache'), [c_void_p])
copy_ds = voidptr_output(std_call('GDALCreateCopy'), copy_ds = voidptr_output(
std_call('GDALCreateCopy'),
[c_void_p, c_char_p, c_void_p, c_int, POINTER(c_char_p), c_void_p, c_void_p] [c_void_p, c_char_p, c_void_p, c_int, POINTER(c_char_p), c_void_p, c_void_p]
) )
add_band_ds = void_output(std_call('GDALAddBand'), [c_void_p, c_int]) add_band_ds = void_output(std_call('GDALAddBand'), [c_void_p, c_int])
@ -51,7 +52,8 @@ get_ds_geotransform = void_output(std_call('GDALGetGeoTransform'), [c_void_p, PO
set_ds_geotransform = void_output(std_call('GDALSetGeoTransform'), [c_void_p, POINTER(c_double * 6)]) set_ds_geotransform = void_output(std_call('GDALSetGeoTransform'), [c_void_p, POINTER(c_double * 6)])
# Raster Band Routines # Raster Band Routines
band_io = void_output(std_call('GDALRasterIO'), band_io = void_output(
std_call('GDALRasterIO'),
[c_void_p, c_int, c_int, c_int, c_int, c_int, c_void_p, c_int, c_int, c_int, c_int, c_int] [c_void_p, c_int, c_int, c_int, c_int, c_int, c_void_p, c_int, c_int, c_int, c_int, c_int]
) )
get_band_xsize = int_output(std_call('GDALGetRasterBandXSize'), [c_void_p]) get_band_xsize = int_output(std_call('GDALGetRasterBandXSize'), [c_void_p])
@ -74,15 +76,18 @@ get_band_statistics = void_output(
], ],
errcheck=False errcheck=False
) )
compute_band_statistics = void_output(std_call('GDALComputeRasterStatistics'), compute_band_statistics = void_output(
std_call('GDALComputeRasterStatistics'),
[c_void_p, c_int, POINTER(c_double), POINTER(c_double), POINTER(c_double), POINTER(c_double), c_void_p, c_void_p], [c_void_p, c_int, POINTER(c_double), POINTER(c_double), POINTER(c_double), POINTER(c_double), c_void_p, c_void_p],
errcheck=False errcheck=False
) )
# Reprojection routine # Reprojection routine
reproject_image = void_output(std_call('GDALReprojectImage'), reproject_image = void_output(
std_call('GDALReprojectImage'),
[c_void_p, c_char_p, c_void_p, c_char_p, c_int, c_double, c_double, c_void_p, c_void_p, c_void_p] [c_void_p, c_char_p, c_void_p, c_char_p, c_int, c_double, c_double, c_void_p, c_void_p, c_void_p]
) )
auto_create_warped_vrt = voidptr_output(std_call('GDALAutoCreateWarpedVRT'), auto_create_warped_vrt = voidptr_output(
std_call('GDALAutoCreateWarpedVRT'),
[c_void_p, c_char_p, c_char_p, c_int, c_double, c_void_p] [c_void_p, c_char_p, c_char_p, c_int, c_double, c_void_p]
) )

View File

@ -56,7 +56,8 @@ angular_units = units_func(lgdal.OSRGetAngularUnits)
# For exporting to WKT, PROJ.4, "Pretty" WKT, and XML. # For exporting to WKT, PROJ.4, "Pretty" WKT, and XML.
to_wkt = string_output(std_call('OSRExportToWkt'), [c_void_p, POINTER(c_char_p)], decoding='ascii') to_wkt = string_output(std_call('OSRExportToWkt'), [c_void_p, POINTER(c_char_p)], decoding='ascii')
to_proj = string_output(std_call('OSRExportToProj4'), [c_void_p, POINTER(c_char_p)], decoding='ascii') to_proj = string_output(std_call('OSRExportToProj4'), [c_void_p, POINTER(c_char_p)], decoding='ascii')
to_pretty_wkt = string_output(std_call('OSRExportToPrettyWkt'), to_pretty_wkt = string_output(
std_call('OSRExportToPrettyWkt'),
[c_void_p, POINTER(c_char_p), c_int], offset=-2, decoding='ascii' [c_void_p, POINTER(c_char_p), c_int], offset=-2, decoding='ascii'
) )

View File

@ -176,6 +176,8 @@ class Polygon(GEOSGeometry):
@property @property
def kml(self): def kml(self):
"Returns the KML representation of this Polygon." "Returns the KML representation of this Polygon."
inner_kml = ''.join("<innerBoundaryIs>%s</innerBoundaryIs>" % self[i + 1].kml inner_kml = ''.join(
for i in range(self.num_interior_rings)) "<innerBoundaryIs>%s</innerBoundaryIs>" % self[i + 1].kml
for i in range(self.num_interior_rings)
)
return "<Polygon><outerBoundaryIs>%s</outerBoundaryIs>%s</Polygon>" % (self[0].kml, inner_kml) return "<Polygon><outerBoundaryIs>%s</outerBoundaryIs>%s</Polygon>" % (self[0].kml, inner_kml)

View File

@ -31,49 +31,70 @@ class ListOptionAction(argparse.Action):
class Command(BaseCommand): class Command(BaseCommand):
help = ('Inspects the given OGR-compatible data source (e.g., a shapefile) and outputs\n' help = (
'a GeoDjango model with the given model name. For example:\n' 'Inspects the given OGR-compatible data source (e.g., a shapefile) and outputs\n'
' ./manage.py ogrinspect zipcode.shp Zipcode') 'a GeoDjango model with the given model name. For example:\n'
' ./manage.py ogrinspect zipcode.shp Zipcode'
)
requires_system_checks = False requires_system_checks = False
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument('data_source', help='Path to the data source.') parser.add_argument('data_source', help='Path to the data source.')
parser.add_argument('model_name', help='Name of the model to create.') parser.add_argument('model_name', help='Name of the model to create.')
parser.add_argument('--blank', dest='blank', parser.add_argument(
'--blank', dest='blank',
action=ListOptionAction, default=False, action=ListOptionAction, default=False,
help='Use a comma separated list of OGR field names to add ' help='Use a comma separated list of OGR field names to add '
'the `blank=True` option to the field definition. Set to `true` ' 'the `blank=True` option to the field definition. Set to `true` '
'to apply to all applicable fields.') 'to apply to all applicable fields.',
parser.add_argument('--decimal', dest='decimal', )
parser.add_argument(
'--decimal', dest='decimal',
action=ListOptionAction, default=False, action=ListOptionAction, default=False,
help='Use a comma separated list of OGR float fields to ' help='Use a comma separated list of OGR float fields to '
'generate `DecimalField` instead of the default ' 'generate `DecimalField` instead of the default '
'`FloatField`. Set to `true` to apply to all OGR float fields.') '`FloatField`. Set to `true` to apply to all OGR float fields.',
parser.add_argument('--geom-name', dest='geom_name', default='geom', )
help='Specifies the model name for the Geometry Field ' parser.add_argument(
'(defaults to `geom`)') '--geom-name', dest='geom_name', default='geom',
parser.add_argument('--layer', dest='layer_key', help='Specifies the model name for the Geometry Field (defaults to `geom`)'
)
parser.add_argument(
'--layer', dest='layer_key',
action=LayerOptionAction, default=0, action=LayerOptionAction, default=0,
help='The key for specifying which layer in the OGR data ' help='The key for specifying which layer in the OGR data '
'source to use. Defaults to 0 (the first layer). May be ' 'source to use. Defaults to 0 (the first layer). May be '
'an integer or a string identifier for the layer.') 'an integer or a string identifier for the layer.',
parser.add_argument('--multi-geom', action='store_true', )
parser.add_argument(
'--multi-geom', action='store_true',
dest='multi_geom', default=False, dest='multi_geom', default=False,
help='Treat the geometry in the data source as a geometry collection.') help='Treat the geometry in the data source as a geometry collection.',
parser.add_argument('--name-field', dest='name_field', )
help='Specifies a field name to return for the `__unicode__`/`__str__` function.') parser.add_argument(
parser.add_argument('--no-imports', action='store_false', dest='imports', default=True, '--name-field', dest='name_field',
help='Do not include `from django.contrib.gis.db import models` statement.') help='Specifies a field name to return for the `__unicode__`/`__str__` function.',
parser.add_argument('--null', dest='null', action=ListOptionAction, default=False, )
parser.add_argument(
'--no-imports', action='store_false', dest='imports', default=True,
help='Do not include `from django.contrib.gis.db import models` statement.',
)
parser.add_argument(
'--null', dest='null', action=ListOptionAction, default=False,
help='Use a comma separated list of OGR field names to add ' help='Use a comma separated list of OGR field names to add '
'the `null=True` option to the field definition. Set to `true` ' 'the `null=True` option to the field definition. Set to `true` '
'to apply to all applicable fields.') 'to apply to all applicable fields.',
parser.add_argument('--srid', dest='srid', )
parser.add_argument(
'--srid', dest='srid',
help='The SRID to use for the Geometry Field. If it can be ' help='The SRID to use for the Geometry Field. If it can be '
'determined, the SRID of the data source is used.') 'determined, the SRID of the data source is used.',
parser.add_argument('--mapping', action='store_true', dest='mapping', )
help='Generate mapping dictionary for use with `LayerMapping`.') parser.add_argument(
'--mapping', action='store_true', dest='mapping',
help='Generate mapping dictionary for use with `LayerMapping`.',
)
def handle(self, *args, **options): def handle(self, *args, **options):
data_source, model_name = options.pop('data_source'), options.pop('model_name') data_source, model_name = options.pop('data_source'), options.pop('model_name')
@ -97,10 +118,11 @@ class Command(BaseCommand):
if options['mapping']: if options['mapping']:
# Constructing the keyword arguments for `mapping`, and # Constructing the keyword arguments for `mapping`, and
# calling it on the data source. # calling it on the data source.
kwargs = {'geom_name': options['geom_name'], kwargs = {
'layer_key': options['layer_key'], 'geom_name': options['geom_name'],
'multi_geom': options['multi_geom'], 'layer_key': options['layer_key'],
} 'multi_geom': options['multi_geom'],
}
mapping_dict = mapping(ds, **kwargs) mapping_dict = mapping(ds, **kwargs)
# This extra legwork is so that the dictionary definition comes # This extra legwork is so that the dictionary definition comes
# out in the same order as the fields in the model definition. # out in the same order as the fields in the model definition.

View File

@ -78,8 +78,7 @@ class MeasureBase(object):
raise AttributeError('Unknown unit type: %s' % name) raise AttributeError('Unknown unit type: %s' % name)
def __repr__(self): def __repr__(self):
return '%s(%s=%s)' % (pretty_name(self), self._default_unit, return '%s(%s=%s)' % (pretty_name(self), self._default_unit, getattr(self, self._default_unit))
getattr(self, self._default_unit))
def __str__(self): def __str__(self):
return '%s %s' % (getattr(self, self._default_unit), self._default_unit) return '%s %s' % (getattr(self, self._default_unit), self._default_unit)
@ -102,8 +101,10 @@ class MeasureBase(object):
def __add__(self, other): def __add__(self, other):
if isinstance(other, self.__class__): if isinstance(other, self.__class__):
return self.__class__(default_unit=self._default_unit, return self.__class__(
**{self.STANDARD_UNIT: (self.standard + other.standard)}) default_unit=self._default_unit,
**{self.STANDARD_UNIT: (self.standard + other.standard)}
)
else: else:
raise TypeError('%(class)s must be added with %(class)s' % {"class": pretty_name(self)}) raise TypeError('%(class)s must be added with %(class)s' % {"class": pretty_name(self)})
@ -116,8 +117,10 @@ class MeasureBase(object):
def __sub__(self, other): def __sub__(self, other):
if isinstance(other, self.__class__): if isinstance(other, self.__class__):
return self.__class__(default_unit=self._default_unit, return self.__class__(
**{self.STANDARD_UNIT: (self.standard - other.standard)}) default_unit=self._default_unit,
**{self.STANDARD_UNIT: (self.standard - other.standard)}
)
else: else:
raise TypeError('%(class)s must be subtracted from %(class)s' % {"class": pretty_name(self)}) raise TypeError('%(class)s must be subtracted from %(class)s' % {"class": pretty_name(self)})
@ -130,8 +133,10 @@ class MeasureBase(object):
def __mul__(self, other): def __mul__(self, other):
if isinstance(other, NUMERIC_TYPES): if isinstance(other, NUMERIC_TYPES):
return self.__class__(default_unit=self._default_unit, return self.__class__(
**{self.STANDARD_UNIT: (self.standard * other)}) default_unit=self._default_unit,
**{self.STANDARD_UNIT: (self.standard * other)}
)
else: else:
raise TypeError('%(class)s must be multiplied with number' % {"class": pretty_name(self)}) raise TypeError('%(class)s must be multiplied with number' % {"class": pretty_name(self)})
@ -149,8 +154,10 @@ class MeasureBase(object):
if isinstance(other, self.__class__): if isinstance(other, self.__class__):
return self.standard / other.standard return self.standard / other.standard
if isinstance(other, NUMERIC_TYPES): if isinstance(other, NUMERIC_TYPES):
return self.__class__(default_unit=self._default_unit, return self.__class__(
**{self.STANDARD_UNIT: (self.standard / other)}) default_unit=self._default_unit,
**{self.STANDARD_UNIT: (self.standard / other)}
)
else: else:
raise TypeError('%(class)s must be divided with number or %(class)s' % {"class": pretty_name(self)}) raise TypeError('%(class)s must be divided with number or %(class)s' % {"class": pretty_name(self)})
@ -300,11 +307,15 @@ class Distance(MeasureBase):
def __mul__(self, other): def __mul__(self, other):
if isinstance(other, self.__class__): if isinstance(other, self.__class__):
return Area(default_unit=AREA_PREFIX + self._default_unit, return Area(
**{AREA_PREFIX + self.STANDARD_UNIT: (self.standard * other.standard)}) default_unit=AREA_PREFIX + self._default_unit,
**{AREA_PREFIX + self.STANDARD_UNIT: (self.standard * other.standard)}
)
elif isinstance(other, NUMERIC_TYPES): elif isinstance(other, NUMERIC_TYPES):
return self.__class__(default_unit=self._default_unit, return self.__class__(
**{self.STANDARD_UNIT: (self.standard * other)}) default_unit=self._default_unit,
**{self.STANDARD_UNIT: (self.standard * other)}
)
else: else:
raise TypeError('%(distance)s must be multiplied with number or %(distance)s' % { raise TypeError('%(distance)s must be multiplied with number or %(distance)s' % {
"distance": pretty_name(self.__class__), "distance": pretty_name(self.__class__),
@ -320,8 +331,10 @@ class Area(MeasureBase):
def __truediv__(self, other): def __truediv__(self, other):
if isinstance(other, NUMERIC_TYPES): if isinstance(other, NUMERIC_TYPES):
return self.__class__(default_unit=self._default_unit, return self.__class__(
**{self.STANDARD_UNIT: (self.standard / other)}) default_unit=self._default_unit,
**{self.STANDARD_UNIT: (self.standard / other)}
)
else: else:
raise TypeError('%(class)s must be divided by a number' % {"class": pretty_name(self)}) raise TypeError('%(class)s must be divided by a number' % {"class": pretty_name(self)})

View File

@ -24,8 +24,10 @@ def compress_kml(kml):
def render_to_kml(*args, **kwargs): def render_to_kml(*args, **kwargs):
"Renders the response as KML (using the correct MIME type)." "Renders the response as KML (using the correct MIME type)."
return HttpResponse(loader.render_to_string(*args, **kwargs), return HttpResponse(
content_type='application/vnd.google-earth.kml+xml') loader.render_to_string(*args, **kwargs),
content_type='application/vnd.google-earth.kml+xml',
)
def render_to_kmz(*args, **kwargs): def render_to_kmz(*args, **kwargs):
@ -33,11 +35,12 @@ def render_to_kmz(*args, **kwargs):
Compresses the KML content and returns as KMZ (using the correct Compresses the KML content and returns as KMZ (using the correct
MIME type). MIME type).
""" """
return HttpResponse(compress_kml(loader.render_to_string(*args, **kwargs)), return HttpResponse(
content_type='application/vnd.google-earth.kmz') compress_kml(loader.render_to_string(*args, **kwargs)),
content_type='application/vnd.google-earth.kmz',
)
def render_to_text(*args, **kwargs): def render_to_text(*args, **kwargs):
"Renders the response using the MIME type for plain text." "Renders the response using the MIME type for plain text."
return HttpResponse(loader.render_to_string(*args, **kwargs), return HttpResponse(loader.render_to_string(*args, **kwargs), content_type='text/plain')
content_type='text/plain')

View File

@ -24,8 +24,10 @@ def add_message(request, level, message, extra_tags='', fail_silently=False):
if hasattr(request, '_messages'): if hasattr(request, '_messages'):
return request._messages.add(level, message, extra_tags) return request._messages.add(level, message, extra_tags)
if not fail_silently: if not fail_silently:
raise MessageFailure('You cannot add messages without installing ' raise MessageFailure(
'django.contrib.messages.middleware.MessageMiddleware') 'You cannot add messages without installing '
'django.contrib.messages.middleware.MessageMiddleware'
)
def get_messages(request): def get_messages(request):

View File

@ -82,13 +82,14 @@ class CookieStorage(BaseStorage):
store, or deletes the cookie. store, or deletes the cookie.
""" """
if encoded_data: if encoded_data:
response.set_cookie(self.cookie_name, encoded_data, response.set_cookie(
self.cookie_name, encoded_data,
domain=settings.SESSION_COOKIE_DOMAIN, domain=settings.SESSION_COOKIE_DOMAIN,
secure=settings.SESSION_COOKIE_SECURE or None, secure=settings.SESSION_COOKIE_SECURE or None,
httponly=settings.SESSION_COOKIE_HTTPONLY or None) httponly=settings.SESSION_COOKIE_HTTPONLY or None,
)
else: else:
response.delete_cookie(self.cookie_name, response.delete_cookie(self.cookie_name, domain=settings.SESSION_COOKIE_DOMAIN)
domain=settings.SESSION_COOKIE_DOMAIN)
def _store(self, messages, response, remove_oldest=True, *args, **kwargs): def _store(self, messages, response, remove_oldest=True, *args, **kwargs):
""" """

View File

@ -44,14 +44,16 @@ class KeysValidator(object):
keys = set(value.keys()) keys = set(value.keys())
missing_keys = self.keys - keys missing_keys = self.keys - keys
if missing_keys: if missing_keys:
raise ValidationError(self.messages['missing_keys'], raise ValidationError(
self.messages['missing_keys'],
code='missing_keys', code='missing_keys',
params={'keys': ', '.join(missing_keys)}, params={'keys': ', '.join(missing_keys)},
) )
if self.strict: if self.strict:
extra_keys = keys - self.keys extra_keys = keys - self.keys
if extra_keys: if extra_keys:
raise ValidationError(self.messages['extra_keys'], raise ValidationError(
self.messages['extra_keys'],
code='extra_keys', code='extra_keys',
params={'keys': ', '.join(extra_keys)}, params={'keys': ', '.join(extra_keys)},
) )

View File

@ -7,10 +7,18 @@ from django.utils.translation import ugettext_lazy as _
@python_2_unicode_compatible @python_2_unicode_compatible
class Redirect(models.Model): class Redirect(models.Model):
site = models.ForeignKey(Site, models.CASCADE, verbose_name=_('site')) site = models.ForeignKey(Site, models.CASCADE, verbose_name=_('site'))
old_path = models.CharField(_('redirect from'), max_length=200, db_index=True, old_path = models.CharField(
help_text=_("This should be an absolute path, excluding the domain name. Example: '/events/search/'.")) _('redirect from'),
new_path = models.CharField(_('redirect to'), max_length=200, blank=True, max_length=200,
help_text=_("This can be either an absolute path (as above) or a full URL starting with 'http://'.")) db_index=True,
help_text=_("This should be an absolute path, excluding the domain name. Example: '/events/search/'."),
)
new_path = models.CharField(
_('redirect to'),
max_length=200,
blank=True,
help_text=_("This can be either an absolute path (as above) or a full URL starting with 'http://'."),
)
class Meta: class Meta:
verbose_name = _('redirect') verbose_name = _('redirect')

View File

@ -110,8 +110,7 @@ class SessionBase(object):
# ValueError, SuspiciousOperation, unpickling exceptions. If any of # ValueError, SuspiciousOperation, unpickling exceptions. If any of
# these happen, just return an empty dictionary (an empty session). # these happen, just return an empty dictionary (an empty session).
if isinstance(e, SuspiciousOperation): if isinstance(e, SuspiciousOperation):
logger = logging.getLogger('django.security.%s' % logger = logging.getLogger('django.security.%s' % e.__class__.__name__)
e.__class__.__name__)
logger.warning(force_text(e)) logger.warning(force_text(e))
return {} return {}

View File

@ -45,12 +45,10 @@ class SessionStore(DBStore):
expire_date__gt=timezone.now() expire_date__gt=timezone.now()
) )
data = self.decode(s.session_data) data = self.decode(s.session_data)
self._cache.set(self.cache_key, data, self._cache.set(self.cache_key, data, self.get_expiry_age(expiry=s.expire_date))
self.get_expiry_age(expiry=s.expire_date))
except (self.model.DoesNotExist, SuspiciousOperation) as e: except (self.model.DoesNotExist, SuspiciousOperation) as e:
if isinstance(e, SuspiciousOperation): if isinstance(e, SuspiciousOperation):
logger = logging.getLogger('django.security.%s' % logger = logging.getLogger('django.security.%s' % e.__class__.__name__)
e.__class__.__name__)
logger.warning(force_text(e)) logger.warning(force_text(e))
self._session_key = None self._session_key = None
data = {} data = {}

View File

@ -37,8 +37,7 @@ class SessionStore(SessionBase):
return self.decode(s.session_data) return self.decode(s.session_data)
except (self.model.DoesNotExist, SuspiciousOperation) as e: except (self.model.DoesNotExist, SuspiciousOperation) as e:
if isinstance(e, SuspiciousOperation): if isinstance(e, SuspiciousOperation):
logger = logging.getLogger('django.security.%s' % logger = logging.getLogger('django.security.%s' % e.__class__.__name__)
e.__class__.__name__)
logger.warning(force_text(e)) logger.warning(force_text(e))
self._session_key = None self._session_key = None
return {} return {}

View File

@ -92,8 +92,7 @@ class SessionStore(SessionBase):
session_data = self.decode(file_data) session_data = self.decode(file_data)
except (EOFError, SuspiciousOperation) as e: except (EOFError, SuspiciousOperation) as e:
if isinstance(e, SuspiciousOperation): if isinstance(e, SuspiciousOperation):
logger = logging.getLogger('django.security.%s' % logger = logging.getLogger('django.security.%s' % e.__class__.__name__)
e.__class__.__name__)
logger.warning(force_text(e)) logger.warning(force_text(e))
self.create() self.create()
@ -160,8 +159,7 @@ class SessionStore(SessionBase):
dir, prefix = os.path.split(session_file_name) dir, prefix = os.path.split(session_file_name)
try: try:
output_file_fd, output_file_name = tempfile.mkstemp(dir=dir, output_file_fd, output_file_name = tempfile.mkstemp(dir=dir, prefix=prefix + '_out_')
prefix=prefix + '_out_')
renamed = False renamed = False
try: try:
try: try:

View File

@ -12,11 +12,13 @@ class SessionStore(SessionBase):
raises BadSignature if signature fails. raises BadSignature if signature fails.
""" """
try: try:
return signing.loads(self.session_key, return signing.loads(
self.session_key,
serializer=self.serializer, serializer=self.serializer,
# This doesn't handle non-default expiry dates, see #19201 # This doesn't handle non-default expiry dates, see #19201
max_age=settings.SESSION_COOKIE_AGE, max_age=settings.SESSION_COOKIE_AGE,
salt='django.contrib.sessions.backends.signed_cookies') salt='django.contrib.sessions.backends.signed_cookies',
)
except Exception: except Exception:
# BadSignature, ValueError, or unpickling exceptions. If any of # BadSignature, ValueError, or unpickling exceptions. If any of
# these happen, reset the session. # these happen, reset the session.
@ -73,9 +75,11 @@ class SessionStore(SessionBase):
session key. session key.
""" """
session_cache = getattr(self, '_session_cache', {}) session_cache = getattr(self, '_session_cache', {})
return signing.dumps(session_cache, compress=True, return signing.dumps(
session_cache, compress=True,
salt='django.contrib.sessions.backends.signed_cookies', salt='django.contrib.sessions.backends.signed_cookies',
serializer=self.serializer) serializer=self.serializer,
)
@classmethod @classmethod
def clear_expired(cls): def clear_expired(cls):

View File

@ -33,8 +33,7 @@ class SessionMiddleware(object):
# First check if we need to delete this cookie. # First check if we need to delete this cookie.
# The session should be deleted only if the session is entirely empty # The session should be deleted only if the session is entirely empty
if settings.SESSION_COOKIE_NAME in request.COOKIES and empty: if settings.SESSION_COOKIE_NAME in request.COOKIES and empty:
response.delete_cookie(settings.SESSION_COOKIE_NAME, response.delete_cookie(settings.SESSION_COOKIE_NAME, domain=settings.SESSION_COOKIE_DOMAIN)
domain=settings.SESSION_COOKIE_DOMAIN)
else: else:
if accessed: if accessed:
patch_vary_headers(response, ('Cookie',)) patch_vary_headers(response, ('Cookie',))
@ -56,10 +55,12 @@ class SessionMiddleware(object):
# page will result in a redirect to the login page # page will result in a redirect to the login page
# if required. # if required.
return redirect(request.path) return redirect(request.path)
response.set_cookie(settings.SESSION_COOKIE_NAME, response.set_cookie(
request.session.session_key, max_age=max_age, settings.SESSION_COOKIE_NAME,
expires=expires, domain=settings.SESSION_COOKIE_DOMAIN, request.session.session_key, max_age=max_age,
path=settings.SESSION_COOKIE_PATH, expires=expires, domain=settings.SESSION_COOKIE_DOMAIN,
secure=settings.SESSION_COOKIE_SECURE or None, path=settings.SESSION_COOKIE_PATH,
httponly=settings.SESSION_COOKIE_HTTPONLY or None) secure=settings.SESSION_COOKIE_SECURE or None,
httponly=settings.SESSION_COOKIE_HTTPONLY or None,
)
return response return response

View File

@ -85,8 +85,12 @@ class SiteManager(models.Manager):
@python_2_unicode_compatible @python_2_unicode_compatible
class Site(models.Model): class Site(models.Model):
domain = models.CharField(_('domain name'), max_length=100, domain = models.CharField(
validators=[_simple_domain_name_validator], unique=True) _('domain name'),
max_length=100,
validators=[_simple_domain_name_validator],
unique=True,
)
name = models.CharField(_('display name'), max_length=50) name = models.CharField(_('display name'), max_length=50)
objects = SiteManager() objects = SiteManager()

View File

@ -39,30 +39,43 @@ class Command(BaseCommand):
return True return True
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument('--noinput', '--no-input', parser.add_argument(
'--noinput', '--no-input',
action='store_false', dest='interactive', default=True, action='store_false', dest='interactive', default=True,
help="Do NOT prompt the user for input of any kind.") help="Do NOT prompt the user for input of any kind.",
parser.add_argument('--no-post-process', )
parser.add_argument(
'--no-post-process',
action='store_false', dest='post_process', default=True, action='store_false', dest='post_process', default=True,
help="Do NOT post process collected files.") help="Do NOT post process collected files.",
parser.add_argument('-i', '--ignore', action='append', default=[], )
parser.add_argument(
'-i', '--ignore', action='append', default=[],
dest='ignore_patterns', metavar='PATTERN', dest='ignore_patterns', metavar='PATTERN',
help="Ignore files or directories matching this glob-style " help="Ignore files or directories matching this glob-style "
"pattern. Use multiple times to ignore more.") "pattern. Use multiple times to ignore more.",
parser.add_argument('-n', '--dry-run', )
parser.add_argument(
'-n', '--dry-run',
action='store_true', dest='dry_run', default=False, action='store_true', dest='dry_run', default=False,
help="Do everything except modify the filesystem.") help="Do everything except modify the filesystem.",
parser.add_argument('-c', '--clear', )
parser.add_argument(
'-c', '--clear',
action='store_true', dest='clear', default=False, action='store_true', dest='clear', default=False,
help="Clear the existing files using the storage " help="Clear the existing files using the storage "
"before trying to copy or link the original file.") "before trying to copy or link the original file.",
parser.add_argument('-l', '--link', )
parser.add_argument(
'-l', '--link',
action='store_true', dest='link', default=False, action='store_true', dest='link', default=False,
help="Create a symbolic link to each file instead of copying.") help="Create a symbolic link to each file instead of copying.",
parser.add_argument('--no-default-ignore', action='store_false', )
parser.add_argument(
'--no-default-ignore', action='store_false',
dest='use_default_ignore_patterns', default=True, dest='use_default_ignore_patterns', default=True,
help="Don't ignore the common private glob-style patterns 'CVS', " help="Don't ignore the common private glob-style patterns 'CVS', '.*' and '*~'.",
"'.*' and '*~'.") )
def set_options(self, **options): def set_options(self, **options):
""" """

View File

@ -13,18 +13,21 @@ class Command(LabelCommand):
def add_arguments(self, parser): def add_arguments(self, parser):
super(Command, self).add_arguments(parser) super(Command, self).add_arguments(parser)
parser.add_argument('--first', action='store_false', dest='all', parser.add_argument(
'--first', action='store_false', dest='all',
default=True, default=True,
help="Only return the first match for each static file.") help="Only return the first match for each static file.",
)
def handle_label(self, path, **options): def handle_label(self, path, **options):
verbosity = options['verbosity'] verbosity = options['verbosity']
result = finders.find(path, all=options['all']) result = finders.find(path, all=options['all'])
path = force_text(path) path = force_text(path)
if verbosity >= 2: if verbosity >= 2:
searched_locations = ("\nLooking in the following locations:\n %s" % searched_locations = (
"\n ".join(force_text(location) "\nLooking in the following locations:\n %s" %
for location in finders.searched_locations)) "\n ".join(force_text(location) for location in finders.searched_locations)
)
else: else:
searched_locations = '' searched_locations = ''
if result: if result:

View File

@ -9,10 +9,14 @@ class Command(RunserverCommand):
def add_arguments(self, parser): def add_arguments(self, parser):
super(Command, self).add_arguments(parser) super(Command, self).add_arguments(parser)
parser.add_argument('--nostatic', action="store_false", dest='use_static_handler', default=True, parser.add_argument(
help='Tells Django to NOT automatically serve static files at STATIC_URL.') '--nostatic', action="store_false", dest='use_static_handler', default=True,
parser.add_argument('--insecure', action="store_true", dest='insecure_serving', default=False, help='Tells Django to NOT automatically serve static files at STATIC_URL.',
help='Allows serving static files even if DEBUG is False.') )
parser.add_argument(
'--insecure', action="store_true", dest='insecure_serving', default=False,
help='Allows serving static files even if DEBUG is False.',
)
def get_handler(self, *args, **options): def get_handler(self, *args, **options):
""" """

View File

@ -234,14 +234,16 @@ class BaseCache(object):
cache code. cache code.
""" """
if len(key) > MEMCACHE_MAX_KEY_LENGTH: if len(key) > MEMCACHE_MAX_KEY_LENGTH:
warnings.warn('Cache key will cause errors if used with memcached: ' warnings.warn(
'%r (longer than %s)' % (key, MEMCACHE_MAX_KEY_LENGTH), 'Cache key will cause errors if used with memcached: %r '
CacheKeyWarning) '(longer than %s)' % (key, MEMCACHE_MAX_KEY_LENGTH), CacheKeyWarning
)
for char in key: for char in key:
if ord(char) < 33 or ord(char) == 127: if ord(char) < 33 or ord(char) == 127:
warnings.warn('Cache key contains characters that will cause ' warnings.warn(
'errors if used with memcached: %r' % key, 'Cache key contains characters that will cause errors if '
CacheKeyWarning) 'used with memcached: %r' % key, CacheKeyWarning
)
break break
def incr_version(self, key, delta=1, version=None): def incr_version(self, key, delta=1, version=None):

View File

@ -35,8 +35,7 @@ if os.name == 'nt':
Python 2.6+, or the 'delete', 'buffering', 'encoding', or 'newline' Python 2.6+, or the 'delete', 'buffering', 'encoding', or 'newline'
keyword arguments in Python 3.0+. keyword arguments in Python 3.0+.
""" """
def __init__(self, mode='w+b', bufsize=-1, suffix='', prefix='', def __init__(self, mode='w+b', bufsize=-1, suffix='', prefix='', dir=None):
dir=None):
fd, name = tempfile.mkstemp(suffix=suffix, prefix=prefix, dir=dir) fd, name = tempfile.mkstemp(suffix=suffix, prefix=prefix, dir=dir)
self.name = name self.name = name
self.file = os.fdopen(fd, mode, bufsize) self.file = os.fdopen(fd, mode, bufsize)

View File

@ -62,8 +62,7 @@ class TemporaryUploadedFile(UploadedFile):
""" """
def __init__(self, name, content_type, size, charset, content_type_extra=None): def __init__(self, name, content_type, size, charset, content_type_extra=None):
if settings.FILE_UPLOAD_TEMP_DIR: if settings.FILE_UPLOAD_TEMP_DIR:
file = tempfile.NamedTemporaryFile(suffix='.upload', file = tempfile.NamedTemporaryFile(suffix='.upload', dir=settings.FILE_UPLOAD_TEMP_DIR)
dir=settings.FILE_UPLOAD_TEMP_DIR)
else: else:
file = tempfile.NamedTemporaryFile(suffix='.upload') file = tempfile.NamedTemporaryFile(suffix='.upload')
super(TemporaryUploadedFile, self).__init__(file, name, content_type, size, charset, content_type_extra) super(TemporaryUploadedFile, self).__init__(file, name, content_type, size, charset, content_type_extra)

View File

@ -154,8 +154,10 @@ class BaseHandler(object):
view_name = callback.__name__ view_name = callback.__name__
else: # CBV else: # CBV
view_name = callback.__class__.__name__ + '.__call__' view_name = callback.__class__.__name__ + '.__call__'
raise ValueError("The view %s.%s didn't return an HttpResponse object. It returned None instead." raise ValueError(
% (callback.__module__, view_name)) "The view %s.%s didn't return an HttpResponse object. It "
"returned None instead." % (callback.__module__, view_name)
)
# If the response supports deferred rendering, apply template # If the response supports deferred rendering, apply template
# response middleware and then render the response # response middleware and then render the response
@ -167,7 +169,8 @@ class BaseHandler(object):
raise ValueError( raise ValueError(
"%s.process_template_response didn't return an " "%s.process_template_response didn't return an "
"HttpResponse object. It returned None instead." "HttpResponse object. It returned None instead."
% (middleware_method.__self__.__class__.__name__)) % (middleware_method.__self__.__class__.__name__)
)
try: try:
response = response.render() response = response.render()
except Exception as e: except Exception as e:
@ -176,11 +179,10 @@ class BaseHandler(object):
response_is_rendered = True response_is_rendered = True
except http.Http404 as exc: except http.Http404 as exc:
logger.warning('Not Found: %s', request.path, logger.warning(
extra={ 'Not Found: %s', request.path,
'status_code': 404, extra={'status_code': 404, 'request': request},
'request': request )
})
if settings.DEBUG: if settings.DEBUG:
response = debug.technical_404_response(request, exc) response = debug.technical_404_response(request, exc)
else: else:
@ -189,32 +191,25 @@ class BaseHandler(object):
except PermissionDenied as exc: except PermissionDenied as exc:
logger.warning( logger.warning(
'Forbidden (Permission denied): %s', request.path, 'Forbidden (Permission denied): %s', request.path,
extra={ extra={'status_code': 403, 'request': request},
'status_code': 403, )
'request': request
})
response = self.get_exception_response(request, resolver, 403, exc) response = self.get_exception_response(request, resolver, 403, exc)
except MultiPartParserError as exc: except MultiPartParserError as exc:
logger.warning( logger.warning(
'Bad request (Unable to parse request body): %s', request.path, 'Bad request (Unable to parse request body): %s', request.path,
extra={ extra={'status_code': 400, 'request': request},
'status_code': 400, )
'request': request
})
response = self.get_exception_response(request, resolver, 400, exc) response = self.get_exception_response(request, resolver, 400, exc)
except SuspiciousOperation as exc: except SuspiciousOperation as exc:
# The request logger receives events for any problematic request # The request logger receives events for any problematic request
# The security logger receives events for all SuspiciousOperations # The security logger receives events for all SuspiciousOperations
security_logger = logging.getLogger('django.security.%s' % security_logger = logging.getLogger('django.security.%s' % exc.__class__.__name__)
exc.__class__.__name__)
security_logger.error( security_logger.error(
force_text(exc), force_text(exc),
extra={ extra={'status_code': 400, 'request': request},
'status_code': 400, )
'request': request
})
if settings.DEBUG: if settings.DEBUG:
return debug.technical_500_response(request, *sys.exc_info(), status_code=400) return debug.technical_500_response(request, *sys.exc_info(), status_code=400)
@ -277,12 +272,10 @@ class BaseHandler(object):
if settings.DEBUG_PROPAGATE_EXCEPTIONS: if settings.DEBUG_PROPAGATE_EXCEPTIONS:
raise raise
logger.error('Internal Server Error: %s', request.path, logger.error(
'Internal Server Error: %s', request.path,
exc_info=exc_info, exc_info=exc_info,
extra={ extra={'status_code': 500, 'request': request},
'status_code': 500,
'request': request
}
) )
if settings.DEBUG: if settings.DEBUG:

View File

@ -158,7 +158,8 @@ class WSGIHandler(base.BaseHandler):
try: try:
request = self.request_class(environ) request = self.request_class(environ)
except UnicodeDecodeError: except UnicodeDecodeError:
logger.warning('Bad Request (UnicodeDecodeError)', logger.warning(
'Bad Request (UnicodeDecodeError)',
exc_info=sys.exc_info(), exc_info=sys.exc_info(),
extra={ extra={
'status_code': 400, 'status_code': 400,

View File

@ -50,11 +50,12 @@ def send_mail(subject, message, from_email, recipient_list,
Note: The API for this method is frozen. New code wanting to extend the Note: The API for this method is frozen. New code wanting to extend the
functionality should use the EmailMessage class directly. functionality should use the EmailMessage class directly.
""" """
connection = connection or get_connection(username=auth_user, connection = connection or get_connection(
password=auth_password, username=auth_user,
fail_silently=fail_silently) password=auth_password,
mail = EmailMultiAlternatives(subject, message, from_email, recipient_list, fail_silently=fail_silently,
connection=connection) )
mail = EmailMultiAlternatives(subject, message, from_email, recipient_list, connection=connection)
if html_message: if html_message:
mail.attach_alternative(html_message, 'text/html') mail.attach_alternative(html_message, 'text/html')
@ -75,12 +76,15 @@ def send_mass_mail(datatuple, fail_silently=False, auth_user=None,
Note: The API for this method is frozen. New code wanting to extend the Note: The API for this method is frozen. New code wanting to extend the
functionality should use the EmailMessage class directly. functionality should use the EmailMessage class directly.
""" """
connection = connection or get_connection(username=auth_user, connection = connection or get_connection(
password=auth_password, username=auth_user,
fail_silently=fail_silently) password=auth_password,
messages = [EmailMessage(subject, message, sender, recipient, fail_silently=fail_silently,
connection=connection) )
for subject, message, sender, recipient in datatuple] messages = [
EmailMessage(subject, message, sender, recipient, connection=connection)
for subject, message, sender, recipient in datatuple
]
return connection.send_messages(messages) return connection.send_messages(messages)
@ -89,9 +93,11 @@ def mail_admins(subject, message, fail_silently=False, connection=None,
"""Sends a message to the admins, as defined by the ADMINS setting.""" """Sends a message to the admins, as defined by the ADMINS setting."""
if not settings.ADMINS: if not settings.ADMINS:
return return
mail = EmailMultiAlternatives('%s%s' % (settings.EMAIL_SUBJECT_PREFIX, subject), mail = EmailMultiAlternatives(
message, settings.SERVER_EMAIL, [a[1] for a in settings.ADMINS], '%s%s' % (settings.EMAIL_SUBJECT_PREFIX, subject), message,
connection=connection) settings.SERVER_EMAIL, [a[1] for a in settings.ADMINS],
connection=connection,
)
if html_message: if html_message:
mail.attach_alternative(html_message, 'text/html') mail.attach_alternative(html_message, 'text/html')
mail.send(fail_silently=fail_silently) mail.send(fail_silently=fail_silently)
@ -102,9 +108,11 @@ def mail_managers(subject, message, fail_silently=False, connection=None,
"""Sends a message to the managers, as defined by the MANAGERS setting.""" """Sends a message to the managers, as defined by the MANAGERS setting."""
if not settings.MANAGERS: if not settings.MANAGERS:
return return
mail = EmailMultiAlternatives('%s%s' % (settings.EMAIL_SUBJECT_PREFIX, subject), mail = EmailMultiAlternatives(
message, settings.SERVER_EMAIL, [a[1] for a in settings.MANAGERS], '%s%s' % (settings.EMAIL_SUBJECT_PREFIX, subject), message,
connection=connection) settings.SERVER_EMAIL, [a[1] for a in settings.MANAGERS],
connection=connection,
)
if html_message: if html_message:
mail.attach_alternative(html_message, 'text/html') mail.attach_alternative(html_message, 'text/html')
mail.send(fail_silently=fail_silently) mail.send(fail_silently=fail_silently)

View File

@ -90,8 +90,7 @@ def forbid_multi_line_headers(name, val, encoding):
val.encode('ascii') val.encode('ascii')
except UnicodeEncodeError: except UnicodeEncodeError:
if name.lower() in ADDRESS_HEADERS: if name.lower() in ADDRESS_HEADERS:
val = ', '.join(sanitize_address(addr, encoding) val = ', '.join(sanitize_address(addr, encoding) for addr in getaddresses((val,)))
for addr in getaddresses((val,)))
else: else:
val = Header(val, encoding).encode() val = Header(val, encoding).encode()
else: else:
@ -418,8 +417,8 @@ class EmailMultiAlternatives(EmailMessage):
alternative_subtype = 'alternative' alternative_subtype = 'alternative'
def __init__(self, subject='', body='', from_email=None, to=None, bcc=None, def __init__(self, subject='', body='', from_email=None, to=None, bcc=None,
connection=None, attachments=None, headers=None, alternatives=None, connection=None, attachments=None, headers=None, alternatives=None,
cc=None, reply_to=None): cc=None, reply_to=None):
""" """
Initialize a single email message (which can be sent to multiple Initialize a single email message (which can be sent to multiple
recipients). recipients).

View File

@ -196,8 +196,10 @@ class ManagementUtility(object):
settings.INSTALLED_APPS settings.INSTALLED_APPS
else: else:
sys.stderr.write("No Django settings specified.\n") sys.stderr.write("No Django settings specified.\n")
sys.stderr.write("Unknown command: %r\nType '%s help' for usage.\n" % sys.stderr.write(
(subcommand, self.prog_name)) "Unknown command: %r\nType '%s help' for usage.\n"
% (subcommand, self.prog_name)
)
sys.exit(1) sys.exit(1)
if isinstance(app_name, BaseCommand): if isinstance(app_name, BaseCommand):
# If the command is already loaded, use it directly. # If the command is already loaded, use it directly.

View File

@ -241,25 +241,33 @@ class BaseCommand(object):
Create and return the ``ArgumentParser`` which will be used to Create and return the ``ArgumentParser`` which will be used to
parse the arguments to this command. parse the arguments to this command.
""" """
parser = CommandParser(self, prog="%s %s" % (os.path.basename(prog_name), subcommand), parser = CommandParser(
description=self.help or None) self, prog="%s %s" % (os.path.basename(prog_name), subcommand),
description=self.help or None,
)
parser.add_argument('--version', action='version', version=self.get_version()) parser.add_argument('--version', action='version', version=self.get_version())
parser.add_argument('-v', '--verbosity', action='store', dest='verbosity', default=1, parser.add_argument(
'-v', '--verbosity', action='store', dest='verbosity', default=1,
type=int, choices=[0, 1, 2, 3], type=int, choices=[0, 1, 2, 3],
help='Verbosity level; 0=minimal output, 1=normal output, 2=verbose output, 3=very verbose output') help='Verbosity level; 0=minimal output, 1=normal output, 2=verbose output, 3=very verbose output',
parser.add_argument('--settings', )
parser.add_argument(
'--settings',
help=( help=(
'The Python path to a settings module, e.g. ' 'The Python path to a settings module, e.g. '
'"myproject.settings.main". If this isn\'t provided, the ' '"myproject.settings.main". If this isn\'t provided, the '
'DJANGO_SETTINGS_MODULE environment variable will be used.' 'DJANGO_SETTINGS_MODULE environment variable will be used.'
), ),
) )
parser.add_argument('--pythonpath', parser.add_argument(
help='A directory to add to the Python path, e.g. "/home/djangoprojects/myproject".') '--pythonpath',
parser.add_argument('--traceback', action='store_true', help='A directory to add to the Python path, e.g. "/home/djangoprojects/myproject".',
help='Raise on CommandError exceptions') )
parser.add_argument('--no-color', action='store_true', dest='no_color', default=False, parser.add_argument('--traceback', action='store_true', help='Raise on CommandError exceptions')
help="Don't colorize the command output.") parser.add_argument(
'--no-color', action='store_true', dest='no_color', default=False,
help="Don't colorize the command output.",
)
self.add_arguments(parser) self.add_arguments(parser)
return parser return parser
@ -478,8 +486,7 @@ class AppCommand(BaseCommand):
missing_args_message = "Enter at least one application label." missing_args_message = "Enter at least one application label."
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument('args', metavar='app_label', nargs='+', parser.add_argument('args', metavar='app_label', nargs='+', help='One or more application label.')
help='One or more application label.')
def handle(self, *app_labels, **options): def handle(self, *app_labels, **options):
from django.apps import apps from django.apps import apps

View File

@ -14,12 +14,18 @@ class Command(BaseCommand):
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument('args', metavar='app_label', nargs='*') parser.add_argument('args', metavar='app_label', nargs='*')
parser.add_argument('--tag', '-t', action='append', dest='tags', parser.add_argument(
help='Run only checks labeled with given tag.') '--tag', '-t', action='append', dest='tags',
parser.add_argument('--list-tags', action='store_true', dest='list_tags', help='Run only checks labeled with given tag.',
help='List available tags.') )
parser.add_argument('--deploy', action='store_true', dest='deploy', parser.add_argument(
help='Check deployment settings.') '--list-tags', action='store_true', dest='list_tags',
help='List available tags.',
)
parser.add_argument(
'--deploy', action='store_true', dest='deploy',
help='Check deployment settings.',
)
parser.add_argument( parser.add_argument(
'--fail-level', '--fail-level',
default='ERROR', default='ERROR',

View File

@ -36,13 +36,19 @@ class Command(BaseCommand):
program_options = ['--check-format'] program_options = ['--check-format']
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument('--locale', '-l', dest='locale', action='append', default=[], parser.add_argument(
'--locale', '-l', dest='locale', action='append', default=[],
help='Locale(s) to process (e.g. de_AT). Default is to process all. ' help='Locale(s) to process (e.g. de_AT). Default is to process all. '
'Can be used multiple times.') 'Can be used multiple times.',
parser.add_argument('--exclude', '-x', dest='exclude', action='append', default=[], )
help='Locales to exclude. Default is none. Can be used multiple times.') parser.add_argument(
parser.add_argument('--use-fuzzy', '-f', dest='fuzzy', action='store_true', default=False, '--exclude', '-x', dest='exclude', action='append', default=[],
help='Use fuzzy translations.') help='Locales to exclude. Default is none. Can be used multiple times.',
)
parser.add_argument(
'--use-fuzzy', '-f', dest='fuzzy', action='store_true', default=False,
help='Use fuzzy translations.',
)
def handle(self, **options): def handle(self, **options):
locale = options['locale'] locale = options['locale']
@ -116,8 +122,9 @@ class Command(BaseCommand):
"mo files will not be updated/created." % dirpath) "mo files will not be updated/created." % dirpath)
return return
args = [self.program] + self.program_options + ['-o', args = [self.program] + self.program_options + [
npath(base_path + '.mo'), npath(base_path + '.po')] '-o', npath(base_path + '.mo'), npath(base_path + '.po')
]
output, errors, status = popen_wrapper(args) output, errors, status = popen_wrapper(args)
if status: if status:
if errors: if errors:

View File

@ -15,16 +15,20 @@ class Command(BaseCommand):
requires_system_checks = False requires_system_checks = False
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument('args', metavar='table_name', nargs='*', parser.add_argument(
help='Optional table names. Otherwise, settings.CACHES is used to ' 'args', metavar='table_name', nargs='*',
'find cache tables.') help='Optional table names. Otherwise, settings.CACHES is used to find cache tables.',
parser.add_argument('--database', action='store', dest='database', )
parser.add_argument(
'--database', action='store', dest='database',
default=DEFAULT_DB_ALIAS, default=DEFAULT_DB_ALIAS,
help='Nominates a database onto which the cache tables will be ' help='Nominates a database onto which the cache tables will be '
'installed. Defaults to the "default" database.') 'installed. Defaults to the "default" database.',
parser.add_argument('--dry-run', action='store_true', dest='dry_run', )
help='Does not create the table, just prints the SQL that would ' parser.add_argument(
'be run.') '--dry-run', action='store_true', dest='dry_run',
help='Does not create the table, just prints the SQL that would be run.',
)
def handle(self, *tablenames, **options): def handle(self, *tablenames, **options):
db = options['database'] db = options['database']
@ -72,9 +76,10 @@ class Command(BaseCommand):
field_output.append("UNIQUE") field_output.append("UNIQUE")
if f.db_index: if f.db_index:
unique = "UNIQUE " if f.unique else "" unique = "UNIQUE " if f.unique else ""
index_output.append("CREATE %sINDEX %s ON %s (%s);" % index_output.append(
(unique, qn('%s_%s' % (tablename, f.name)), qn(tablename), "CREATE %sINDEX %s ON %s (%s);" %
qn(f.name))) (unique, qn('%s_%s' % (tablename, f.name)), qn(tablename), qn(f.name))
)
table_output.append(" ".join(field_output)) table_output.append(" ".join(field_output))
full_statement = ["CREATE TABLE %s (" % qn(tablename)] full_statement = ["CREATE TABLE %s (" % qn(tablename)]
for i, line in enumerate(table_output): for i, line in enumerate(table_output):
@ -89,8 +94,7 @@ class Command(BaseCommand):
self.stdout.write(statement) self.stdout.write(statement)
return return
with transaction.atomic(using=database, with transaction.atomic(using=database, savepoint=connection.features.can_rollback_ddl):
savepoint=connection.features.can_rollback_ddl):
with connection.cursor() as curs: with connection.cursor() as curs:
try: try:
curs.execute(full_statement) curs.execute(full_statement)

View File

@ -3,15 +3,18 @@ from django.db import DEFAULT_DB_ALIAS, connections
class Command(BaseCommand): class Command(BaseCommand):
help = ("Runs the command-line client for specified database, or the " help = (
"default database if none is provided.") "Runs the command-line client for specified database, or the "
"default database if none is provided."
)
requires_system_checks = False requires_system_checks = False
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument('--database', action='store', dest='database', parser.add_argument(
default=DEFAULT_DB_ALIAS, help='Nominates a database onto which to ' '--database', action='store', dest='database', default=DEFAULT_DB_ALIAS,
'open a shell. Defaults to the "default" database.') help='Nominates a database onto which to open a shell. Defaults to the "default" database.',
)
def handle(self, **options): def handle(self, **options):
connection = connections[options['database']] connection = connections[options['database']]
@ -22,5 +25,7 @@ class Command(BaseCommand):
# isn't installed. There's a possibility OSError would be raised # isn't installed. There's a possibility OSError would be raised
# for some other reason, in which case this error message would be # for some other reason, in which case this error message would be
# inaccurate. Still, this message catches the common case. # inaccurate. Still, this message catches the common case.
raise CommandError('You appear not to have the %r program installed or on your path.' % raise CommandError(
connection.client.executable_name) 'You appear not to have the %r program installed or on your path.' %
connection.client.executable_name
)

View File

@ -14,9 +14,10 @@ class Command(BaseCommand):
requires_system_checks = False requires_system_checks = False
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument('--all', action='store_true', dest='all', default=False, parser.add_argument(
help='Display all settings, regardless of their value. ' '--all', action='store_true', dest='all', default=False,
'Default values are prefixed by "###".') help='Display all settings, regardless of their value. Default values are prefixed by "###".',
)
def handle(self, **options): def handle(self, **options):
# Inspired by Postfix's "postconf -n". # Inspired by Postfix's "postconf -n".

View File

@ -12,37 +12,57 @@ class ProxyModelWarning(Warning):
class Command(BaseCommand): class Command(BaseCommand):
help = ("Output the contents of the database as a fixture of the given " help = (
"format (using each model's default manager unless --all is " "Output the contents of the database as a fixture of the given format "
"specified).") "(using each model's default manager unless --all is specified)."
)
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument('args', metavar='app_label[.ModelName]', nargs='*', parser.add_argument(
help='Restricts dumped data to the specified app_label or app_label.ModelName.') 'args', metavar='app_label[.ModelName]', nargs='*',
parser.add_argument('--format', default='json', dest='format', help='Restricts dumped data to the specified app_label or app_label.ModelName.',
help='Specifies the output serialization format for fixtures.') )
parser.add_argument('--indent', default=None, dest='indent', type=int, parser.add_argument(
help='Specifies the indent level to use when pretty-printing output.') '--format', default='json', dest='format',
parser.add_argument('--database', action='store', dest='database', help='Specifies the output serialization format for fixtures.',
)
parser.add_argument(
'--indent', default=None, dest='indent', type=int,
help='Specifies the indent level to use when pretty-printing output.',
)
parser.add_argument(
'--database', action='store', dest='database',
default=DEFAULT_DB_ALIAS, default=DEFAULT_DB_ALIAS,
help='Nominates a specific database to dump fixtures from. ' help='Nominates a specific database to dump fixtures from. '
'Defaults to the "default" database.') 'Defaults to the "default" database.',
parser.add_argument('-e', '--exclude', dest='exclude', action='append', default=[], )
parser.add_argument(
'-e', '--exclude', dest='exclude', action='append', default=[],
help='An app_label or app_label.ModelName to exclude ' help='An app_label or app_label.ModelName to exclude '
'(use multiple --exclude to exclude multiple apps/models).') '(use multiple --exclude to exclude multiple apps/models).',
parser.add_argument('--natural-foreign', action='store_true', dest='use_natural_foreign_keys', default=False, )
help='Use natural foreign keys if they are available.') parser.add_argument(
parser.add_argument('--natural-primary', action='store_true', dest='use_natural_primary_keys', default=False, '--natural-foreign', action='store_true', dest='use_natural_foreign_keys', default=False,
help='Use natural primary keys if they are available.') help='Use natural foreign keys if they are available.',
parser.add_argument('-a', '--all', action='store_true', dest='use_base_manager', default=False, )
parser.add_argument(
'--natural-primary', action='store_true', dest='use_natural_primary_keys', default=False,
help='Use natural primary keys if they are available.',
)
parser.add_argument(
'-a', '--all', action='store_true', dest='use_base_manager', default=False,
help="Use Django's base manager to dump all models stored in the database, " help="Use Django's base manager to dump all models stored in the database, "
"including those that would otherwise be filtered or modified by a custom manager.") "including those that would otherwise be filtered or modified by a custom manager.",
parser.add_argument('--pks', dest='primary_keys', )
help="Only dump objects with given primary keys. " parser.add_argument(
"Accepts a comma separated list of keys. " '--pks', dest='primary_keys',
"This option will only work when you specify one model.") help="Only dump objects with given primary keys. Accepts a comma-separated "
parser.add_argument('-o', '--output', default=None, dest='output', "list of keys. This option only works when you specify one model.",
help='Specifies file to which the output is written.') )
parser.add_argument(
'-o', '--output', default=None, dest='output',
help='Specifies file to which the output is written.'
)
def handle(self, *app_labels, **options): def handle(self, *app_labels, **options):
format = options['format'] format = options['format']
@ -80,9 +100,10 @@ class Command(BaseCommand):
if len(app_labels) == 0: if len(app_labels) == 0:
if primary_keys: if primary_keys:
raise CommandError("You can only use --pks option with one model") raise CommandError("You can only use --pks option with one model")
app_list = OrderedDict((app_config, None) app_list = OrderedDict(
for app_config in apps.get_app_configs() (app_config, None) for app_config in apps.get_app_configs()
if app_config.models_module is not None and app_config not in excluded_apps) if app_config.models_module is not None and app_config not in excluded_apps
)
else: else:
if len(app_labels) > 1 and primary_keys: if len(app_labels) > 1 and primary_keys:
raise CommandError("You can only use --pks option with one model") raise CommandError("You can only use --pks option with one model")
@ -171,11 +192,13 @@ class Command(BaseCommand):
object_count = sum(get_objects(count_only=True)) object_count = sum(get_objects(count_only=True))
stream = open(output, 'w') if output else None stream = open(output, 'w') if output else None
try: try:
serializers.serialize(format, get_objects(), indent=indent, serializers.serialize(
use_natural_foreign_keys=use_natural_foreign_keys, format, get_objects(), indent=indent,
use_natural_primary_keys=use_natural_primary_keys, use_natural_foreign_keys=use_natural_foreign_keys,
stream=stream or self.stdout, progress_output=progress_output, use_natural_primary_keys=use_natural_primary_keys,
object_count=object_count) stream=stream or self.stdout, progress_output=progress_output,
object_count=object_count,
)
finally: finally:
if stream: if stream:
stream.close() stream.close()

View File

@ -13,16 +13,21 @@ from django.utils.six.moves import input
class Command(BaseCommand): class Command(BaseCommand):
help = ('Removes ALL DATA from the database, including data added during ' help = (
'migrations. Does not achieve a "fresh install" state.') 'Removes ALL DATA from the database, including data added during '
'migrations. Does not achieve a "fresh install" state.'
)
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument('--noinput', '--no-input', parser.add_argument(
'--noinput', '--no-input',
action='store_false', dest='interactive', default=True, action='store_false', dest='interactive', default=True,
help='Tells Django to NOT prompt the user for input of any kind.') help='Tells Django to NOT prompt the user for input of any kind.',
parser.add_argument('--database', action='store', dest='database', )
default=DEFAULT_DB_ALIAS, parser.add_argument(
help='Nominates a database to flush. Defaults to the "default" database.') '--database', action='store', dest='database', default=DEFAULT_DB_ALIAS,
help='Nominates a database to flush. Defaults to the "default" database.',
)
def handle(self, **options): def handle(self, **options):
database = options['database'] database = options['database']

View File

@ -17,11 +17,14 @@ class Command(BaseCommand):
db_module = 'django.db' db_module = 'django.db'
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument('table', action='store', nargs='*', type=str, parser.add_argument(
help='Selects what tables or views should be introspected.') 'table', action='store', nargs='*', type=str,
parser.add_argument('--database', action='store', dest='database', help='Selects what tables or views should be introspected.',
default=DEFAULT_DB_ALIAS, help='Nominates a database to ' )
'introspect. Defaults to using the "default" database.') parser.add_argument(
'--database', action='store', dest='database', default=DEFAULT_DB_ALIAS,
help='Nominates a database to introspect. Defaults to using the "default" database.',
)
def handle(self, **options): def handle(self, **options):
try: try:

View File

@ -32,21 +32,26 @@ except ImportError:
class Command(BaseCommand): class Command(BaseCommand):
help = 'Installs the named fixture(s) in the database.' help = 'Installs the named fixture(s) in the database.'
missing_args_message = ("No database fixture specified. Please provide the " missing_args_message = (
"path of at least one fixture in the command line.") "No database fixture specified. Please provide the path of at least "
"one fixture in the command line."
)
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument('args', metavar='fixture', nargs='+', parser.add_argument('args', metavar='fixture', nargs='+', help='Fixture labels.')
help='Fixture labels.') parser.add_argument(
parser.add_argument('--database', action='store', dest='database', '--database', action='store', dest='database', default=DEFAULT_DB_ALIAS,
default=DEFAULT_DB_ALIAS, help='Nominates a specific database to load ' help='Nominates a specific database to load fixtures into. Defaults to the "default" database.',
'fixtures into. Defaults to the "default" database.') )
parser.add_argument('--app', action='store', dest='app_label', parser.add_argument(
default=None, help='Only look for fixtures in the specified app.') '--app', action='store', dest='app_label', default=None,
parser.add_argument('--ignorenonexistent', '-i', action='store_true', help='Only look for fixtures in the specified app.',
dest='ignore', default=False, )
parser.add_argument(
'--ignorenonexistent', '-i', action='store_true', dest='ignore', default=False,
help='Ignores entries in the serialized data for fields that do not ' help='Ignores entries in the serialized data for fields that do not '
'currently exist on the model.') 'currently exist on the model.',
)
def handle(self, *fixture_labels, **options): def handle(self, *fixture_labels, **options):
@ -120,11 +125,15 @@ class Command(BaseCommand):
if self.verbosity >= 1: if self.verbosity >= 1:
if self.fixture_object_count == self.loaded_object_count: if self.fixture_object_count == self.loaded_object_count:
self.stdout.write("Installed %d object(s) from %d fixture(s)" % self.stdout.write(
(self.loaded_object_count, self.fixture_count)) "Installed %d object(s) from %d fixture(s)"
% (self.loaded_object_count, self.fixture_count)
)
else: else:
self.stdout.write("Installed %d object(s) (of %d) from %d fixture(s)" % self.stdout.write(
(self.loaded_object_count, self.fixture_object_count, self.fixture_count)) "Installed %d object(s) (of %d) from %d fixture(s)"
% (self.loaded_object_count, self.fixture_object_count, self.fixture_count)
)
def load_label(self, fixture_label): def load_label(self, fixture_label):
""" """
@ -140,11 +149,14 @@ class Command(BaseCommand):
objects_in_fixture = 0 objects_in_fixture = 0
loaded_objects_in_fixture = 0 loaded_objects_in_fixture = 0
if self.verbosity >= 2: if self.verbosity >= 2:
self.stdout.write("Installing %s fixture '%s' from %s." % self.stdout.write(
(ser_fmt, fixture_name, humanize(fixture_dir))) "Installing %s fixture '%s' from %s."
% (ser_fmt, fixture_name, humanize(fixture_dir))
)
objects = serializers.deserialize(ser_fmt, fixture, objects = serializers.deserialize(
using=self.using, ignorenonexistent=self.ignore) ser_fmt, fixture, using=self.using, ignorenonexistent=self.ignore,
)
for obj in objects: for obj in objects:
objects_in_fixture += 1 objects_in_fixture += 1
@ -208,8 +220,10 @@ class Command(BaseCommand):
for dir_ in fixture_dirs] for dir_ in fixture_dirs]
fixture_name = os.path.basename(fixture_name) fixture_name = os.path.basename(fixture_name)
suffixes = ('.'.join(ext for ext in combo if ext) suffixes = (
for combo in product(databases, ser_fmts, cmp_fmts)) '.'.join(ext for ext in combo if ext)
for combo in product(databases, ser_fmts, cmp_fmts)
)
targets = set('.'.join((fixture_name, suffix)) for suffix in suffixes) targets = set('.'.join((fixture_name, suffix)) for suffix in suffixes)
fixture_files = [] fixture_files = []

View File

@ -30,8 +30,10 @@ NO_LOCALE_DIR = object()
def check_programs(*programs): def check_programs(*programs):
for program in programs: for program in programs:
if find_command(program) is None: if find_command(program) is None:
raise CommandError("Can't find %s. Make sure you have GNU " raise CommandError(
"gettext tools 0.15 or newer installed." % program) "Can't find %s. Make sure you have GNU gettext tools 0.15 or "
"newer installed." % program
)
@total_ordering @total_ordering
@ -161,11 +163,13 @@ def write_pot_file(potfile, msgs):
class Command(BaseCommand): class Command(BaseCommand):
help = ("Runs over the entire source tree of the current directory and " help = (
"pulls out all strings marked for translation. It creates (or updates) a message " "Runs over the entire source tree of the current directory and "
"file in the conf/locale (in the django tree) or locale (for projects and " "pulls out all strings marked for translation. It creates (or updates) a message "
"applications) directory.\n\nYou must run this command with one of either the " "file in the conf/locale (in the django tree) or locale (for projects and "
"--locale, --exclude or --all options.") "applications) directory.\n\nYou must run this command with one of either the "
"--locale, --exclude, or --all options."
)
translatable_file_class = TranslatableFile translatable_file_class = TranslatableFile
build_file_class = BuildFile build_file_class = BuildFile
@ -179,37 +183,60 @@ class Command(BaseCommand):
xgettext_options = ['--from-code=UTF-8', '--add-comments=Translators'] xgettext_options = ['--from-code=UTF-8', '--add-comments=Translators']
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument('--locale', '-l', default=[], dest='locale', action='append', parser.add_argument(
'--locale', '-l', default=[], dest='locale', action='append',
help='Creates or updates the message files for the given locale(s) (e.g. pt_BR). ' help='Creates or updates the message files for the given locale(s) (e.g. pt_BR). '
'Can be used multiple times.') 'Can be used multiple times.',
parser.add_argument('--exclude', '-x', default=[], dest='exclude', action='append', )
help='Locales to exclude. Default is none. Can be used multiple times.') parser.add_argument(
parser.add_argument('--domain', '-d', default='django', dest='domain', '--exclude', '-x', default=[], dest='exclude', action='append',
help='The domain of the message files (default: "django").') help='Locales to exclude. Default is none. Can be used multiple times.',
parser.add_argument('--all', '-a', action='store_true', dest='all', )
default=False, help='Updates the message files for all existing locales.') parser.add_argument(
parser.add_argument('--extension', '-e', dest='extensions', '--domain', '-d', default='django', dest='domain',
help='The domain of the message files (default: "django").',
)
parser.add_argument(
'--all', '-a', action='store_true', dest='all', default=False,
help='Updates the message files for all existing locales.',
)
parser.add_argument(
'--extension', '-e', dest='extensions', action='append',
help='The file extension(s) to examine (default: "html,txt,py", or "js" ' help='The file extension(s) to examine (default: "html,txt,py", or "js" '
'if the domain is "djangojs"). Separate multiple extensions with ' 'if the domain is "djangojs"). Separate multiple extensions with '
'commas, or use -e multiple times.', 'commas, or use -e multiple times.',
action='append') )
parser.add_argument('--symlinks', '-s', action='store_true', dest='symlinks', parser.add_argument(
default=False, help='Follows symlinks to directories when examining ' '--symlinks', '-s', action='store_true', dest='symlinks', default=False,
'source code and templates for translation strings.') help='Follows symlinks to directories when examining source code '
parser.add_argument('--ignore', '-i', action='append', dest='ignore_patterns', 'and templates for translation strings.',
)
parser.add_argument(
'--ignore', '-i', action='append', dest='ignore_patterns',
default=[], metavar='PATTERN', default=[], metavar='PATTERN',
help='Ignore files or directories matching this glob-style pattern. ' help='Ignore files or directories matching this glob-style pattern. '
'Use multiple times to ignore more.') 'Use multiple times to ignore more.',
parser.add_argument('--no-default-ignore', action='store_false', dest='use_default_ignore_patterns', )
default=True, help="Don't ignore the common glob-style patterns 'CVS', '.*', '*~' and '*.pyc'.") parser.add_argument(
parser.add_argument('--no-wrap', action='store_true', dest='no_wrap', '--no-default-ignore', action='store_false', dest='use_default_ignore_patterns',
default=False, help="Don't break long message lines into several lines.") default=True, help="Don't ignore the common glob-style patterns 'CVS', '.*', '*~' and '*.pyc'.",
parser.add_argument('--no-location', action='store_true', dest='no_location', )
default=False, help="Don't write '#: filename:line' lines.") parser.add_argument(
parser.add_argument('--no-obsolete', action='store_true', dest='no_obsolete', '--no-wrap', action='store_true', dest='no_wrap',
default=False, help="Remove obsolete message strings.") default=False, help="Don't break long message lines into several lines.",
parser.add_argument('--keep-pot', action='store_true', dest='keep_pot', )
default=False, help="Keep .pot file after making messages. Useful when debugging.") parser.add_argument(
'--no-location', action='store_true', dest='no_location',
default=False, help="Don't write '#: filename:line' lines.",
)
parser.add_argument(
'--no-obsolete', action='store_true', dest='no_obsolete',
default=False, help="Remove obsolete message strings.",
)
parser.add_argument(
'--keep-pot', action='store_true', dest='keep_pot',
default=False, help="Keep .pot file after making messages. Useful when debugging.",
)
def handle(self, *args, **options): def handle(self, *args, **options):
locale = options['locale'] locale = options['locale']
@ -256,12 +283,16 @@ class Command(BaseCommand):
self.extensions = handle_extensions(exts) self.extensions = handle_extensions(exts)
if (locale is None and not exclude and not process_all) or self.domain is None: if (locale is None and not exclude and not process_all) or self.domain is None:
raise CommandError("Type '%s help %s' for usage information." % ( raise CommandError(
os.path.basename(sys.argv[0]), sys.argv[1])) "Type '%s help %s' for usage information."
% (os.path.basename(sys.argv[0]), sys.argv[1])
)
if self.verbosity > 1: if self.verbosity > 1:
self.stdout.write('examining files with the extensions: %s\n' self.stdout.write(
% get_text_list(list(self.extensions), 'and')) 'examining files with the extensions: %s\n'
% get_text_list(list(self.extensions), 'and')
)
self.invoked_for_django = False self.invoked_for_django = False
self.locale_paths = [] self.locale_paths = []

View File

@ -24,24 +24,40 @@ class Command(BaseCommand):
help = "Creates new migration(s) for apps." help = "Creates new migration(s) for apps."
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument('args', metavar='app_label', nargs='*', parser.add_argument(
help='Specify the app label(s) to create migrations for.') 'args', metavar='app_label', nargs='*',
parser.add_argument('--dry-run', action='store_true', dest='dry_run', default=False, help='Specify the app label(s) to create migrations for.',
help="Just show what migrations would be made; don't actually write them.") )
parser.add_argument('--merge', action='store_true', dest='merge', default=False, parser.add_argument(
help="Enable fixing of migration conflicts.") '--dry-run', action='store_true', dest='dry_run', default=False,
parser.add_argument('--empty', action='store_true', dest='empty', default=False, help="Just show what migrations would be made; don't actually write them.",
help="Create an empty migration.") )
parser.add_argument('--noinput', '--no-input', parser.add_argument(
'--merge', action='store_true', dest='merge', default=False,
help="Enable fixing of migration conflicts.",
)
parser.add_argument(
'--empty', action='store_true', dest='empty', default=False,
help="Create an empty migration.",
)
parser.add_argument(
'--noinput', '--no-input',
action='store_false', dest='interactive', default=True, action='store_false', dest='interactive', default=True,
help='Tells Django to NOT prompt the user for input of any kind.') help='Tells Django to NOT prompt the user for input of any kind.',
parser.add_argument('-n', '--name', action='store', dest='name', default=None, )
help="Use this name for migration file(s).") parser.add_argument(
parser.add_argument('-e', '--exit', action='store_true', dest='exit_code', default=False, '-n', '--name', action='store', dest='name', default=None,
help="Use this name for migration file(s).",
)
parser.add_argument(
'-e', '--exit', action='store_true', dest='exit_code', default=False,
help='Exit with error code 1 if no changes needing migrations are found. ' help='Exit with error code 1 if no changes needing migrations are found. '
'Deprecated, use the --check option instead.') 'Deprecated, use the --check option instead.',
parser.add_argument('--check', action='store_true', dest='check_changes', )
help='Exit with a non-zero status if model changes are missing migrations.') parser.add_argument(
'--check', action='store_true', dest='check_changes',
help='Exit with a non-zero status if model changes are missing migrations.',
)
def handle(self, *app_labels, **options): def handle(self, *app_labels, **options):
self.verbosity = options['verbosity'] self.verbosity = options['verbosity']

View File

@ -22,28 +22,39 @@ class Command(BaseCommand):
help = "Updates database schema. Manages both apps with migrations and those without." help = "Updates database schema. Manages both apps with migrations and those without."
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument('app_label', nargs='?', parser.add_argument(
help='App label of an application to synchronize the state.') 'app_label', nargs='?',
parser.add_argument('migration_name', nargs='?', help='App label of an application to synchronize the state.',
help=(
'Database state will be brought to the state after that '
'migration. Use the name "zero" to unapply all migrations.'
),
) )
parser.add_argument('--noinput', '--no-input', parser.add_argument(
'migration_name', nargs='?',
help='Database state will be brought to the state after that '
'migration. Use the name "zero" to unapply all migrations.',
)
parser.add_argument(
'--noinput', '--no-input',
action='store_false', dest='interactive', default=True, action='store_false', dest='interactive', default=True,
help='Tells Django to NOT prompt the user for input of any kind.') help='Tells Django to NOT prompt the user for input of any kind.',
parser.add_argument('--database', action='store', dest='database', )
default=DEFAULT_DB_ALIAS, help='Nominates a database to synchronize. ' parser.add_argument(
'Defaults to the "default" database.') '--database', action='store', dest='database',
parser.add_argument('--fake', action='store_true', dest='fake', default=False, default=DEFAULT_DB_ALIAS,
help='Mark migrations as run without actually running them.') help='Nominates a database to synchronize. Defaults to the "default" database.',
parser.add_argument('--fake-initial', action='store_true', dest='fake_initial', default=False, )
parser.add_argument(
'--fake', action='store_true', dest='fake', default=False,
help='Mark migrations as run without actually running them.',
)
parser.add_argument(
'--fake-initial', action='store_true', dest='fake_initial', default=False,
help='Detect if tables already exist and fake-apply initial migrations if so. Make sure ' help='Detect if tables already exist and fake-apply initial migrations if so. Make sure '
'that the current database schema matches your initial migration before using this ' 'that the current database schema matches your initial migration before using this '
'flag. Django will only check for an existing table name.') 'flag. Django will only check for an existing table name.',
parser.add_argument('--run-syncdb', action='store_true', dest='run_syncdb', )
help='Creates tables for apps without migrations.') parser.add_argument(
'--run-syncdb', action='store_true', dest='run_syncdb',
help='Creates tables for apps without migrations.',
)
def handle(self, *args, **options): def handle(self, *args, **options):
@ -238,8 +249,10 @@ class Command(BaseCommand):
opts = model._meta opts = model._meta
converter = connection.introspection.table_name_converter converter = connection.introspection.table_name_converter
# Note that if a model is unmanaged we short-circuit and never try to install it # Note that if a model is unmanaged we short-circuit and never try to install it
return not ((converter(opts.db_table) in tables) or return not (
(opts.auto_created and converter(opts.auto_created._meta.db_table) in tables)) (converter(opts.db_table) in tables) or
(opts.auto_created and converter(opts.auto_created._meta.db_table) in tables)
)
manifest = OrderedDict( manifest = OrderedDict(
(app_name, list(filter(model_installed, model_list))) (app_name, list(filter(model_installed, model_list)))

View File

@ -32,14 +32,22 @@ class Command(BaseCommand):
default_port = '8000' default_port = '8000'
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument('addrport', nargs='?', parser.add_argument(
help='Optional port number, or ipaddr:port') 'addrport', nargs='?',
parser.add_argument('--ipv6', '-6', action='store_true', dest='use_ipv6', default=False, help='Optional port number, or ipaddr:port'
help='Tells Django to use an IPv6 address.') )
parser.add_argument('--nothreading', action='store_false', dest='use_threading', default=True, parser.add_argument(
help='Tells Django to NOT use threading.') '--ipv6', '-6', action='store_true', dest='use_ipv6', default=False,
parser.add_argument('--noreload', action='store_false', dest='use_reloader', default=True, help='Tells Django to use an IPv6 address.',
help='Tells Django to NOT use the auto-reloader.') )
parser.add_argument(
'--nothreading', action='store_false', dest='use_threading', default=True,
help='Tells Django to NOT use threading.',
)
parser.add_argument(
'--noreload', action='store_false', dest='use_reloader', default=True,
help='Tells Django to NOT use the auto-reloader.',
)
def execute(self, *args, **options): def execute(self, *args, **options):
if options['no_color']: if options['no_color']:

View File

@ -10,12 +10,18 @@ class Command(BaseCommand):
missing_args_message = "You must specify some email recipients, or pass the --managers or --admin options." missing_args_message = "You must specify some email recipients, or pass the --managers or --admin options."
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument('email', nargs='*', parser.add_argument(
help='One or more email addresses to send a test email to.') 'email', nargs='*',
parser.add_argument('--managers', action='store_true', dest='managers', default=False, help='One or more email addresses to send a test email to.',
help='Send a test email to the addresses specified in settings.MANAGERS.') )
parser.add_argument('--admins', action='store_true', dest='admins', default=False, parser.add_argument(
help='Send a test email to the addresses specified in settings.ADMINS.') '--managers', action='store_true', dest='managers', default=False,
help='Send a test email to the addresses specified in settings.MANAGERS.',
)
parser.add_argument(
'--admins', action='store_true', dest='admins', default=False,
help='Send a test email to the addresses specified in settings.ADMINS.',
)
def handle(self, *args, **kwargs): def handle(self, *args, **kwargs):
subject = 'Test email from %s on %s' % (socket.gethostname(), timezone.now()) subject = 'Test email from %s on %s' % (socket.gethostname(), timezone.now())

View File

@ -11,15 +11,23 @@ class Command(BaseCommand):
shells = ['ipython', 'bpython', 'python'] shells = ['ipython', 'bpython', 'python']
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument('--plain', action='store_true', dest='plain', parser.add_argument(
'--plain', action='store_true', dest='plain',
help='Tells Django to use plain Python, not IPython or bpython. ' help='Tells Django to use plain Python, not IPython or bpython. '
'Deprecated, use the `-i python` or `--interface python` option instead.') 'Deprecated, use the `-i python` or `--interface python` option instead.',
parser.add_argument('--no-startup', action='store_true', dest='no_startup', )
help='When using plain Python, ignore the PYTHONSTARTUP environment variable and ~/.pythonrc.py script.') parser.add_argument(
parser.add_argument('-i', '--interface', choices=self.shells, dest='interface', '--no-startup', action='store_true', dest='no_startup',
help='Specify an interactive interpreter interface. Available options: "ipython", "bpython", and "python"') help='When using plain Python, ignore the PYTHONSTARTUP environment variable and ~/.pythonrc.py script.',
parser.add_argument('-c', '--command', dest='command', )
help='Instead of opening an interactive shell, run a command as Django and exit.') parser.add_argument(
'-i', '--interface', choices=self.shells, dest='interface',
help='Specify an interactive interpreter interface. Available options: "ipython", "bpython", and "python"',
)
parser.add_argument(
'-c', '--command', dest='command',
help='Instead of opening an interactive shell, run a command as Django and exit.',
)
def _ipython_pre_011(self): def _ipython_pre_011(self):
"""Start IPython pre-0.11""" """Start IPython pre-0.11"""

View File

@ -10,16 +10,24 @@ class Command(BaseCommand):
help = "Shows all available migrations for the current project" help = "Shows all available migrations for the current project"
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument('app_label', nargs='*', parser.add_argument(
help='App labels of applications to limit the output to.') 'app_label', nargs='*',
parser.add_argument('--database', action='store', dest='database', default=DEFAULT_DB_ALIAS, help='App labels of applications to limit the output to.',
help='Nominates a database to synchronize. Defaults to the "default" database.') )
parser.add_argument(
'--database', action='store', dest='database', default=DEFAULT_DB_ALIAS,
help='Nominates a database to synchronize. Defaults to the "default" database.',
)
formats = parser.add_mutually_exclusive_group() formats = parser.add_mutually_exclusive_group()
formats.add_argument('--list', '-l', action='store_const', dest='format', const='list', formats.add_argument(
help='Shows a list of all migrations and which are applied.') '--list', '-l', action='store_const', dest='format', const='list',
formats.add_argument('--plan', '-p', action='store_const', dest='format', const='plan', help='Shows a list of all migrations and which are applied.',
help='Shows all migrations in the order they will be applied.') )
formats.add_argument(
'--plan', '-p', action='store_const', dest='format', const='plan',
help='Shows all migrations in the order they will be applied.',
)
parser.set_defaults(format='list') parser.set_defaults(format='list')

View File

@ -15,9 +15,10 @@ class Command(BaseCommand):
def add_arguments(self, parser): def add_arguments(self, parser):
super(Command, self).add_arguments(parser) super(Command, self).add_arguments(parser)
parser.add_argument('--database', default=DEFAULT_DB_ALIAS, parser.add_argument(
help='Nominates a database to print the SQL for. Defaults to the ' '--database', default=DEFAULT_DB_ALIAS,
'"default" database.') help='Nominates a database to print the SQL for. Defaults to the "default" database.',
)
def handle(self, **options): def handle(self, **options):
return '\n'.join(sql_flush(self.style, connections[options['database']], only_django=True)) return '\n'.join(sql_flush(self.style, connections[options['database']], only_django=True))

View File

@ -13,15 +13,17 @@ class Command(BaseCommand):
output_transaction = True output_transaction = True
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument('app_label', parser.add_argument('app_label', help='App label of the application containing the migration.')
help='App label of the application containing the migration.') parser.add_argument('migration_name', help='Migration name to print the SQL for.')
parser.add_argument('migration_name', parser.add_argument(
help='Migration name to print the SQL for.') '--database', default=DEFAULT_DB_ALIAS,
parser.add_argument('--database', default=DEFAULT_DB_ALIAS, help='Nominates a database to create SQL for. Defaults to the "default" database.',
help='Nominates a database to create SQL for. Defaults to the ' )
'"default" database.') parser.add_argument(
parser.add_argument('--backwards', action='store_true', dest='backwards', '--backwards', action='store_true', dest='backwards',
default=False, help='Creates SQL to unapply the migration, rather than to apply it') default=False,
help='Creates SQL to unapply the migration, rather than to apply it',
)
def execute(self, *args, **options): def execute(self, *args, **options):
# sqlmigrate doesn't support coloring its output but we need to force # sqlmigrate doesn't support coloring its output but we need to force

View File

@ -11,9 +11,10 @@ class Command(AppCommand):
def add_arguments(self, parser): def add_arguments(self, parser):
super(Command, self).add_arguments(parser) super(Command, self).add_arguments(parser)
parser.add_argument('--database', default=DEFAULT_DB_ALIAS, parser.add_argument(
help='Nominates a database to print the SQL for. Defaults to the ' '--database', default=DEFAULT_DB_ALIAS,
'"default" database.') help='Nominates a database to print the SQL for. Defaults to the "default" database.',
)
def handle_app_config(self, app_config, **options): def handle_app_config(self, app_config, **options):
if app_config.models_module is None: if app_config.models_module is None:

View File

@ -13,17 +13,26 @@ class Command(BaseCommand):
help = "Squashes an existing set of migrations (from first until specified) into a single new one." help = "Squashes an existing set of migrations (from first until specified) into a single new one."
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument('app_label', parser.add_argument(
help='App label of the application to squash migrations for.') 'app_label',
parser.add_argument('start_migration_name', default=None, nargs='?', help='App label of the application to squash migrations for.',
help='Migrations will be squashed starting from and including this migration.') )
parser.add_argument('migration_name', parser.add_argument(
help='Migrations will be squashed until and including this migration.') 'start_migration_name', default=None, nargs='?',
parser.add_argument('--no-optimize', action='store_true', dest='no_optimize', default=False, help='Migrations will be squashed starting from and including this migration.',
help='Do not try to optimize the squashed operations.') )
parser.add_argument('--noinput', '--no-input', parser.add_argument(
action='store_false', dest='interactive', default=True, 'migration_name',
help='Tells Django to NOT prompt the user for input of any kind.') help='Migrations will be squashed until and including this migration.',
)
parser.add_argument(
'--no-optimize', action='store_true', dest='no_optimize', default=False,
help='Do not try to optimize the squashed operations.',
)
parser.add_argument(
'--noinput', '--no-input', action='store_false', dest='interactive', default=True,
help='Tells Django to NOT prompt the user for input of any kind.',
)
def handle(self, **options): def handle(self, **options):

View File

@ -5,9 +5,10 @@ from django.core.management.templates import TemplateCommand
class Command(TemplateCommand): class Command(TemplateCommand):
help = ("Creates a Django app directory structure for the given app " help = (
"name in the current directory or optionally in the given " "Creates a Django app directory structure for the given app name in "
"directory.") "the current directory or optionally in the given directory."
)
missing_args_message = "You must provide an application name." missing_args_message = "You must provide an application name."
def handle(self, **options): def handle(self, **options):
@ -20,8 +21,9 @@ class Command(TemplateCommand):
except ImportError: except ImportError:
pass pass
else: else:
raise CommandError("%r conflicts with the name of an existing " raise CommandError(
"Python module and cannot be used as an app " "%r conflicts with the name of an existing Python module and "
"name. Please try another name." % app_name) "cannot be used as an app name. Please try another name." % app_name
)
super(Command, self).handle('app', app_name, target, **options) super(Command, self).handle('app', app_name, target, **options)

View File

@ -7,9 +7,10 @@ from ..utils import get_random_secret_key
class Command(TemplateCommand): class Command(TemplateCommand):
help = ("Creates a Django project directory structure for the given " help = (
"project name in the current directory or optionally in the " "Creates a Django project directory structure for the given project "
"given directory.") "name in the current directory or optionally in the given directory."
)
missing_args_message = "You must provide a project name." missing_args_message = "You must provide a project name."
def handle(self, **options): def handle(self, **options):
@ -22,10 +23,10 @@ class Command(TemplateCommand):
except ImportError: except ImportError:
pass pass
else: else:
raise CommandError("%r conflicts with the name of an existing " raise CommandError(
"Python module and cannot be used as a " "%r conflicts with the name of an existing Python module and "
"project name. Please try another name." % "cannot be used as a project name. Please try another name." % project_name
project_name) )
# Create a random SECRET_KEY to put it in the main settings. # Create a random SECRET_KEY to put it in the main settings.
options['secret_key'] = get_random_secret_key() options['secret_key'] = get_random_secret_key()

View File

@ -29,24 +29,29 @@ class Command(BaseCommand):
super(Command, self).run_from_argv(argv) super(Command, self).run_from_argv(argv)
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument('args', metavar='test_label', nargs='*', parser.add_argument(
help='Module paths to test; can be modulename, modulename.TestCase or modulename.TestCase.test_method') 'args', metavar='test_label', nargs='*',
parser.add_argument('--noinput', '--no-input', help='Module paths to test; can be modulename, modulename.TestCase or modulename.TestCase.test_method'
action='store_false', dest='interactive', default=True, )
help='Tells Django to NOT prompt the user for input of any kind.') parser.add_argument(
parser.add_argument('--failfast', '--noinput', '--no-input', action='store_false', dest='interactive', default=True,
action='store_true', dest='failfast', default=False, help='Tells Django to NOT prompt the user for input of any kind.',
help='Tells Django to stop running the test suite after first ' )
'failed test.') parser.add_argument(
parser.add_argument('--testrunner', '--failfast', action='store_true', dest='failfast', default=False,
action='store', dest='testrunner', help='Tells Django to stop running the test suite after first failed test.',
)
parser.add_argument(
'--testrunner', action='store', dest='testrunner',
help='Tells Django to use specified test runner class instead of ' help='Tells Django to use specified test runner class instead of '
'the one specified by the TEST_RUNNER setting.') 'the one specified by the TEST_RUNNER setting.',
parser.add_argument('--liveserver', )
action='store', dest='liveserver', default=None, parser.add_argument(
'--liveserver', action='store', dest='liveserver', default=None,
help='Overrides the default address where the live server (used ' help='Overrides the default address where the live server (used '
'with LiveServerTestCase) is expected to run from. The ' 'with LiveServerTestCase) is expected to run from. The '
'default value is localhost:8081-8179.') 'default value is localhost:8081-8179.',
)
test_runner_class = get_runner(settings, self.test_runner) test_runner_class = get_runner(settings, self.test_runner)

View File

@ -9,15 +9,22 @@ class Command(BaseCommand):
requires_system_checks = False requires_system_checks = False
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument('args', metavar='fixture', nargs='*', parser.add_argument(
help='Path(s) to fixtures to load before running the server.') 'args', metavar='fixture', nargs='*',
parser.add_argument('--noinput', '--no-input', help='Path(s) to fixtures to load before running the server.',
action='store_false', dest='interactive', default=True, )
help='Tells Django to NOT prompt the user for input of any kind.') parser.add_argument(
parser.add_argument('--addrport', default='', '--noinput', '--no-input', action='store_false', dest='interactive', default=True,
help='Port number or ipaddr:port to run the server on.') help='Tells Django to NOT prompt the user for input of any kind.',
parser.add_argument('--ipv6', '-6', action='store_true', dest='use_ipv6', default=False, )
help='Tells Django to use an IPv6 address.') parser.add_argument(
'--addrport', default='',
help='Port number or ipaddr:port to run the server on.',
)
parser.add_argument(
'--ipv6', '-6', action='store_true', dest='use_ipv6', default=False,
help='Tells Django to use an IPv6 address.',
)
def handle(self, *fixture_labels, **options): def handle(self, *fixture_labels, **options):
verbosity = options['verbosity'] verbosity = options['verbosity']

View File

@ -51,18 +51,20 @@ class TemplateCommand(BaseCommand):
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument('name', help='Name of the application or project.') parser.add_argument('name', help='Name of the application or project.')
parser.add_argument('directory', nargs='?', help='Optional destination directory') parser.add_argument('directory', nargs='?', help='Optional destination directory')
parser.add_argument('--template', parser.add_argument('--template', help='The path or URL to load the template from.')
help='The path or URL to load the template from.') parser.add_argument(
parser.add_argument('--extension', '-e', dest='extensions', '--extension', '-e', dest='extensions',
action='append', default=['py'], action='append', default=['py'],
help='The file extension(s) to render (default: "py"). ' help='The file extension(s) to render (default: "py"). '
'Separate multiple extensions with commas, or use ' 'Separate multiple extensions with commas, or use '
'-e multiple times.') '-e multiple times.'
parser.add_argument('--name', '-n', dest='files', )
parser.add_argument(
'--name', '-n', dest='files',
action='append', default=[], action='append', default=[],
help='The file name(s) to render. ' help='The file name(s) to render. Separate multiple extensions '
'Separate multiple extensions with commas, or use ' 'with commas, or use -n multiple times.'
'-n multiple times.') )
def handle(self, app_or_project, name, target=None, **options): def handle(self, app_or_project, name, target=None, **options):
self.app_or_project = app_or_project self.app_or_project = app_or_project

View File

@ -227,9 +227,12 @@ def sort_dependencies(app_list):
else: else:
skipped.append((model, deps)) skipped.append((model, deps))
if not changed: if not changed:
raise RuntimeError("Can't resolve dependencies for %s in serialized app list." % raise RuntimeError(
', '.join('%s.%s' % (model._meta.app_label, model._meta.object_name) "Can't resolve dependencies for %s in serialized app list." %
for model, deps in sorted(skipped, key=lambda obj: obj[0].__name__)) ', '.join(
'%s.%s' % (model._meta.app_label, model._meta.object_name)
for model, deps in sorted(skipped, key=lambda obj: obj[0].__name__)
)
) )
model_dependencies = skipped model_dependencies = skipped

View File

@ -75,8 +75,9 @@ class Serializer(base.Serializer):
else: else:
def m2m_value(value): def m2m_value(value):
return force_text(value._get_pk_val(), strings_only=True) return force_text(value._get_pk_val(), strings_only=True)
self._current[field.name] = [m2m_value(related) self._current[field.name] = [
for related in getattr(obj, field.name).iterator()] m2m_value(related) for related in getattr(obj, field.name).iterator()
]
def getvalue(self): def getvalue(self):
return self.objects return self.objects

View File

@ -160,8 +160,7 @@ class Signer(object):
'Unsafe Signer separator: %r (cannot be empty or consist of ' 'Unsafe Signer separator: %r (cannot be empty or consist of '
'only A-z0-9-_=)' % sep, 'only A-z0-9-_=)' % sep,
) )
self.salt = force_str(salt or self.salt = force_str(salt or '%s.%s' % (self.__class__.__module__, self.__class__.__name__))
'%s.%s' % (self.__class__.__module__, self.__class__.__name__))
def signature(self, value): def signature(self, value):
signature = base64_hmac(self.salt + 'signer', value, self.key) signature = base64_hmac(self.salt + 'signer', value, self.key)

View File

@ -6,8 +6,7 @@ from django.utils import six
TableInfo = namedtuple('TableInfo', ['name', 'type']) TableInfo = namedtuple('TableInfo', ['name', 'type'])
# Structure returned by the DB-API cursor.description interface (PEP 249) # Structure returned by the DB-API cursor.description interface (PEP 249)
FieldInfo = namedtuple('FieldInfo', FieldInfo = namedtuple('FieldInfo', 'name type_code display_size internal_size precision scale null_ok')
'name type_code display_size internal_size precision scale null_ok')
class BaseDatabaseIntrospection(object): class BaseDatabaseIntrospection(object):

View File

@ -43,8 +43,8 @@ from .validation import DatabaseValidation # isort:skip
# lexicographic ordering in this check because then (1, 2, 1, 'gamma') # lexicographic ordering in this check because then (1, 2, 1, 'gamma')
# inadvertently passes the version test. # inadvertently passes the version test.
version = Database.version_info version = Database.version_info
if (version < (1, 2, 1) or (version[:3] == (1, 2, 1) and if (version < (1, 2, 1) or (
(len(version) < 5 or version[3] != 'final' or version[4] < 2))): version[:3] == (1, 2, 1) and (len(version) < 5 or version[3] != 'final' or version[4] < 2))):
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
raise ImproperlyConfigured("MySQLdb-1.2.1p2 or newer is required; you have %s" % Database.__version__) raise ImproperlyConfigured("MySQLdb-1.2.1p2 or newer is required; you have %s" % Database.__version__)
@ -334,19 +334,27 @@ class DatabaseWrapper(BaseDatabaseWrapper):
continue continue
key_columns = self.introspection.get_key_columns(cursor, table_name) key_columns = self.introspection.get_key_columns(cursor, table_name)
for column_name, referenced_table_name, referenced_column_name in key_columns: for column_name, referenced_table_name, referenced_column_name in key_columns:
cursor.execute(""" cursor.execute(
"""
SELECT REFERRING.`%s`, REFERRING.`%s` FROM `%s` as REFERRING SELECT REFERRING.`%s`, REFERRING.`%s` FROM `%s` as REFERRING
LEFT JOIN `%s` as REFERRED LEFT JOIN `%s` as REFERRED
ON (REFERRING.`%s` = REFERRED.`%s`) ON (REFERRING.`%s` = REFERRED.`%s`)
WHERE REFERRING.`%s` IS NOT NULL AND REFERRED.`%s` IS NULL""" WHERE REFERRING.`%s` IS NOT NULL AND REFERRED.`%s` IS NULL
% (primary_key_column_name, column_name, table_name, referenced_table_name, """ % (
column_name, referenced_column_name, column_name, referenced_column_name)) primary_key_column_name, column_name, table_name,
referenced_table_name, column_name, referenced_column_name,
column_name, referenced_column_name,
)
)
for bad_row in cursor.fetchall(): for bad_row in cursor.fetchall():
raise utils.IntegrityError("The row in table '%s' with primary key '%s' has an invalid " raise utils.IntegrityError(
"The row in table '%s' with primary key '%s' has an invalid "
"foreign key: %s.%s contains a value '%s' that does not have a corresponding value in %s.%s." "foreign key: %s.%s contains a value '%s' that does not have a corresponding value in %s.%s."
% (table_name, bad_row[0], % (
table_name, column_name, bad_row[1], table_name, bad_row[0], table_name, column_name,
referenced_table_name, referenced_column_name)) bad_row[1], referenced_table_name, referenced_column_name,
)
)
def is_usable(self): def is_usable(self):
try: try:

View File

@ -12,7 +12,8 @@ class DatabaseOperations(BaseDatabaseOperations):
compiler_module = "django.db.backends.mysql.compiler" compiler_module = "django.db.backends.mysql.compiler"
# MySQL stores positive fields as UNSIGNED ints. # MySQL stores positive fields as UNSIGNED ints.
integer_field_ranges = dict(BaseDatabaseOperations.integer_field_ranges, integer_field_ranges = dict(
BaseDatabaseOperations.integer_field_ranges,
PositiveSmallIntegerField=(0, 65535), PositiveSmallIntegerField=(0, 65535),
PositiveIntegerField=(0, 4294967295), PositiveIntegerField=(0, 4294967295),
) )

View File

@ -367,8 +367,7 @@ class OracleParam(object):
else: else:
# To transmit to the database, we need Unicode if supported # To transmit to the database, we need Unicode if supported
# To get size right, we must consider bytes. # To get size right, we must consider bytes.
self.force_bytes = convert_unicode(param, cursor.charset, self.force_bytes = convert_unicode(param, cursor.charset, strings_only)
strings_only)
if isinstance(self.force_bytes, six.string_types): if isinstance(self.force_bytes, six.string_types):
# We could optimize by only converting up to 4000 bytes here # We could optimize by only converting up to 4000 bytes here
string_size = len(force_bytes(param, cursor.charset, strings_only)) string_size = len(force_bytes(param, cursor.charset, strings_only))
@ -498,8 +497,7 @@ class FormatStylePlaceholderCursor(object):
formatted = [firstparams] + [self._format_params(p) for p in params_iter] formatted = [firstparams] + [self._format_params(p) for p in params_iter]
self._guess_input_sizes(formatted) self._guess_input_sizes(formatted)
try: try:
return self.cursor.executemany(query, return self.cursor.executemany(query, [self._param_generator(p) for p in formatted])
[self._param_generator(p) for p in formatted])
except Database.DatabaseError as e: except Database.DatabaseError as e:
# cx_Oracle <= 4.4.0 wrongly raises a DatabaseError for ORA-01400. # cx_Oracle <= 4.4.0 wrongly raises a DatabaseError for ORA-01400.
if hasattr(e.args[0], 'code') and e.args[0].code == 1400 and not isinstance(e, IntegrityError): if hasattr(e.args[0], 'code') and e.args[0].code == 1400 and not isinstance(e, IntegrityError):

View File

@ -99,8 +99,7 @@ WHEN (new.%(col_name)s IS NULL)
days = str(timedelta.days) days = str(timedelta.days)
day_precision = len(days) day_precision = len(days)
fmt = "INTERVAL '%s %02d:%02d:%02d.%06d' DAY(%d) TO SECOND(6)" fmt = "INTERVAL '%s %02d:%02d:%02d.%06d' DAY(%d) TO SECOND(6)"
return fmt % (days, hours, minutes, seconds, timedelta.microseconds, return fmt % (days, hours, minutes, seconds, timedelta.microseconds, day_precision), []
day_precision), []
def date_trunc_sql(self, lookup_type, field_name): def date_trunc_sql(self, lookup_type, field_name):
# http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions230.htm#i1002084 # http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions230.htm#i1002084

View File

@ -139,11 +139,11 @@ class DatabaseOperations(BaseDatabaseOperations):
# This will be the case if it's an m2m using an autogenerated # This will be the case if it's an m2m using an autogenerated
# intermediate table (see BaseDatabaseIntrospection.sequence_list) # intermediate table (see BaseDatabaseIntrospection.sequence_list)
column_name = 'id' column_name = 'id'
sql.append("%s setval(pg_get_serial_sequence('%s','%s'), 1, false);" % sql.append("%s setval(pg_get_serial_sequence('%s','%s'), 1, false);" % (
(style.SQL_KEYWORD('SELECT'), style.SQL_KEYWORD('SELECT'),
style.SQL_TABLE(self.quote_name(table_name)), style.SQL_TABLE(self.quote_name(table_name)),
style.SQL_FIELD(column_name)) style.SQL_FIELD(column_name),
) ))
return sql return sql
def tablespace_sql(self, tablespace, inline=False): def tablespace_sql(self, tablespace, inline=False):

View File

@ -282,18 +282,28 @@ class DatabaseWrapper(BaseDatabaseWrapper):
continue continue
key_columns = self.introspection.get_key_columns(cursor, table_name) key_columns = self.introspection.get_key_columns(cursor, table_name)
for column_name, referenced_table_name, referenced_column_name in key_columns: for column_name, referenced_table_name, referenced_column_name in key_columns:
cursor.execute(""" cursor.execute(
"""
SELECT REFERRING.`%s`, REFERRING.`%s` FROM `%s` as REFERRING SELECT REFERRING.`%s`, REFERRING.`%s` FROM `%s` as REFERRING
LEFT JOIN `%s` as REFERRED LEFT JOIN `%s` as REFERRED
ON (REFERRING.`%s` = REFERRED.`%s`) ON (REFERRING.`%s` = REFERRED.`%s`)
WHERE REFERRING.`%s` IS NOT NULL AND REFERRED.`%s` IS NULL""" WHERE REFERRING.`%s` IS NOT NULL AND REFERRED.`%s` IS NULL
% (primary_key_column_name, column_name, table_name, referenced_table_name, """
column_name, referenced_column_name, column_name, referenced_column_name)) % (
primary_key_column_name, column_name, table_name,
referenced_table_name, column_name, referenced_column_name,
column_name, referenced_column_name,
)
)
for bad_row in cursor.fetchall(): for bad_row in cursor.fetchall():
raise utils.IntegrityError("The row in table '%s' with primary key '%s' has an invalid " raise utils.IntegrityError(
"foreign key: %s.%s contains a value '%s' that does not have a corresponding value in %s.%s." "The row in table '%s' with primary key '%s' has an "
% (table_name, bad_row[0], table_name, column_name, bad_row[1], "invalid foreign key: %s.%s contains a value '%s' that "
referenced_table_name, referenced_column_name)) "does not have a corresponding value in %s.%s." % (
table_name, bad_row[0], table_name, column_name,
bad_row[1], referenced_table_name, referenced_column_name,
)
)
def is_usable(self): def is_usable(self):
return True return True

View File

@ -85,7 +85,8 @@ class CursorDebugWrapper(CursorWrapper):
'sql': sql, 'sql': sql,
'time': "%.3f" % duration, 'time': "%.3f" % duration,
}) })
logger.debug('(%.3f) %s; args=%s', duration, sql, params, logger.debug(
'(%.3f) %s; args=%s', duration, sql, params,
extra={'duration': duration, 'sql': sql, 'params': params} extra={'duration': duration, 'sql': sql, 'params': params}
) )
@ -104,7 +105,8 @@ class CursorDebugWrapper(CursorWrapper):
'sql': '%s times: %s' % (times, sql), 'sql': '%s times: %s' % (times, sql),
'time': "%.3f" % duration, 'time': "%.3f" % duration,
}) })
logger.debug('(%.3f) %s; args=%s', duration, sql, param_list, logger.debug(
'(%.3f) %s; args=%s', duration, sql, param_list,
extra={'duration': duration, 'sql': sql, 'params': param_list} extra={'duration': duration, 'sql': sql, 'params': param_list}
) )
@ -154,9 +156,11 @@ def typecast_timestamp(s): # does NOT store time zone information
else: else:
microseconds = '0' microseconds = '0'
tzinfo = utc if settings.USE_TZ else None tzinfo = utc if settings.USE_TZ else None
return datetime.datetime(int(dates[0]), int(dates[1]), int(dates[2]), return datetime.datetime(
int(dates[0]), int(dates[1]), int(dates[2]),
int(times[0]), int(times[1]), int(seconds), int(times[0]), int(times[1]), int(seconds),
int((microseconds + '000000')[:6]), tzinfo) int((microseconds + '000000')[:6]), tzinfo
)
def typecast_decimal(s): def typecast_decimal(s):

View File

@ -519,9 +519,10 @@ class Model(six.with_metaclass(ModelBase)):
if pickled_version: if pickled_version:
current_version = get_version() current_version = get_version()
if current_version != pickled_version: if current_version != pickled_version:
msg = ("Pickled model instance's Django version %s does" msg = (
" not match the current version %s." "Pickled model instance's Django version %s does not match "
% (pickled_version, current_version)) "the current version %s." % (pickled_version, current_version)
)
else: else:
msg = "Pickled model instance's Django version is not specified." msg = "Pickled model instance's Django version is not specified."
@ -1285,9 +1286,7 @@ class Model(six.with_metaclass(ModelBase)):
@classmethod @classmethod
def _check_id_field(cls): def _check_id_field(cls):
""" Check if `id` field is a primary key. """ """ Check if `id` field is a primary key. """
fields = list(f for f in cls._meta.local_fields if f.name == 'id' and f != cls._meta.pk)
fields = list(f for f in cls._meta.local_fields
if f.name == 'id' and f != cls._meta.pk)
# fields is empty or consists of the invalid "id" field # fields is empty or consists of the invalid "id" field
if fields and not fields[0].primary_key and cls._meta.pk.name == 'id': if fields and not fields[0].primary_key and cls._meta.pk.name == 'id':
return [ return [
@ -1342,8 +1341,7 @@ class Model(six.with_metaclass(ModelBase)):
# field "id" and automatically added unique field "id", both # field "id" and automatically added unique field "id", both
# defined at the same model. This special case is considered in # defined at the same model. This special case is considered in
# _check_id_field and here we ignore it. # _check_id_field and here we ignore it.
id_conflict = (f.name == "id" and id_conflict = f.name == "id" and clash and clash.name == "id" and clash.model == cls
clash and clash.name == "id" and clash.model == cls)
if clash and not id_conflict: if clash and not id_conflict:
errors.append( errors.append(
checks.Error( checks.Error(
@ -1397,8 +1395,7 @@ class Model(six.with_metaclass(ModelBase)):
) )
] ]
elif any(not isinstance(fields, (tuple, list)) elif any(not isinstance(fields, (tuple, list)) for fields in cls._meta.index_together):
for fields in cls._meta.index_together):
return [ return [
checks.Error( checks.Error(
"All 'index_together' elements must be lists or tuples.", "All 'index_together' elements must be lists or tuples.",
@ -1425,8 +1422,7 @@ class Model(six.with_metaclass(ModelBase)):
) )
] ]
elif any(not isinstance(fields, (tuple, list)) elif any(not isinstance(fields, (tuple, list)) for fields in cls._meta.unique_together):
for fields in cls._meta.unique_together):
return [ return [
checks.Error( checks.Error(
"All 'unique_together' elements must be lists or tuples.", "All 'unique_together' elements must be lists or tuples.",

View File

@ -20,8 +20,9 @@ def CASCADE(collector, field, sub_objs, using):
def PROTECT(collector, field, sub_objs, using): def PROTECT(collector, field, sub_objs, using):
raise ProtectedError("Cannot delete some instances of model '%s' because " raise ProtectedError(
"they are referenced through a protected foreign key: '%s.%s'" % ( "Cannot delete some instances of model '%s' because they are "
"referenced through a protected foreign key: '%s.%s'" % (
field.remote_field.model.__name__, sub_objs[0].__class__.__name__, field.name field.remote_field.model.__name__, sub_objs[0].__class__.__name__, field.name
), ),
sub_objs sub_objs
@ -165,7 +166,7 @@ class Collector(object):
return [objs] return [objs]
def collect(self, objs, source=None, nullable=False, collect_related=True, def collect(self, objs, source=None, nullable=False, collect_related=True,
source_attr=None, reverse_dependency=False, keep_parents=False): source_attr=None, reverse_dependency=False, keep_parents=False):
""" """
Adds 'objs' to the collection of objects to be deleted as well as all Adds 'objs' to the collection of objects to be deleted as well as all
parent instances. 'objs' must be a homogeneous iterable collection of parent instances. 'objs' must be a homogeneous iterable collection of

View File

@ -137,12 +137,12 @@ class Field(RegisterLookupMixin):
description = property(_description) description = property(_description)
def __init__(self, verbose_name=None, name=None, primary_key=False, def __init__(self, verbose_name=None, name=None, primary_key=False,
max_length=None, unique=False, blank=False, null=False, max_length=None, unique=False, blank=False, null=False,
db_index=False, rel=None, default=NOT_PROVIDED, editable=True, db_index=False, rel=None, default=NOT_PROVIDED, editable=True,
serialize=True, unique_for_date=None, unique_for_month=None, serialize=True, unique_for_date=None, unique_for_month=None,
unique_for_year=None, choices=None, help_text='', db_column=None, unique_for_year=None, choices=None, help_text='', db_column=None,
db_tablespace=None, auto_created=False, validators=[], db_tablespace=None, auto_created=False, validators=[],
error_messages=None): error_messages=None):
self.name = name self.name = name
self.verbose_name = verbose_name # May be set by set_attributes_from_name self.verbose_name = verbose_name # May be set by set_attributes_from_name
self._verbose_name = verbose_name # Store original for deconstruction self._verbose_name = verbose_name # Store original for deconstruction
@ -806,8 +806,7 @@ class Field(RegisterLookupMixin):
if callable(self.default): if callable(self.default):
return self.default() return self.default()
return self.default return self.default
if (not self.empty_strings_allowed or (self.null and if not self.empty_strings_allowed or self.null and not connection.features.interprets_empty_strings_as_nulls:
not connection.features.interprets_empty_strings_as_nulls)):
return None return None
return "" return ""
@ -1177,10 +1176,8 @@ class DateTimeCheckMixin(object):
# auto_now, auto_now_add, and default are mutually exclusive # auto_now, auto_now_add, and default are mutually exclusive
# options. The use of more than one of these options together # options. The use of more than one of these options together
# will trigger an Error # will trigger an Error
mutually_exclusive_options = [self.auto_now_add, self.auto_now, mutually_exclusive_options = [self.auto_now_add, self.auto_now, self.has_default()]
self.has_default()] enabled_options = [option not in (None, False) for option in mutually_exclusive_options].count(True)
enabled_options = [option not in (None, False)
for option in mutually_exclusive_options].count(True)
if enabled_options > 1: if enabled_options > 1:
return [ return [
checks.Error( checks.Error(
@ -1314,12 +1311,14 @@ class DateField(DateTimeCheckMixin, Field):
def contribute_to_class(self, cls, name, **kwargs): def contribute_to_class(self, cls, name, **kwargs):
super(DateField, self).contribute_to_class(cls, name, **kwargs) super(DateField, self).contribute_to_class(cls, name, **kwargs)
if not self.null: if not self.null:
setattr(cls, 'get_next_by_%s' % self.name, setattr(
curry(cls._get_next_or_previous_by_FIELD, field=self, cls, 'get_next_by_%s' % self.name,
is_next=True)) curry(cls._get_next_or_previous_by_FIELD, field=self, is_next=True)
setattr(cls, 'get_previous_by_%s' % self.name, )
curry(cls._get_next_or_previous_by_FIELD, field=self, setattr(
is_next=False)) cls, 'get_previous_by_%s' % self.name,
curry(cls._get_next_or_previous_by_FIELD, field=self, is_next=False)
)
def get_prep_value(self, value): def get_prep_value(self, value):
value = super(DateField, self).get_prep_value(value) value = super(DateField, self).get_prep_value(value)
@ -1633,8 +1632,7 @@ class DecimalField(Field):
return utils.format_number(value, self.max_digits, self.decimal_places) return utils.format_number(value, self.max_digits, self.decimal_places)
def get_db_prep_save(self, value, connection): def get_db_prep_save(self, value, connection):
return connection.ops.adapt_decimalfield_value(self.to_python(value), return connection.ops.adapt_decimalfield_value(self.to_python(value), self.max_digits, self.decimal_places)
self.max_digits, self.decimal_places)
def get_prep_value(self, value): def get_prep_value(self, value):
value = super(DecimalField, self).get_prep_value(value) value = super(DecimalField, self).get_prep_value(value)
@ -2002,8 +2000,7 @@ class GenericIPAddressField(Field):
value = force_text(value) value = force_text(value)
value = value.strip() value = value.strip()
if ':' in value: if ':' in value:
return clean_ipv6_address(value, return clean_ipv6_address(value, self.unpack_ipv4, self.error_messages['invalid'])
self.unpack_ipv4, self.error_messages['invalid'])
return value return value
def get_db_prep_value(self, value, connection, prepared=False): def get_db_prep_value(self, value, connection, prepared=False):

View File

@ -369,8 +369,7 @@ class ImageField(FileField):
descriptor_class = ImageFileDescriptor descriptor_class = ImageFileDescriptor
description = _("Image") description = _("Image")
def __init__(self, verbose_name=None, name=None, width_field=None, def __init__(self, verbose_name=None, name=None, width_field=None, height_field=None, **kwargs):
height_field=None, **kwargs):
self.width_field, self.height_field = width_field, height_field self.width_field, self.height_field = width_field, height_field
super(ImageField, self).__init__(verbose_name, name, **kwargs) super(ImageField, self).__init__(verbose_name, name, **kwargs)

View File

@ -221,8 +221,7 @@ class RelatedField(Field):
# model_set and it clashes with Target.model_set. # model_set and it clashes with Target.model_set.
potential_clashes = rel_opts.fields + rel_opts.many_to_many potential_clashes = rel_opts.fields + rel_opts.many_to_many
for clash_field in potential_clashes: for clash_field in potential_clashes:
clash_name = "%s.%s" % (rel_opts.object_name, clash_name = "%s.%s" % (rel_opts.object_name, clash_field.name) # i.e. "Target.model_set"
clash_field.name) # i. e. "Target.model_set"
if not rel_is_hidden and clash_field.name == rel_name: if not rel_is_hidden and clash_field.name == rel_name:
errors.append( errors.append(
checks.Error( checks.Error(
@ -441,8 +440,8 @@ class ForeignObject(RelatedField):
rel_class = ForeignObjectRel rel_class = ForeignObjectRel
def __init__(self, to, on_delete, from_fields, to_fields, rel=None, related_name=None, def __init__(self, to, on_delete, from_fields, to_fields, rel=None, related_name=None,
related_query_name=None, limit_choices_to=None, parent_link=False, related_query_name=None, limit_choices_to=None, parent_link=False,
swappable=True, **kwargs): swappable=True, **kwargs):
if rel is None: if rel is None:
rel = self.rel_class( rel = self.rel_class(
@ -491,8 +490,9 @@ class ForeignObject(RelatedField):
has_unique_constraint = any(u <= foreign_fields for u in unique_foreign_fields) has_unique_constraint = any(u <= foreign_fields for u in unique_foreign_fields)
if not has_unique_constraint and len(self.foreign_related_fields) > 1: if not has_unique_constraint and len(self.foreign_related_fields) > 1:
field_combination = ', '.join("'%s'" % rel_field.name field_combination = ', '.join(
for rel_field in self.foreign_related_fields) "'%s'" % rel_field.name for rel_field in self.foreign_related_fields
)
model_name = self.remote_field.model.__name__ model_name = self.remote_field.model.__name__
return [ return [
checks.Error( checks.Error(
@ -743,8 +743,8 @@ class ForeignKey(ForeignObject):
description = _("Foreign Key (type determined by related field)") description = _("Foreign Key (type determined by related field)")
def __init__(self, to, on_delete=None, related_name=None, related_query_name=None, def __init__(self, to, on_delete=None, related_name=None, related_query_name=None,
limit_choices_to=None, parent_link=False, to_field=None, limit_choices_to=None, parent_link=False, to_field=None,
db_constraint=True, **kwargs): db_constraint=True, **kwargs):
try: try:
to._meta.model_name to._meta.model_name
except AttributeError: except AttributeError:
@ -1111,9 +1111,9 @@ class ManyToManyField(RelatedField):
description = _("Many-to-many relationship") description = _("Many-to-many relationship")
def __init__(self, to, related_name=None, related_query_name=None, def __init__(self, to, related_name=None, related_query_name=None,
limit_choices_to=None, symmetrical=None, through=None, limit_choices_to=None, symmetrical=None, through=None,
through_fields=None, db_constraint=True, db_table=None, through_fields=None, db_constraint=True, db_table=None,
swappable=True, **kwargs): swappable=True, **kwargs):
try: try:
to._meta to._meta
except AttributeError: except AttributeError:
@ -1241,8 +1241,10 @@ class ManyToManyField(RelatedField):
# Count foreign keys in intermediate model # Count foreign keys in intermediate model
if self_referential: if self_referential:
seen_self = sum(from_model == getattr(field.remote_field, 'model', None) seen_self = sum(
for field in self.remote_field.through._meta.fields) from_model == getattr(field.remote_field, 'model', None)
for field in self.remote_field.through._meta.fields
)
if seen_self > 2 and not self.remote_field.through_fields: if seen_self > 2 and not self.remote_field.through_fields:
errors.append( errors.append(
@ -1260,10 +1262,14 @@ class ManyToManyField(RelatedField):
else: else:
# Count foreign keys in relationship model # Count foreign keys in relationship model
seen_from = sum(from_model == getattr(field.remote_field, 'model', None) seen_from = sum(
for field in self.remote_field.through._meta.fields) from_model == getattr(field.remote_field, 'model', None)
seen_to = sum(to_model == getattr(field.remote_field, 'model', None) for field in self.remote_field.through._meta.fields
for field in self.remote_field.through._meta.fields) )
seen_to = sum(
to_model == getattr(field.remote_field, 'model', None)
for field in self.remote_field.through._meta.fields
)
if seen_from > 1 and not self.remote_field.through_fields: if seen_from > 1 and not self.remote_field.through_fields:
errors.append( errors.append(
@ -1469,8 +1475,7 @@ class ManyToManyField(RelatedField):
elif self.db_table: elif self.db_table:
return self.db_table return self.db_table
else: else:
return utils.truncate_name('%s_%s' % (opts.db_table, self.name), return utils.truncate_name('%s_%s' % (opts.db_table, self.name), connection.ops.max_name_length())
connection.ops.max_name_length())
def _get_m2m_attr(self, related, attr): def _get_m2m_attr(self, related, attr):
""" """

View File

@ -868,16 +868,19 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
def clear(self): def clear(self):
db = router.db_for_write(self.through, instance=self.instance) db = router.db_for_write(self.through, instance=self.instance)
with transaction.atomic(using=db, savepoint=False): with transaction.atomic(using=db, savepoint=False):
signals.m2m_changed.send(sender=self.through, action="pre_clear", signals.m2m_changed.send(
sender=self.through, action="pre_clear",
instance=self.instance, reverse=self.reverse, instance=self.instance, reverse=self.reverse,
model=self.model, pk_set=None, using=db) model=self.model, pk_set=None, using=db,
)
filters = self._build_remove_filters(super(ManyRelatedManager, self).get_queryset().using(db)) filters = self._build_remove_filters(super(ManyRelatedManager, self).get_queryset().using(db))
self.through._default_manager.using(db).filter(filters).delete() self.through._default_manager.using(db).filter(filters).delete()
signals.m2m_changed.send(sender=self.through, action="post_clear", signals.m2m_changed.send(
sender=self.through, action="post_clear",
instance=self.instance, reverse=self.reverse, instance=self.instance, reverse=self.reverse,
model=self.model, pk_set=None, using=db) model=self.model, pk_set=None, using=db,
)
clear.alters_data = True clear.alters_data = True
def set(self, objs, **kwargs): def set(self, objs, **kwargs):
@ -905,9 +908,10 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
new_objs = [] new_objs = []
for obj in objs: for obj in objs:
fk_val = (self.target_field.get_foreign_related_value(obj)[0] fk_val = (
if isinstance(obj, self.model) else obj) self.target_field.get_foreign_related_value(obj)[0]
if isinstance(obj, self.model) else obj
)
if fk_val in old_ids: if fk_val in old_ids:
old_ids.remove(fk_val) old_ids.remove(fk_val)
else: else:
@ -998,9 +1002,11 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
if self.reverse or source_field_name == self.source_field_name: if self.reverse or source_field_name == self.source_field_name:
# Don't send the signal when we are inserting the # Don't send the signal when we are inserting the
# duplicate data row for symmetrical reverse entries. # duplicate data row for symmetrical reverse entries.
signals.m2m_changed.send(sender=self.through, action='pre_add', signals.m2m_changed.send(
sender=self.through, action='pre_add',
instance=self.instance, reverse=self.reverse, instance=self.instance, reverse=self.reverse,
model=self.model, pk_set=new_ids, using=db) model=self.model, pk_set=new_ids, using=db,
)
# Add the ones that aren't there already # Add the ones that aren't there already
self.through._default_manager.using(db).bulk_create([ self.through._default_manager.using(db).bulk_create([
@ -1014,9 +1020,11 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
if self.reverse or source_field_name == self.source_field_name: if self.reverse or source_field_name == self.source_field_name:
# Don't send the signal when we are inserting the # Don't send the signal when we are inserting the
# duplicate data row for symmetrical reverse entries. # duplicate data row for symmetrical reverse entries.
signals.m2m_changed.send(sender=self.through, action='post_add', signals.m2m_changed.send(
sender=self.through, action='post_add',
instance=self.instance, reverse=self.reverse, instance=self.instance, reverse=self.reverse,
model=self.model, pk_set=new_ids, using=db) model=self.model, pk_set=new_ids, using=db,
)
def _remove_items(self, source_field_name, target_field_name, *objs): def _remove_items(self, source_field_name, target_field_name, *objs):
# source_field_name: the PK colname in join table for the source object # source_field_name: the PK colname in join table for the source object
@ -1037,9 +1045,11 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
db = router.db_for_write(self.through, instance=self.instance) db = router.db_for_write(self.through, instance=self.instance)
with transaction.atomic(using=db, savepoint=False): with transaction.atomic(using=db, savepoint=False):
# Send a signal to the other end if need be. # Send a signal to the other end if need be.
signals.m2m_changed.send(sender=self.through, action="pre_remove", signals.m2m_changed.send(
sender=self.through, action="pre_remove",
instance=self.instance, reverse=self.reverse, instance=self.instance, reverse=self.reverse,
model=self.model, pk_set=old_ids, using=db) model=self.model, pk_set=old_ids, using=db,
)
target_model_qs = super(ManyRelatedManager, self).get_queryset() target_model_qs = super(ManyRelatedManager, self).get_queryset()
if target_model_qs._has_filters(): if target_model_qs._has_filters():
old_vals = target_model_qs.using(db).filter(**{ old_vals = target_model_qs.using(db).filter(**{
@ -1049,8 +1059,10 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
filters = self._build_remove_filters(old_vals) filters = self._build_remove_filters(old_vals)
self.through._default_manager.using(db).filter(filters).delete() self.through._default_manager.using(db).filter(filters).delete()
signals.m2m_changed.send(sender=self.through, action="post_remove", signals.m2m_changed.send(
sender=self.through, action="post_remove",
instance=self.instance, reverse=self.reverse, instance=self.instance, reverse=self.reverse,
model=self.model, pk_set=old_ids, using=db) model=self.model, pk_set=old_ids, using=db,
)
return ManyRelatedManager return ManyRelatedManager

View File

@ -40,7 +40,7 @@ class ForeignObjectRel(object):
null = True null = True
def __init__(self, field, to, related_name=None, related_query_name=None, def __init__(self, field, to, related_name=None, related_query_name=None,
limit_choices_to=None, parent_link=False, on_delete=None): limit_choices_to=None, parent_link=False, on_delete=None):
self.field = field self.field = field
self.model = to self.model = to
self.related_name = related_name self.related_name = related_name
@ -212,7 +212,7 @@ class ManyToOneRel(ForeignObjectRel):
""" """
def __init__(self, field, to, field_name, related_name=None, related_query_name=None, def __init__(self, field, to, field_name, related_name=None, related_query_name=None,
limit_choices_to=None, parent_link=False, on_delete=None): limit_choices_to=None, parent_link=False, on_delete=None):
super(ManyToOneRel, self).__init__( super(ManyToOneRel, self).__init__(
field, to, field, to,
related_name=related_name, related_name=related_name,
@ -235,8 +235,7 @@ class ManyToOneRel(ForeignObjectRel):
""" """
field = self.model._meta.get_field(self.field_name) field = self.model._meta.get_field(self.field_name)
if not field.concrete: if not field.concrete:
raise exceptions.FieldDoesNotExist("No related field named '%s'" % raise exceptions.FieldDoesNotExist("No related field named '%s'" % self.field_name)
self.field_name)
return field return field
def set_field_name(self): def set_field_name(self):
@ -252,7 +251,7 @@ class OneToOneRel(ManyToOneRel):
""" """
def __init__(self, field, to, field_name, related_name=None, related_query_name=None, def __init__(self, field, to, field_name, related_name=None, related_query_name=None,
limit_choices_to=None, parent_link=False, on_delete=None): limit_choices_to=None, parent_link=False, on_delete=None):
super(OneToOneRel, self).__init__( super(OneToOneRel, self).__init__(
field, to, field_name, field, to, field_name,
related_name=related_name, related_name=related_name,
@ -274,8 +273,8 @@ class ManyToManyRel(ForeignObjectRel):
""" """
def __init__(self, field, to, related_name=None, related_query_name=None, def __init__(self, field, to, related_name=None, related_query_name=None,
limit_choices_to=None, symmetrical=True, through=None, through_fields=None, limit_choices_to=None, symmetrical=True, through=None,
db_constraint=True): through_fields=None, db_constraint=True):
super(ManyToManyRel, self).__init__( super(ManyToManyRel, self).__init__(
field, to, field, to,
related_name=related_name, related_name=related_name,

View File

@ -28,13 +28,14 @@ IMMUTABLE_WARNING = (
"for your own use, make a copy first." "for your own use, make a copy first."
) )
DEFAULT_NAMES = ('verbose_name', 'verbose_name_plural', 'db_table', 'ordering', DEFAULT_NAMES = (
'unique_together', 'permissions', 'get_latest_by', 'verbose_name', 'verbose_name_plural', 'db_table', 'ordering',
'order_with_respect_to', 'app_label', 'db_tablespace', 'unique_together', 'permissions', 'get_latest_by', 'order_with_respect_to',
'abstract', 'managed', 'proxy', 'swappable', 'auto_created', 'app_label', 'db_tablespace', 'abstract', 'managed', 'proxy', 'swappable',
'index_together', 'apps', 'default_permissions', 'auto_created', 'index_together', 'apps', 'default_permissions',
'select_on_save', 'default_related_name', 'select_on_save', 'default_related_name', 'required_db_features',
'required_db_features', 'required_db_vendor') 'required_db_vendor',
)
def normalize_together(option_together): def normalize_together(option_together):
@ -249,8 +250,7 @@ class Options(object):
field.primary_key = True field.primary_key = True
self.setup_pk(field) self.setup_pk(field)
else: else:
auto = AutoField(verbose_name='ID', primary_key=True, auto = AutoField(verbose_name='ID', primary_key=True, auto_created=True)
auto_created=True)
model.add_to_class('id', auto) model.add_to_class('id', auto)
def add_field(self, field, virtual=False): def add_field(self, field, virtual=False):
@ -385,8 +385,7 @@ class Options(object):
return make_immutable_fields_list( return make_immutable_fields_list(
"fields", "fields",
(f for f in self._get_fields(reverse=False) (f for f in self._get_fields(reverse=False)
if is_not_an_m2m_field(f) and is_not_a_generic_relation(f) and if is_not_an_m2m_field(f) and is_not_a_generic_relation(f) and is_not_a_generic_foreign_key(f))
is_not_a_generic_foreign_key(f))
) )
@cached_property @cached_property
@ -426,8 +425,7 @@ class Options(object):
""" """
return make_immutable_fields_list( return make_immutable_fields_list(
"many_to_many", "many_to_many",
(f for f in self._get_fields(reverse=False) (f for f in self._get_fields(reverse=False) if f.is_relation and f.many_to_many)
if f.is_relation and f.many_to_many)
) )
@cached_property @cached_property
@ -444,8 +442,7 @@ class Options(object):
all_related_fields = self._get_fields(forward=False, reverse=True, include_hidden=True) all_related_fields = self._get_fields(forward=False, reverse=True, include_hidden=True)
return make_immutable_fields_list( return make_immutable_fields_list(
"related_objects", "related_objects",
(obj for obj in all_related_fields (obj for obj in all_related_fields if not obj.hidden or obj.field.many_to_many)
if not obj.hidden or obj.field.many_to_many)
) )
@cached_property @cached_property

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