Skip to content

Commit

Permalink
Merge branch 'django:main' into ticket_28401
Browse files Browse the repository at this point in the history
  • Loading branch information
vakwetu committed Oct 11, 2021
2 parents 7870ce3 + 5b0f1f9 commit 0a9654e
Show file tree
Hide file tree
Showing 71 changed files with 899 additions and 255 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/docs.yml
Expand Up @@ -21,7 +21,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.9
python-version: '3.10'
- name: Cache dependencies
uses: actions/cache@v2
with:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/linters.yml
Expand Up @@ -20,7 +20,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.9
python-version: '3.10'
- run: python -m pip install flake8
- name: flake8
uses: liskin/gh-problem-matcher-wrap@v1
Expand All @@ -36,7 +36,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.9
python-version: '3.10'
- run: python -m pip install isort
- name: isort
uses: liskin/gh-problem-matcher-wrap@v1
Expand Down
2 changes: 2 additions & 0 deletions AUTHORS
Expand Up @@ -55,6 +55,7 @@ answer newbie questions, and generally made Django that much better:
Alexey Boriskin <alex@boriskin.me>
Alexey Tsivunin <most-208@yandex.ru>
Ali Vakilzade <ali@vakilzade.com>
Aljaž Košir <aljazkosir5@gmail.com>
Aljosa Mohorovic <aljosa.mohorovic@gmail.com>
Amit Chakradeo <https://amit.chakradeo.net/>
Amit Ramon <amit.ramon@gmail.com>
Expand Down Expand Up @@ -990,6 +991,7 @@ answer newbie questions, and generally made Django that much better:
Xia Kai <https://blog.xiaket.org/>
Yann Fouillat <gagaro42@gmail.com>
Yann Malet
Yash Jhunjhunwala
Yasushi Masuda <whosaysni@gmail.com>
ye7cakf02@sneakemail.com
ymasuda@ethercube.com
Expand Down
63 changes: 58 additions & 5 deletions django/contrib/admin/static/admin/js/admin/RelatedObjectLookups.js
Expand Up @@ -4,14 +4,45 @@
'use strict';
{
const $ = django.jQuery;
let popupIndex = 0;
const relatedWindows = [];

function dismissChildPopups() {
relatedWindows.forEach(function(win) {
if(!win.closed) {
win.dismissChildPopups();
win.close();
}
});
}

function setPopupIndex() {
if(document.getElementsByName("_popup").length > 0) {
const index = window.name.lastIndexOf("__") + 2;
popupIndex = parseInt(window.name.substring(index));
} else {
popupIndex = 0;
}
}

function addPopupIndex(name) {
name = name + "__" + (popupIndex + 1);
return name;
}

function removePopupIndex(name) {
name = name.replace(new RegExp("__" + (popupIndex + 1) + "$"), '');
return name;
}

function showAdminPopup(triggeringLink, name_regexp, add_popup) {
const name = triggeringLink.id.replace(name_regexp, '');
const name = addPopupIndex(triggeringLink.id.replace(name_regexp, ''));
const href = new URL(triggeringLink.href);
if (add_popup) {
href.searchParams.set('_popup', 1);
}
const win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes');
relatedWindows.push(win);
win.focus();
return false;
}
Expand All @@ -21,13 +52,17 @@
}

function dismissRelatedLookupPopup(win, chosenId) {
const name = win.name;
const name = removePopupIndex(win.name);
const elem = document.getElementById(name);
if (elem.classList.contains('vManyToManyRawIdAdminField') && elem.value) {
elem.value += ',' + chosenId;
} else {
document.getElementById(name).value = chosenId;
}
const index = relatedWindows.indexOf(win);
if (index > -1) {
relatedWindows.splice(index, 1);
}
win.close();
}

Expand All @@ -53,7 +88,7 @@
}

function dismissAddRelatedObjectPopup(win, newId, newRepr) {
const name = win.name;
const name = removePopupIndex(win.name);
const elem = document.getElementById(name);
if (elem) {
const elemName = elem.nodeName.toUpperCase();
Expand All @@ -74,11 +109,15 @@
SelectBox.add_to_cache(toId, o);
SelectBox.redisplay(toId);
}
const index = relatedWindows.indexOf(win);
if (index > -1) {
relatedWindows.splice(index, 1);
}
win.close();
}

function dismissChangeRelatedObjectPopup(win, objId, newRepr, newId) {
const id = win.name.replace(/^edit_/, '');
const id = removePopupIndex(win.name.replace(/^edit_/, ''));
const selectsSelector = interpolate('#%s, #%s_from, #%s_to', [id, id, id]);
const selects = $(selectsSelector);
selects.find('option').each(function() {
Expand All @@ -93,18 +132,26 @@
this.lastChild.textContent = newRepr;
this.title = newRepr;
});
const index = relatedWindows.indexOf(win);
if (index > -1) {
relatedWindows.splice(index, 1);
}
win.close();
}

function dismissDeleteRelatedObjectPopup(win, objId) {
const id = win.name.replace(/^delete_/, '');
const id = removePopupIndex(win.name.replace(/^delete_/, ''));
const selectsSelector = interpolate('#%s, #%s_from, #%s_to', [id, id, id]);
const selects = $(selectsSelector);
selects.find('option').each(function() {
if (this.value === objId) {
$(this).remove();
}
}).trigger('change');
const index = relatedWindows.indexOf(win);
if (index > -1) {
relatedWindows.splice(index, 1);
}
win.close();
}

Expand All @@ -115,12 +162,18 @@
window.dismissAddRelatedObjectPopup = dismissAddRelatedObjectPopup;
window.dismissChangeRelatedObjectPopup = dismissChangeRelatedObjectPopup;
window.dismissDeleteRelatedObjectPopup = dismissDeleteRelatedObjectPopup;
window.dismissChildPopups = dismissChildPopups;

