Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions django/contrib/admin/static/admin/css/forms.css
Original file line number Diff line number Diff line change
Expand Up @@ -429,24 +429,26 @@ body.popup .submit-row {
.inline-group .tabular tr td.original {
padding: 2px 0 0 0;
width: 0;
_position: relative;
}

.inline-group .tabular th.original {
width: 0px;
padding: 0;
}

.inline-group .tabular td {
font-size: 1rem;
}

.inline-group .tabular td.original p {
position: absolute;
left: 0;
height: 1.1em;
height: 1.2em;
padding: 2px 9px;
overflow: hidden;
font-size: 0.5625rem;
font-size: 0.875rem;
font-weight: bold;
color: var(--body-quiet-color);
_width: 700px;
}

.inline-group div.add-row,
Expand Down
6 changes: 4 additions & 2 deletions django/contrib/gis/static/gis/js/OLMapWidget.js
Original file line number Diff line number Diff line change
Expand Up @@ -266,8 +266,10 @@ function initMapWidgetInSection(section) {
if (wrapper.id.includes('__prefix__')) {
return;
}
const options = JSON.parse(wrapper.querySelector("#mapwidget-options").textContent);
options.id = wrapper.querySelector("textarea").id;
const textarea_id = wrapper.querySelector("textarea").id;
const options_script = wrapper.querySelector(`script#${textarea_id}_mapwidget_options`);
const options = JSON.parse(options_script.textContent);
options.id = textarea_id;
options.map_id = wrapper.querySelector(".dj_map").id;
maps.push(new MapWidget(options));
});
Expand Down
4 changes: 3 additions & 1 deletion django/contrib/gis/templates/gis/openlayers.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,7 @@
{% if widget.attrs.display_raw %}<p>{% translate "Debugging window (serialized value)" %}</p>{% endif %}
<textarea id="{{ widget.attrs.id }}" class="vSerializedField required" cols="150" rows="10" name="{{ widget.name }}"
{% if not widget.attrs.display_raw %} hidden{% endif %}>{{ serialized }}</textarea>
{{ widget.attrs|json_script:"mapwidget-options" }}
{% with script_id=widget.attrs.id|add:"_mapwidget_options" %}
{{ widget.attrs|json_script:script_id }}
{% endwith %}
</div>
13 changes: 11 additions & 2 deletions django/contrib/staticfiles/management/commands/collectstatic.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ def __init__(self, *args, **kwargs):
self.symlinked_files = []
self.unmodified_files = []
self.post_processed_files = []
self.skipped_files = []
self.storage = staticfiles_storage
self.style = no_style()

Expand Down Expand Up @@ -134,12 +135,13 @@ def collect(self):
found_files[prefixed_path] = (storage, path)
handler(path, prefixed_path, storage)
else:
self.skipped_files.append(prefixed_path)
self.log(
"Found another file with the destination path '%s'. It "
"will be ignored since only the first encountered file "
"is collected. If this is not what you want, make sure "
"every static file has a unique path." % prefixed_path,
level=1,
level=2,
)

# Storage backends may define a post_process() method.
Expand All @@ -165,6 +167,7 @@ def collect(self):
"modified": self.copied_files + self.symlinked_files,
"unmodified": self.unmodified_files,
"post_processed": self.post_processed_files,
"skipped": self.skipped_files,
}

def handle(self, **options):
Expand Down Expand Up @@ -212,9 +215,10 @@ def handle(self, **options):
modified_count = len(collected["modified"])
unmodified_count = len(collected["unmodified"])
post_processed_count = len(collected["post_processed"])
skipped_count = len(collected["skipped"])
return (
"\n%(modified_count)s %(identifier)s %(action)s"
"%(destination)s%(unmodified)s%(post_processed)s."
"%(destination)s%(unmodified)s%(post_processed)s%(skipped)s."
) % {
"modified_count": modified_count,
"identifier": "static file" + ("" if modified_count == 1 else "s"),
Expand All @@ -232,6 +236,11 @@ def handle(self, **options):
and ", %s post-processed" % post_processed_count
or ""
),
"skipped": (
", %s skipped due to conflict" % skipped_count
if collected["skipped"]
else ""
),
}

