Skip to content
Merged
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ answer newbie questions, and generally made Django that much better:
Dan Stephenson <http://dan.io/>
Dan Watson <http://danwatson.net/>
dave@thebarproject.com
Dave Gaeddert <dave.gaeddert@gmail.com>
David Ascher <https://ascher.ca/>
David Avsajanishvili <avsd05@gmail.com>
David Blewett <david@dawninglight.net>
Expand Down
9 changes: 6 additions & 3 deletions django/db/models/lookups.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import itertools
import math
from collections.abc import Iterator

from django.core.exceptions import EmptyResultSet, FullResultSet
from django.db.models.expressions import (
Expand Down Expand Up @@ -292,7 +293,9 @@ class FieldGetDbPrepValueIterableMixin(FieldGetDbPrepValueMixin):
def get_prep_lookup(self):
if hasattr(self.rhs, "resolve_expression"):
return self.rhs
if any(hasattr(value, "resolve_expression") for value in self.rhs):
# Prevent iterator from being consumed by any().
rhs = list(self.rhs) if isinstance(self.rhs, Iterator) else self.rhs
if any(hasattr(value, "resolve_expression") for value in rhs):
# Wrap direct values in Value expressions so they are handled by
# the database at compilation time, along with other expressions.
return ExpressionList(
Expand All @@ -302,11 +305,11 @@ def get_prep_lookup(self):
if hasattr(value, "resolve_expression")
else Value(value, getattr(self.lhs, "output_field", None))
)
for value in self.rhs
for value in rhs
]
)
prepared_values = []
for rhs_value in self.rhs:
for rhs_value in rhs:
if (
self.prepare_rhs
and hasattr(self.lhs, "output_field")
Expand Down
19 changes: 14 additions & 5 deletions django/db/models/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -1303,13 +1303,22 @@ def in_bulk(self, id_list=None, *, field_name="pk"):
def get_obj(obj):
return obj

selected_fields = tuple(
self.query.selected
or (
*self.query.extra_select,
*self.query.values_select,
*self.query.annotation_select,
)
)

if issubclass(self._iterable_class, ModelIterable):
# Raise an AttributeError if field_name is deferred.
get_key = operator.attrgetter(field_name)

elif issubclass(self._iterable_class, ValuesIterable):
if field_name not in self.query.values_select:
qs = qs.values(field_name, *self.query.values_select)
qs = qs.values(field_name, *selected_fields)

def get_obj(obj): # noqa: F811
# We can safely mutate the dictionaries returned by
Expand All @@ -1322,16 +1331,16 @@ def get_obj(obj): # noqa: F811

elif issubclass(self._iterable_class, ValuesListIterable):
try:
field_index = self.query.values_select.index(field_name)
field_index = selected_fields.index(field_name)
except ValueError:
# field_name is missing from values_select, so add it.
# field_name isn't selected, so add it.
field_index = 0
if issubclass(self._iterable_class, NamedValuesListIterable):
kwargs = {"named": True}
else:
kwargs = {}
get_obj = operator.itemgetter(slice(1, None))
qs = qs.values_list(field_name, *self.query.values_select, **kwargs)
qs = qs.values_list(field_name, *selected_fields, **kwargs)

get_key = operator.itemgetter(field_index)

Expand All @@ -1341,7 +1350,7 @@ def get_obj(obj): # noqa: F811
get_key = get_obj
else:
# Transform it back into a non-flat values_list().
qs = qs.values_list(field_name, *self.query.values_select)
qs = qs.values_list(field_name, *selected_fields)
get_key = operator.itemgetter(0)
get_obj = operator.itemgetter(1)

Expand Down
23 changes: 21 additions & 2 deletions django/db/models/sql/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -357,11 +357,30 @@ def _order_by_pairs(self):
# Avoid computing `selected_exprs` if there is no `ordering` as it's
# relatively expensive.
if ordering and (select := self.select):
distinct_fields = self.query.distinct_fields
annotation_select = self.query.annotation_select
# An expression can be selected at more than one position, e.g.
# when two lookup paths resolve to the same column. get_distinct()
# refers to such selections by expression and PostgreSQL binds an
# expression reference to the first position it is selected at, so
# ordering must refer to that position as well for the prefixes of
# both clauses to match. Raw selections are excluded as equal SQL
# is not necessarily interchangeable, e.g. a volatile function
# selected twice.
first_positions = {}
for ordinal, (expr, _, alias) in enumerate(select, start=1):
pos_expr = PositionRef(ordinal, alias, expr)
if distinct_fields and not isinstance(expr, RawSQL):
first_pos_expr = first_positions.setdefault(expr, pos_expr)
else:
first_pos_expr = pos_expr
if alias:
selected_exprs[alias] = pos_expr
selected_exprs[expr] = pos_expr
# get_distinct() refers to annotations by alias, which
# binds to their own position.
selected_exprs[alias] = (
pos_expr if alias in annotation_select else first_pos_expr
)
selected_exprs[expr] = first_pos_expr

for field in ordering:
if hasattr(field, "resolve_expression"):
Expand Down
12 changes: 12 additions & 0 deletions docs/howto/static-files/deployment.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,18 @@ As with all deployment tasks, the devil's in the details. Every production
setup will be a bit different, so you'll need to adapt the basic outline to fit
your needs. Below are a few common patterns that might help.

Having your Django application serve static files
-------------------------------------------------

While web servers are much better and faster at serving static files, it is
possible to have Django serve them using community-maintained packages. There
are static file packages highlighted on the `Community Ecosystem`_ page. The
Django Packages `Static Builders grid`_ has even more options for you!

.. _Community Ecosystem: https://www.djangoproject.com/community/ecosystem/#storage-static-files
.. _Static Builders grid: https://djangopackages.org/grids/g/static-builders/


Serving the site and your static files from the same server
-----------------------------------------------------------

Expand Down
20 changes: 18 additions & 2 deletions docs/ref/contrib/admin/actions.txt
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,8 @@ decorator and passing the ``permissions`` argument::
queryset.update(status="p")

The ``make_published()`` action will only be available to users that pass the
:meth:`.ModelAdmin.has_change_permission` check.
:meth:`.ModelAdmin.has_change_permission` check when it is called with
``obj=None``.

If ``permissions`` has more than one permission, the action will be available
as long as the user passes at least one of the checks.
Expand Down Expand Up @@ -441,10 +442,25 @@ For example::
codename = get_permission_codename("publish", opts)
return request.user.has_perm("%s.%s" % (opts.app_label, codename))

The admin doesn't automatically check object-level permissions for each
selected object when executing an action. To limit which objects an action may
modify based on object-level permissions, perform those checks in the action
itself. For example::

class ArticleAdmin(admin.ModelAdmin):
actions = ["make_published"]

@admin.action(permissions=["change"])
def make_published(self, request, queryset):
for obj in queryset:
if self.has_change_permission(request, obj=obj):
obj.status = "p"
obj.save(update_fields=["status"])

.. _admin-action-availability:

Controlling where actions are available
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
---------------------------------------

.. versionadded:: 6.1

Expand Down
28 changes: 23 additions & 5 deletions docs/ref/contrib/admin/index.txt
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,15 @@ Other topics

Having problems? Try :doc:`/faq/admin`.

.. admonition:: There are community-maintained solutions!

Django has a vibrant ecosystem. There are solutions for customizing and
extending the admin highlighted on the `Community Ecosystem`_ page. The
Django Packages `Admin interface grid`_ has even more options for you!

.. _Community Ecosystem: https://www.djangoproject.com/community/ecosystem/#admin
.. _Admin interface grid: https://djangopackages.org/grids/g/admin-interface/

``ModelAdmin`` objects
======================

Expand Down Expand Up @@ -1959,15 +1968,24 @@ default templates used by the :class:`ModelAdmin` views:

.. method:: ModelAdmin.has_view_permission(request, obj=None)

Should return ``True`` if viewing ``obj`` is permitted, ``False``
otherwise. If obj is ``None``, should return ``True`` or ``False`` to
indicate whether viewing of objects of this type is permitted in general
(e.g., ``False`` will be interpreted as meaning that the current user is
not permitted to view any object of this type).
Should return ``True`` if the user is permitted to access the change or
history view for ``obj``, and ``False`` otherwise. If obj is ``None``,
should return ``True`` or ``False`` to indicate whether viewing of objects
of this type is permitted in general (e.g., ``False`` will be interpreted
as meaning that the current user is not permitted to view any object of
this type).

The default implementation returns ``True`` if the user has either the
"change" or "view" permission.

.. admonition:: Object-level view permissions aren't visibility filters

Object-level view permissions don't prevent information about an object
from appearing elsewhere in the admin, including in the admin
changelist, related field choices, autocomplete results, and recent
actions. To restrict this information, customize the querysets used by
the relevant views and form fields.

.. method:: ModelAdmin.has_add_permission(request)

Should return ``True`` if adding an object is permitted, ``False``
Expand Down
10 changes: 10 additions & 0 deletions docs/ref/django-admin.txt
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,16 @@ notification and debug information that ``django-admin`` prints to the console.
Available commands
==================

.. admonition:: There are community-maintained solutions!

Django has a vibrant ecosystem. There are developer tool packages
highlighted on the `Community Ecosystem`_ page. The Django Packages
`Developer Tools grid`_ has even more options for you!

.. _Community Ecosystem: https://www.djangoproject.com/community/ecosystem/#debugging-development-tools
.. _Developer Tools grid: https://djangopackages.org/grids/g/developer-tools/


``check``
---------

Expand Down
16 changes: 14 additions & 2 deletions docs/releases/6.1.1.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@
Django 6.1.1 release notes
==========================

*Expected September 2, 2026*
*September 2, 2026*

Django 6.1.1 fixes several bugs in 6.1.
Django 6.1.1 fixes one crash in Django 5.2 and several bugs in 6.1.

Bugfixes
========

* Fixed a crash in Django 5.2 when combining :meth:`distinct(*fields)
<.QuerySet.distinct>` with ``order_by()`` and ``values()`` and using two
lookup paths resolving to the same column (:ticket:`37222`).

* Fixed a regression in Django 6.1 where the deprecation of double-dot variable
lookups incorrectly applied to string and translated template literals
containing two consecutive dots, such as ``{{ "a..b" }}`` (:ticket:`37257`).
Expand Down Expand Up @@ -50,3 +54,11 @@ Bugfixes
``choices``, and where any search term matched all rows with a ``True``
value when an ``__exact`` lookup was used on a ``BooleanField``
(:ticket:`37263`).

* Fixed a regression in Django 6.1 that caused ``__in`` lookups on annotations
to erroneously return empty querysets and ``__range`` lookups to crash when
passed an iterator (:ticket:`37311`).

* Fixed a bug in Django 6.1 where :meth:`.QuerySet.in_bulk` chained after
:meth:`.QuerySet.values` or :meth:`.QuerySet.values_list` could drop selected
annotations or produce incorrect mapping keys (:ticket:`37312`).
12 changes: 12 additions & 0 deletions docs/releases/6.1.2.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
==========================
Django 6.1.2 release notes
==========================

*Expected October 6, 2026*

Django 6.1.2 fixes several bugs in 6.1.1.

Bugfixes
========

* ...
1 change: 1 addition & 0 deletions docs/releases/index.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ versions of the documentation contain the release notes for any later releases.
.. toctree::
:maxdepth: 1

6.1.2
6.1.1
6.1

Expand Down
8 changes: 8 additions & 0 deletions docs/topics/auth/customizing.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ can be checked through Django's authorization system.
You can :ref:`extend <extending-user>` the default ``User`` model, or
:ref:`substitute <auth-custom-user>` a completely customized model.

.. admonition:: There are community-maintained solutions!

Django has a vibrant ecosystem. There are authentication and authorization
solutions highlighted on the `Community Ecosystem`_ page. The Django
Packages `Authentication grid`_ has even more options for you!

.. _Community Ecosystem: https://www.djangoproject.com/community/ecosystem/#authentication-authorization
.. _Authentication grid: https://djangopackages.org/grids/g/authentication/
.. _authentication-backends:

Other authentication sources
Expand Down
10 changes: 10 additions & 0 deletions docs/topics/auth/default.txt
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,16 @@ objects in the same way as any other :doc:`Django model
myuser.user_permissions.remove(permission, permission, ...)
myuser.user_permissions.clear()

.. admonition:: There are community-maintained solutions!

Django has a vibrant ecosystem. There are authentication and authorization
solutions highlighted on the `Community Ecosystem`_ page. The Django
Packages `Authorization grid`_ has even more options for you!

.. _Community Ecosystem: https://www.djangoproject.com/community/ecosystem/#authentication-authorization
.. _Authorization grid: https://djangopackages.org/grids/g/authorization/


Default permissions
-------------------

Expand Down
10 changes: 10 additions & 0 deletions docs/topics/class-based-views/index.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,16 @@ documentation</ref/class-based-views/index>`.
generic-editing
mixins

.. admonition:: There are community-maintained solutions!

Django has a vibrant ecosystem. There are generic view extensions
highlighted on the `Community Ecosystem`_ page that build on Django's
class-based views. The Django Packages `Class Based Views grid`_ has
even more options for you!

.. _Community Ecosystem: https://www.djangoproject.com/community/ecosystem/#forms-views
.. _Class Based Views grid: https://djangopackages.org/grids/g/cbv/

Basic examples
==============

Expand Down
9 changes: 9 additions & 0 deletions docs/topics/forms/index.txt
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,15 @@ Django handles three distinct parts of the work involved in forms:
It is *possible* to write code that does all of this manually, but Django can
take care of it all for you.

.. admonition:: There are community-maintained solutions!

Django has a vibrant ecosystem. There are solutions for customizing how
forms are rendered highlighted on the `Community Ecosystem`_ page. The
Django Packages `Forms grid`_ has even more options for you!

.. _Community Ecosystem: https://www.djangoproject.com/community/ecosystem/#forms-views
.. _Forms grid: https://djangopackages.org/grids/g/forms/

Forms in Django
===============

Expand Down
10 changes: 10 additions & 0 deletions docs/topics/i18n/translation.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2011,6 +2011,16 @@ A number of settings can be used to adjust language cookie options:
* :setting:`LANGUAGE_COOKIE_SAMESITE`
* :setting:`LANGUAGE_COOKIE_SECURE`

Translating text stored in models
---------------------------------

Currently Django does not support translating text stored in models. However,
there are community-maintained solutions on the `Community Ecosystem`_ page.
The Django Packages `Internationalization grid`_ has even more options for you!

.. _Community Ecosystem: https://www.djangoproject.com/community/ecosystem/#internationalization-localization
.. _Internationalization grid: https://djangopackages.org/grids/g/i18n/

Implementation notes
====================

Expand Down
Loading
Loading