// Kept for backward compatibility
window.showAddAnotherPopup = showRelatedObjectPopup;
window.dismissAddAnotherPopup = dismissAddRelatedObjectPopup;

window.addEventListener('unload', function(evt) {
window.dismissChildPopups();
});

$(document).ready(function() {
setPopupIndex();
$("a[data-popup-opener]").on('click', function(event) {
event.preventDefault();
opener.dismissRelatedLookupPopup(window, $(this).data("popup-opener"));
Expand Down
4 changes: 2 additions & 2 deletions django/contrib/admin/static/admin/js/nav_sidebar.js
Expand Up @@ -74,15 +74,15 @@
} else {
event.target.classList.add('no-results');
}
localStorage.setItem('django.admin.navSidebarFilterValue', filterValue);
sessionStorage.setItem('django.admin.navSidebarFilterValue', filterValue);
}

const nav = document.getElementById('nav-filter');
nav.addEventListener('change', checkValue, false);
nav.addEventListener('input', checkValue, false);
nav.addEventListener('keyup', checkValue, false);

const storedValue = localStorage.getItem('django.admin.navSidebarFilterValue');
const storedValue = sessionStorage.getItem('django.admin.navSidebarFilterValue');
if (storedValue) {
nav.value = storedValue;
checkValue({target: nav, key: ''});
Expand Down
4 changes: 4 additions & 0 deletions django/contrib/auth/management/commands/createsuperuser.py
Expand Up @@ -185,6 +185,10 @@ def handle(self, *args, **options):
raise CommandError('You must use --%s with --noinput.' % field_name)
field = self.UserModel._meta.get_field(field_name)
user_data[field_name] = field.clean(value, None)
if field.many_to_many and isinstance(user_data[field_name], str):
user_data[field_name] = [
pk.strip() for pk in user_data[field_name].split(',')
]

self.UserModel._default_manager.db_manager(database).create_superuser(**user_data)
if options['verbosity'] >= 1:
Expand Down
7 changes: 6 additions & 1 deletion django/contrib/postgres/aggregates/general.py
Expand Up @@ -9,7 +9,8 @@
from .mixins import OrderableAggMixin

__all__ = [
'ArrayAgg', 'BitAnd', 'BitOr', 'BoolAnd', 'BoolOr', 'JSONBAgg', 'StringAgg',
'ArrayAgg', 'BitAnd', 'BitOr', 'BitXor', 'BoolAnd', 'BoolOr', 'JSONBAgg',
'StringAgg',
]


Expand Down Expand Up @@ -60,6 +61,10 @@ class BitOr(Aggregate):
function = 'BIT_OR'


class BitXor(Aggregate):
function = 'BIT_XOR'


class BoolAnd(Aggregate):
function = 'BOOL_AND'
output_field = BooleanField()
Expand Down
2 changes: 1 addition & 1 deletion django/contrib/postgres/aggregates/statistics.py
Expand Up @@ -36,7 +36,7 @@ class RegrAvgY(StatAggregate):
class RegrCount(StatAggregate):
function = 'REGR_COUNT'
output_field = IntegerField()
empty_aggregate_value = 0
empty_result_set_value = 0


class RegrIntercept(StatAggregate):
Expand Down
22 changes: 16 additions & 6 deletions django/contrib/postgres/constraints.py
Expand Up @@ -45,10 +45,6 @@ def __init__(
raise ValueError(
'ExclusionConstraint.include must be a list or tuple.'
)
if include and index_type and index_type.lower() != 'gist':
raise ValueError(
'Covering exclusion constraints only support GiST indexes.'
)
if not isinstance(opclasses, (list, tuple)):
raise ValueError(
'ExclusionConstraint.opclasses must be a list or tuple.'
Expand Down Expand Up @@ -124,9 +120,23 @@ def remove_sql(self, model, schema_editor):
)

def check_supported(self, schema_editor):
if self.include and not schema_editor.connection.features.supports_covering_gist_indexes:
if (
self.include and
self.index_type.lower() == 'gist' and
not schema_editor.connection.features.supports_covering_gist_indexes
):
raise NotSupportedError(
'Covering exclusion constraints using a GiST index require '
'PostgreSQL 12+.'
)
if (
self.include and
self.index_type.lower() == 'spgist' and
not schema_editor.connection.features.supports_covering_spgist_indexes
):
raise NotSupportedError(
'Covering exclusion constraints requires PostgreSQL 12+.'
'Covering exclusion constraints using an SP-GiST index '
'require PostgreSQL 14+.'
)

def deconstruct(self):
Expand Down
9 changes: 8 additions & 1 deletion django/contrib/postgres/indexes.py
Expand Up @@ -178,7 +178,7 @@ def get_with_params(self):

def check_supported(self, schema_editor):
if self.include and not schema_editor.connection.features.supports_covering_gist_indexes:
raise NotSupportedError('Covering GiST indexes requires PostgreSQL 12+.')
raise NotSupportedError('Covering GiST indexes require PostgreSQL 12+.')


class HashIndex(PostgresIndex):
Expand Down Expand Up @@ -220,6 +220,13 @@ def get_with_params(self):
with_params.append('fillfactor = %d' % self.fillfactor)
return with_params

def check_supported(self, schema_editor):
if (
self.include and
not schema_editor.connection.features.supports_covering_spgist_indexes
):
raise NotSupportedError('Covering SP-GiST indexes require PostgreSQL 14+.')


class OpClass(Func):
template = '%(expressions)s %(name)s'
Expand Down

0 comments on commit 0a9654e

Please sign in to comment.