def log(self, msg, level=2):
Expand Down
4 changes: 4 additions & 0 deletions docs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -174,3 +174,7 @@ black:
| xargs blacken-docs --rst-literal-block; echo $$? > "$(BUILDDIR)/black/output.txt"
@echo
@echo "Code blocks reformatted"

check: spelling black
@echo
@echo "Style and spelling checks completed."
44 changes: 39 additions & 5 deletions docs/internals/contributing/writing-documentation.txt
Original file line number Diff line number Diff line change
Expand Up @@ -152,10 +152,29 @@ To edit this page, for example, we would edit the file
:source:`docs/internals/contributing/writing-documentation.txt` and rebuild the
HTML with ``make html``.

.. _documentation-checks:

Documentation quality checks
----------------------------

Several checks help maintain Django's documentation quality, including
:ref:`spelling <documentation-spelling-check>` and
:ref:`code block formatting <documentation-code-block-format-check>`.

These checks are run automatically in CI and must pass before documentation
changes can be merged. They can also be run locally with a single command:

.. console::

$ make check

This command runs all current checks and will include any new checks added in
the future.

.. _documentation-spelling-check:

Spelling check
--------------
~~~~~~~~~~~~~~

Before you commit your docs, it's a good idea to run the spelling checker.
You'll need to install :pypi:`sphinxcontrib-spelling` first. Then from the
Expand All @@ -177,6 +196,25 @@ one of the following:
* If, and only if, you are sure the word you are using is correct - add it
to ``docs/spelling_wordlist`` (please keep the list in alphabetical order).

.. _documentation-code-block-format-check:

Code block format check
~~~~~~~~~~~~~~~~~~~~~~~

All Python code blocks should be formatted using the :pypi:`blacken-docs`
auto-formatter. This is automatically run by the :ref:`pre-commit hook
<coding-style-pre-commit>` if configured.

The check can also be run manually: provided that ``blacken-docs`` is installed,
run the following command from the ``docs`` directory:

.. console::

$ make black

The formatter will report any issues by printing them to the terminal and will
reformat code blocks where possible.

.. _documentation-link-check:

Link check
Expand Down Expand Up @@ -305,10 +343,6 @@ documentation:
"last bit" of that path. So ``:mod:`~django.contrib.auth``` will
display a link with the title "auth".

* All Python code blocks should be formatted using the :pypi:`blacken-docs`
auto-formatter. This will be run by :ref:`pre-commit
<coding-style-pre-commit>` if that is configured.

* Use :mod:`~sphinx.ext.intersphinx` to reference Python's and Sphinx'
documentation.

Expand Down
28 changes: 22 additions & 6 deletions docs/make.bat
Original file line number Diff line number Diff line change
Expand Up @@ -189,20 +189,36 @@ results in %BUILDDIR%/doctest/output.txt.
)

if "%1" == "spelling" (
%SPHINXBUILD% -b spelling %ALLSPHINXOPTS% %BUILDDIR%/spelling
if errorlevel 1 exit /b 1
echo.
echo.Check finished. Wrong words can be found in %BUILDDIR%/^
spelling/output.txt.
call :run_spelling
goto end
)

if "%1" == "black" (
call :run_black
goto end
)

if "%1" == "check" (
call :run_black
call :run_spelling
echo.
echo.All checks completed.
goto end
)

:run_spelling
%SPHINXBUILD% -b spelling %ALLSPHINXOPTS% %BUILDDIR%/spelling
if errorlevel 1 exit /b 1
echo.
echo.Check finished. Wrong words can be found in %BUILDDIR%/spelling/output.txt.
exit /b

:run_black
for /f "usebackq tokens=*" %%i in (`dir *.txt /s /b ^| findstr /v /c:"_build" /c:"_theme"`) do (
blacken-docs --rst-literal-block %%i
)
echo.
echo.Code blocks reformatted
)
exit /b

:end
4 changes: 4 additions & 0 deletions docs/releases/6.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,10 @@ Miscellaneous
* The minimum supported version of ``asgiref`` is increased from 3.8.1 to
3.9.1.

* The :djadmin:`collectstatic` command now reports only a summary of skipped
files due to conflicts when ``--verbosity`` is 1. To see warnings for each
conflicting destination path, set the ``--verbosity`` flag to 2 or higher.

.. _deprecated-features-6.0:

Features deprecated in 6.0
Expand Down
4 changes: 2 additions & 2 deletions js_tests/gis/mapwidget.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ QUnit.test('initMapWidgetInSection initializes widgets and skips __prefix__', fu
wrapper1.innerHTML = `
<textarea id="id_point"></textarea>
<div class="dj_map" id="id_point_map"></div>
<script type="application/json" id="mapwidget-options">
<script type="application/json" id="id_point_mapwidget_options">
{ "geom_name": "Point" }
</script>
`;
Expand All @@ -154,7 +154,7 @@ QUnit.test('initMapWidgetInSection initializes widgets and skips __prefix__', fu
wrapper2.innerHTML = `
<textarea id="id_fake"></textarea>
<div class="dj_map" id="id_fake_map"></div>
<script type="application/json" id="mapwidget-options">
<script type="application/json" id="id_fake_mapwidget_options">
{ "geom_name": "MultiPoint" }
</script>
`;
Expand Down
3 changes: 2 additions & 1 deletion tests/admin_inlines/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,7 @@ def get_max_num(self, request, obj=None, **kwargs):
# admin for #19524
class SightingInline(admin.TabularInline):
model = Sighting
show_change_link = True


# admin and form for #18263
Expand Down Expand Up @@ -517,7 +518,7 @@ def get_inlines(self, request, obj):
site.register(BinaryTree, inlines=[BinaryTreeAdmin])
site.register(ExtraTerrestrial, inlines=[SightingInline])
site.register(SomeParentModel, inlines=[SomeChildModelInline])
site.register([Question, Inner4Stacked, Inner4Tabular])
site.register([Question, Inner4Stacked, Inner4Tabular, Sighting])
site.register(Teacher, TeacherAdmin)
site.register(Chapter, inlines=[FootNoteNonEditableInlineCustomForm])
site.register(OutfitItem, inlines=[WeaknessInlineCustomForm])
Expand Down
3 changes: 3 additions & 0 deletions tests/admin_inlines/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,9 @@ class Sighting(models.Model):
et = models.ForeignKey(ExtraTerrestrial, models.CASCADE)
place = models.CharField(max_length=100)

def __str__(self):
return self.place


# Models for #18263
class SomeParentModel(models.Model):
Expand Down
16 changes: 16 additions & 0 deletions tests/admin_inlines/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -2532,3 +2532,19 @@ def test_tabular_inline_delete_layout(self):
delete.get_attribute("innerHTML"),
)
self.take_screenshot("loaded")

@screenshot_cases(["desktop_size", "mobile_size", "rtl", "dark", "high_contrast"])
def test_tabular_inline_object_with_show_change_link(self):
from selenium.webdriver.common.by import By

et = ExtraTerrestrial.objects.create(name="test")
Sighting.objects.create(et=et, place="Desert")
self.admin_login(username="super", password="secret")
url = reverse("admin:admin_inlines_extraterrestrial_change", args=(et.pk,))
self.selenium.get(self.live_server_url + url)
object_str = self.selenium.find_element(
By.CSS_SELECTOR, "fieldset.module tbody tr td.original p"
)
self.assertTrue(object_str.is_displayed())
self.assertIn("Desert", object_str.text)
self.take_screenshot("tabular")
6 changes: 3 additions & 3 deletions tests/gis_tests/test_geoforms.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ class PointForm(forms.Form):
"id": "id_p",
"geom_name": "Point",
}
expected = json_script(attrs, "mapwidget-options")
expected = json_script(attrs, "id_p_mapwidget_options")
self.assertInHTML(expected, rendered)


Expand Down Expand Up @@ -305,7 +305,7 @@ def assertMapWidget(self, form_instance, geom_name):
"id": map_field.id_for_label,
"geom_name": geom_name,
}
expected = json_script(attrs, "mapwidget-options")
expected = json_script(attrs, f"{map_field.id_for_label}_mapwidget_options")
self.assertInHTML(expected, rendered)
self.assertIn("gis/js/OLMapWidget.js", str(form_instance.media))

Expand Down Expand Up @@ -475,7 +475,7 @@ class PointForm(forms.Form):
"id": "id_p",
"geom_name": "Point",
}
expected = json_script(attrs, "mapwidget-options")
expected = json_script(attrs, "id_p_mapwidget_options")
self.assertInHTML(expected, rendered)


Expand Down
Loading
Loading