Question: Multi-level FilteredRelation with selectrelated() may set wrong related object. Description test case: def testwrongselectrelated(self): with self.assertNumQueries(3): p = list(PoolStyle.objects.annotate( tournamentpool=FilteredRelation('pooltournamentpool'), ).selectrelated('tournamentpool')) self.assertEqual(p[0].pool.tournament, p[0].tournamentpool.tournament) result: FAIL: testwrongselectrelated () Traceback (most recent call last): File "D:\Work\django\tests\knownrelatedobjects\", line 171, in testwrongselectrelated self.assertEqual(p[0].pool.tournament, p[0].tournamentpool.tournament) AssertionError: <Tournament: Tournament object (1)!= <PoolStyle: PoolStyle object (1)

if from_obj:                     final_field.remote_field.set_cached_value(from_obj, obj) <ins>            def local_setter_noop(obj, from_obj):                pass</ins>             def remote_setter(name, obj, from_obj):                 setattr(from_obj, name, obj)


Question: Multi-level FilteredRelation with selectrelated() may set wrong related object. Description test case: def testwrongselectrelated(self): with self.assertNumQueries(3): p = list(PoolStyle.objects.annotate( tournamentpool=FilteredRelation('pooltournamentpool'), ).selectrelated('tournamentpool')) self.assertEqual(p[0].pool.tournament, p[0].tournamentpool.tournament) result: FAIL: testwrongselectrelated () Traceback (most recent call last): File "D:\Work\django\tests\knownrelatedobjects\", line 171, in testwrongselectrelated self.assertEqual(p[0].pool.tournament, p[0].tournamentpool.tournament) AssertionError: <Tournament: Tournament object (1)!= <PoolStyle: PoolStyle object (1)

"model": model,                         "field": final_field,                         "reverse": True,                        "local_setter": partial(local_setter, final_field),                        "local_setter": (                            partial(local_setter, final_field)                            if len(joins) <= 2                            else local_setter_noop                        ),                         "remote_setter": partial(remote_setter, name),                         "from_parent": from_parent,                     }


Question: ManifestStaticFilesStorage should expose a "hash" of the manifest file. Description It would be great if ManifestFilesMixin could expose a manifest_hash that changes whenever anything in the manifest itself changes. This would allow SPAs (or applications enhanced with htmx/unpoly etc) to send along a header in responses ala X-Asset-Hash and allow them to perform a full reload if the header changes. I'll be opening a PR for discussion soon.

class ManifestFilesMixin(HashedFilesMixin):    manifest_version = "1.0"  # the manifest format standard    manifest_version = "1.1"  # the manifest format standard     manifest_name = "staticfiles.json"     manifest_strict = True     keep_intermediate_files = False


Question: ManifestStaticFilesStorage should expose a "hash" of the manifest file. Description It would be great if ManifestFilesMixin could expose a manifest_hash that changes whenever anything in the manifest itself changes. This would allow SPAs (or applications enhanced with htmx/unpoly etc) to send along a header in responses ala X-Asset-Hash and allow them to perform a full reload if the header changes. I'll be opening a PR for discussion soon.

if manifest_storage is None:             manifest_storage = self         self.manifest_storage = manifest_storage        self.hashed_files = self.load_manifest()        self.hashed_files, self.manifest_hash = self.load_manifest()      def read_manifest(self):         try:


Question: ManifestStaticFilesStorage should expose a "hash" of the manifest file. Description It would be great if ManifestFilesMixin could expose a manifest_hash that changes whenever anything in the manifest itself changes. This would allow SPAs (or applications enhanced with htmx/unpoly etc) to send along a header in responses ala X-Asset-Hash and allow them to perform a full reload if the header changes. I'll be opening a PR for discussion soon.

def load_manifest(self):         content = self.read_manifest()         if content is None:            return {}            return {}, ""         try:             stored = json.loads(content)         except json.JSONDecodeError:             pass         else:             version = stored.get("version")            if version == "1.0":                return stored.get("paths", {})            if version in ("1.0", "1.1"):                return stored.get("paths", {}), stored.get("hash", "")         raise ValueError(             "Couldn't load manifest '%s' (version %s)"             % (self.manifest_name, self.manifest_version)


Question: ManifestStaticFilesStorage should expose a "hash" of the manifest file. Description It would be great if ManifestFilesMixin could expose a manifest_hash that changes whenever anything in the manifest itself changes. This would allow SPAs (or applications enhanced with htmx/unpoly etc) to send along a header in responses ala X-Asset-Hash and allow them to perform a full reload if the header changes. I'll be opening a PR for discussion soon.

self.save_manifest()      def save_manifest(self):        payload = {"paths": self.hashed_files, "version": self.manifest_version}        self.manifest_hash = self.file_hash(            None, ContentFile(json.dumps(sorted(self.hashed_files.items())).encode())        )        payload = {            "paths": self.hashed_files,            "version": self.manifest_version,            "hash": self.manifest_hash,        }         if self.manifest_storage.exists(self.manifest_name):             self.manifest_storage.delete(self.manifest_name)         contents = json.dumps(payload).encode()


Question: timesince() raises TypeError with USETZ=True and 1 month interval. Description (last modified by Sage Abdullah) As of , calling timesince() with a datetime object that's one month (or more) in the past and the USETZ setting is set to True results in the following crash: TypeError: can't subtract offset-naive and offset-aware datetimes Test: ... class TimesinceTests(TestCase): ... def testlongintervalwithtz(self): now = () d = now - datetime.timedelta(days=31) self.assertEqual(timesince(d), "1\xa0month") I believe this is because the pivot instantiated here:  does not take into account the datetime object's tzinfo. Adding 0, d.tzinfo arguments to the datetime.datetime call seems to fix this. Happy to send a PR.

d.hour,             d.minute,             d.second,<ins>            tzinfo=d.tzinfo,</ins>         )     else:         pivot = d


Question: Management command subparsers don’t retain error formatting Description Django management commands use a subclass of argparse.ArgumentParser, CommandParser, that takes some extra arguments to improve error formatting. These arguments are not copied into subparsers, created via CommandParser.addsubparsers().addparser(). Missing arguments to subparsers thus end as stack traces on the CLI, rather than human-facing usage messages. For example take this command with a subparser: from import BaseCommand class Command(BaseCommand): def addarguments(self, parser): subparsers = parser.addsubparsers(required=True) create = subparsers.addparser("create") create.addargument("name") def handle(self, args, *options): pass Missing the required subparser name argument gives the usage message, as for any normal argument: $ cheeses usage: cheeses [-h] [--version] [-v {0,1,2,3}] [--settings SETTINGS] [--pythonpath PYTHONPATH] [--traceback] [--no-color] [--force-color] [--skip-checks] {create} ... cheeses: error: the following arguments are required: {create} But missing the name argument to create fails with a stacktrace: $ cheeses create Traceback (most recent call last): File "", line 21, in <modulemain() ... File "", line 2131, in parseknownargs (('the following arguments are required: %s') % File "", line 72, in error raise CommandError("Error: %s" % message) Error: the following arguments are required: name We can correct this by ensuring that the subparser action returned by add_subparsers() copies the relevant arguments through to constructed subparsers. (Originally reported by Mark Gregson on django-developers:  )

import os import sys from argparse import ArgumentParser, HelpFormatter<ins>from functools import partial</ins> from io import TextIOBase  import django


Question: Management command subparsers don’t retain error formatting Description Django management commands use a subclass of argparse.ArgumentParser, CommandParser, that takes some extra arguments to improve error formatting. These arguments are not copied into subparsers, created via CommandParser.addsubparsers().addparser(). Missing arguments to subparsers thus end as stack traces on the CLI, rather than human-facing usage messages. For example take this command with a subparser: from import BaseCommand class Command(BaseCommand): def addarguments(self, parser): subparsers = parser.addsubparsers(required=True) create = subparsers.addparser("create") create.addargument("name") def handle(self, args, *options): pass Missing the required subparser name argument gives the usage message, as for any normal argument: $ cheeses usage: cheeses [-h] [--version] [-v {0,1,2,3}] [--settings SETTINGS] [--pythonpath PYTHONPATH] [--traceback] [--no-color] [--force-color] [--skip-checks] {create} ... cheeses: error: the following arguments are required: {create} But missing the name argument to create fails with a stacktrace: $ cheeses create Traceback (most recent call last): File "", line 21, in <modulemain() ... File "", line 2131, in parseknownargs (('the following arguments are required: %s') % File "", line 72, in error raise CommandError("Error: %s" % message) Error: the following arguments are required: name We can correct this by ensuring that the subparser action returned by add_subparsers() copies the relevant arguments through to constructed subparsers. (Originally reported by Mark Gregson on django-developers:  )

else:             raise CommandError("Error: %s" % message) <ins>    def add_subparsers(self, **kwargs):        parser_class = kwargs.get("parser_class", type(self))        if issubclass(parser_class, CommandParser):            kwargs["parser_class"] = partial(                parser_class,                called_from_command_line=self.called_from_command_line,            )        return super().add_subparsers(**kwargs)</ins>  def handle_default_options(options):     """


Question: floatformat() crashes on "0.00". Description from decimal import Decimal from django.template.defaultfilters import floatformat floatformat('0.00', 0) floatformat(Decimal('0.00'), 0) Both throw ValueError: valid range for prec is [1, MAX_PREC]

except (ValueError, OverflowError, InvalidOperation):         return input_val     if not m and p < 0:    if not m and p <= 0:         return mark_safe(             formats.number_format(                 "%d" % (int(d)),


Question: Exists annotations can return non-boolean results (i.e. None) if used with an empty QuerySet. Description I suspect this is following on from, but potentially separate to -- because that ticket starts out using Django 3.2 to observe that an empty queryset (EmptyQuerySet or whatever, via none()) can short circuit evaluation to be 0 as ... in the SQL query, which is exactly the same problem I observed. However, as far as I can tell, the result of an Exists(()) can still return values outside of True/False, namely, None. Using Django main as of (from Wed Jan 11 ... 2023), here's the behaviour on both postgres and sqlite. In both scenarios I'm using 3.10.2 with psycopg2==2.9.3 and sqlite3.sqliteversion is 3.37.0 and sqlite3.version is 2.6.0. IPython outputs 8 and 11 are the problems. class A(models.Model): pass class B(models.Model): pass In [1]: from import A, B In [2]: ("pg").create() Out[2]: <A: A object (1)In [3]: ("pg").create() Out[3]: <B: B object (1)In [4]: ("sqlite").create() Out[4]: <A: A object (1)In [4]: ("sqlite").create() Out[4]: <B: B object (1)In [5]: from import Exists In [6]: ("sqlite").annotate(shouldbebool=Exists(())).first().shouldbebool Out[6]: True In [7]: ("sqlite").annotate(shouldbebool=Exists((pk=))).first().shouldbebool Out[7]: False In [8]: ("sqlite").annotate(shouldbebool=Exists(())).first().shouldbebool In [9]: ("pg").annotate(shouldbebool=Exists(())).first().shouldbebool Out[9]: True In [10]: ("pg").annotate(shouldbebool=Exists((pk=))).first().shouldbebool Out[10]: False In [11]: ("pg").annotate(shouldbebool=Exists(())).first().shouldbebool And the queries, which are the same for postgres & sqlite: {'sql': 'SELECT "appa"."id", EXISTS(SELECT 1 AS "a" FROM "appb" LIMIT 1) AS "shouldbebool" FROM "appa" ORDER BY "appa"."id" ASC LIMIT 1', 'time': '0.001'}, {'sql': 'SELECT "appa"."id", EXISTS(SELECT 1 AS "a" FROM "appb" U0 WHERE U0."id" = LIMIT 1) AS "shouldbebool" FROM "appa" ORDER BY "appa"."id" ASC LIMIT 1', 'time': '0.001'}, {'sql': 'SELECT "appa"."id", NULL AS "shouldbebool" FROM "appa" ORDER BY "appa"."id" ASC LIMIT 1', 'time': '0.001'} Given Exists has an outputfield of BooleanField and that definition doesn't have null=True as an argument, it seems incongruent from both an expectations ("exists sounds boolean") and implementation ("it doesn't say it could be null") standpoint. Whilst the problem exists in main, it has also changed behaviour (presumably or potentially unexpectedly) since 3.2, where postgres and sqlite actually do different things, hence we tested both above. So main is now consistent, but I'd personally argue it's consistently wrong (for a given value thereof, no judgement made!) In 3.2.16, under sqlite, using annotate(x=Exists(y.none())) returns False but on main it now returns None (see above) -- the 3.2 behaviour is correct for my expectations In [4]: ("sqlite").annotate(shouldbebool=Exists(())).first().shouldbebool Out[4]: False In [5]: connections['sqlite'].queries Out[5]: {'sql': 'SELECT "appa"."id", 0 AS "shouldbebool" FROM "appa" ORDER BY "appa"."id" ASC LIMIT 1', 'time': '0.000'} In 3.2.16 with postgres we get neither None nor False but the integer 0 instead: In [4]: ("pg").annotate(shouldbebool=Exists(())).first().shouldbebool Out[4]: 0 In [5]: connections['pg'].queries Out[5]: {'sql': 'SELECT "appa"."id", 0 AS "shouldbebool" FROM "appa" ORDER BY "app_a"."id" ASC LIMIT 1', 'time': '0.001'} So we can observe that under 3.2 using the 0 AS ... behaviour sqlite appears to behave correctly (returning False) postgres appears to behave incorrectly (failing to cast a raw integer to a boolean) And under main using the NULL AS ... behaviour sqlite no longer behaves the same, returning None where I'd expect False (or even True given the way SQL EXISTS works...) postgres behaves differently, 0 is now None but I'd still expect True or False as the output.

class Exists(Subquery):     template = "EXISTS(%(subquery)s)"     output_field = fields.BooleanField()<ins>    empty_result_set_value = False</ins>      def __init__(self, queryset, **kwargs):         super().__init__(queryset, **kwargs)


Question: Callable storage on FileField fails to deconstruct when it returns defaultstorage Description If the storage argument on a FileField is set to a callable that returns defaultstorage, it is omitted from the deconstructed form of the field, rather than being included as a reference to the callable as expected. For example, given a model definition: from import FileSystemStorage, defaultstorage from import models import random otherstorage = FileSystemStorage(location='/media/other') def getstorage(): return ([defaultstorage, otherstorage]) class MyModel(models.Model): myfile = models.FileField(storage=getstorage) repeatedly running makemigrations will randomly generate a migration that alternately includes or omits on the FileField definition. This case was overlooked in the fix for - the deconstruct method tests if self.storage is not defaultstorage to determine whether to add the storage kwarg, but at this point self.storage is the evaluated version, so it wrongly returns false for a callable that returns defaultstorage.

if kwargs.get("max_length") == 100:             del kwargs["max_length"]         kwargs["upload_to"] = self.upload_to        if self.storage is not default_storage:            kwargs["storage"] = getattr(self, "_storage_callable", self.storage)        storage = getattr(self, "_storage_callable", self.storage)        if storage is not default_storage:            kwargs["storage"] = storage         return name, path, args, kwargs      def get_internal_type(self):


Question: Validation of UniqueConstraint with ordered expressions crashes. Description I this model: class Foo(models.Model): name = models.CharField(maxlength=300, unique=True) class Meta: constraints = [ UniqueConstraint( Lower("name").desc(), name="uniquelowername" ) ] and this admin class: class FooAdmin(admin.ModelAdmin): searchfields = ("name",) I based the UniqueConstraint on the documentation (), which shows UniqueConstraint(Lower('name').desc(), 'category', name='uniquelowernamecategory') When I visit the admin and click "add foo", enter name "foo1", and click Save, I get a stack trace: Request Method: POST Request URL: http://localhost:8000/admin/myapp/foo/add/ Django Version: 4.1.5 Python Version: 3.10.9 ... Traceback (most recent call last): File ".../lib/python3.10/site-", line 89, in execute return (sql, params) The above exception (syntax error at or near "DESC" LINE 1: ...werappfoo" WHERE LOWER("myappfoo"."name") DESC = (LO... ^ ) was the direct cause of the following exception: File ".../lib/python3.10/site-", line 55, in inner response = getresponse(request) File ".../lib/python3.10/site-", line 197, in getresponse response = wrappedcallback(request, callbackargs, callbackkwargs) File ".../lib/python3.10/site-", line 686, in wrapper return self.adminsite.adminview(view)(args, kwargs) File ".../lib/python3.10/site-", line 133, in wrappedview response = viewfunc(request, args, kwargs) File ".../lib/python3.10/site-", line 62, in wrappedviewfunc response = viewfunc(request, args, kwargs) File ".../lib/python3.10/site-", line 242, in inner return view(request, args, kwargs) File ".../lib/python3.10/site-", line 1890, in addview return self.changeformview(request, None, formurl, extracontext) File ".../lib/python3.10/site-", line 46, in wrapper return boundmethod(args, kwargs) File ".../lib/python3.10/site-", line 133, in wrappedview response = viewfunc(request, args, *kwargs) File ".../lib/python3.10/site-", line 1750, in changeformview return self.changeformview(request, objectid, formurl, extracontext) File ".../lib/python3.10/site-", line 1796, in changeformview formvalidated = form.isvalid() File ".../lib/python3.10/site-", line 205, in isvalid return self.isbound and not File ".../lib/python3.10/site-", line 200, in errors self.fullclean() File ".../lib/python3.10/site-", line 439, in fullclean self.postclean() File ".../lib/python3.10/site-", line 492, in postclean self.instance.fullclean(exclude=exclude, validateunique=False) File ".../lib/python3.10/site-", line 1472, in fullclean self.validateconstraints(exclude=exclude) File ".../lib/python3.10/site-", line 1423, in validateconstraints constraint.validate(modelclass, self, exclude=exclude, using=using) File ".../lib/python3.10/site-", line 347, in validate if (): File ".../lib/python3.10/site-", line 1226, in exists return () File ".../lib/python3.10/site-", line 592, in hasresults return compiler.hasresults() File ".../lib/python3.10/site-", line 1366, in hasresults return bool(self.executesql(SINGLE)) File ".../lib/python3.10/site-", line 1398, in executesql cursor.execute(sql, params) File ".../lib/python3.10/site-", line 230, in execute return (, sql, params) File ".../lib/python3.10/site-", line 154, in record return method(sql, params) File ".../lib/python3.10/site-", line 103, in execute return super().execute(sql, params) File ".../lib/python3.10/site-", line 67, in execute return self.executewithwrappers( File ".../lib/python3.10/site-", line 80, in executewithwrappers return executor(sql, params, many, context) File ".../lib/python3.10/site-", line 84, in execute with File ".../lib/python3.10/site-", line 91, in exit raise djexcvalue.withtraceback(traceback) from excvalue File ".../lib/python3.10/site-", line 89, in execute return (sql, params) Exception Type: ProgrammingError at /admin/myapp/foo/add/ Exception Value: syntax error at or near "DESC" LINE 1: ...myappfoo" WHERE LOWER("myappfoo"."name") DESC = (LO... ^ This happens on the Postgres backend (psycopg2 2.9.5). I also get this error using the sqlite backend. Exception Type: OperationalError at /admin/myapp/foo/add/ Exception Value: near "DESC": syntax error

from django.core.exceptions import FieldError, ValidationError from django.db import connectionsfrom django.db.models.expressions import Exists, ExpressionList, Ffrom django.db.models.expressions import Exists, ExpressionList, F, OrderBy from django.db.models.indexes import IndexExpression from django.db.models.lookups import Exact from django.db.models.query_utils import Q


Question: Validation of UniqueConstraint with ordered expressions crashes. Description I this model: class Foo(models.Model): name = models.CharField(maxlength=300, unique=True) class Meta: constraints = [ UniqueConstraint( Lower("name").desc(), name="uniquelowername" ) ] and this admin class: class FooAdmin(admin.ModelAdmin): searchfields = ("name",) I based the UniqueConstraint on the documentation (), which shows UniqueConstraint(Lower('name').desc(), 'category', name='uniquelowernamecategory') When I visit the admin and click "add foo", enter name "foo1", and click Save, I get a stack trace: Request Method: POST Request URL: http://localhost:8000/admin/myapp/foo/add/ Django Version: 4.1.5 Python Version: 3.10.9 ... Traceback (most recent call last): File ".../lib/python3.10/site-", line 89, in execute return (sql, params) The above exception (syntax error at or near "DESC" LINE 1: ...werappfoo" WHERE LOWER("myappfoo"."name") DESC = (LO... ^ ) was the direct cause of the following exception: File ".../lib/python3.10/site-", line 55, in inner response = getresponse(request) File ".../lib/python3.10/site-", line 197, in getresponse response = wrappedcallback(request, callbackargs, callbackkwargs) File ".../lib/python3.10/site-", line 686, in wrapper return self.adminsite.adminview(view)(args, kwargs) File ".../lib/python3.10/site-", line 133, in wrappedview response = viewfunc(request, args, kwargs) File ".../lib/python3.10/site-", line 62, in wrappedviewfunc response = viewfunc(request, args, kwargs) File ".../lib/python3.10/site-", line 242, in inner return view(request, args, kwargs) File ".../lib/python3.10/site-", line 1890, in addview return self.changeformview(request, None, formurl, extracontext) File ".../lib/python3.10/site-", line 46, in wrapper return boundmethod(args, kwargs) File ".../lib/python3.10/site-", line 133, in wrappedview response = viewfunc(request, args, *kwargs) File ".../lib/python3.10/site-", line 1750, in changeformview return self.changeformview(request, objectid, formurl, extracontext) File ".../lib/python3.10/site-", line 1796, in changeformview formvalidated = form.isvalid() File ".../lib/python3.10/site-", line 205, in isvalid return self.isbound and not File ".../lib/python3.10/site-", line 200, in errors self.fullclean() File ".../lib/python3.10/site-", line 439, in fullclean self.postclean() File ".../lib/python3.10/site-", line 492, in postclean self.instance.fullclean(exclude=exclude, validateunique=False) File ".../lib/python3.10/site-", line 1472, in fullclean self.validateconstraints(exclude=exclude) File ".../lib/python3.10/site-", line 1423, in validateconstraints constraint.validate(modelclass, self, exclude=exclude, using=using) File ".../lib/python3.10/site-", line 347, in validate if (): File ".../lib/python3.10/site-", line 1226, in exists return () File ".../lib/python3.10/site-", line 592, in hasresults return compiler.hasresults() File ".../lib/python3.10/site-", line 1366, in hasresults return bool(self.executesql(SINGLE)) File ".../lib/python3.10/site-", line 1398, in executesql cursor.execute(sql, params) File ".../lib/python3.10/site-", line 230, in execute return (, sql, params) File ".../lib/python3.10/site-", line 154, in record return method(sql, params) File ".../lib/python3.10/site-", line 103, in execute return super().execute(sql, params) File ".../lib/python3.10/site-", line 67, in execute return self.executewithwrappers( File ".../lib/python3.10/site-", line 80, in executewithwrappers return executor(sql, params, many, context) File ".../lib/python3.10/site-", line 84, in execute with File ".../lib/python3.10/site-", line 91, in exit raise djexcvalue.withtraceback(traceback) from excvalue File ".../lib/python3.10/site-", line 89, in execute return (sql, params) Exception Type: ProgrammingError at /admin/myapp/foo/add/ Exception Value: syntax error at or near "DESC" LINE 1: ...myappfoo" WHERE LOWER("myappfoo"."name") DESC = (LO... ^ This happens on the Postgres backend (psycopg2 2.9.5). I also get this error using the sqlite backend. Exception Type: OperationalError at /admin/myapp/foo/add/ Exception Value: near "DESC": syntax error

meta=model._meta, exclude=exclude                 ).items()             }            expressions = [                Exact(expr, expr.replace_expressions(replacements))                for expr in self.expressions            ]            expressions = []            for expr in self.expressions:                # Ignore ordering.                if isinstance(expr, OrderBy):                    expr = expr.expression                expressions.append(Exact(expr, expr.replace_expressions(replacements)))             queryset = queryset.filter(*expressions)         model_class_pk = instance._get_pk_val(model._meta)         if not instance._state.adding and model_class_pk is not None:


Question: After runserver returns response body for HTTP HEAD requests Description For compliance with RFC 2616, section 4.3, response bodies must not be returned for HEAD requests. In , the stripping of the response bodies was removed from Django in favour of letting the server perform the body removal, since the common servers (gunicorn, mod_wsgi etc) already do so. However it appears that runserver does not strip the body, contrary to: As such, starting in Django 1.10 the responses from runserver for HEAD requests are no longer compliant with the spec. (In certain configurations this also results in "Broken pipe" error messages in runserver output, since compliant user agents expect to be able to terminate the connection after the headers are sent.) STR: 1) mkvirtualenv django-test 2) pip install 'Django1.10,<1.11' 3) django-admin startproject django-test 4) cd django-test 5) runserver 6) In another terminal, run curl -iX HEAD http://127.0.0.1:8000/ 7) Observe response from curl Expected: HTTP/1.0 200 OK Date: Fri, 07 Apr 2017 14:56:39 GMT Server: WSGIServer/0.2 CPython/3.4.5 Content-Type: text/html X-Frame-Options: SAMEORIGIN Actual: HTTP/1.0 200 OK Date: Fri, 07 Apr 2017 14:56:39 GMT Server: WSGIServer/0.2 CPython/3.4.5 Content-Type: text/html X-Frame-Options: SAMEORIGIN <!DOCTYPE html<html lang="en"<head<meta http-equiv="content-type" content="text/html; charset=utf-8"<meta name="robots" content="NONE,NOARCHIVE"<titleWelcome to Django</title... Tested with Python 2.7.13 and 3.4.5. Doesn't reproduce under Django 1.9.13.

import socket import socketserver import sys<ins>from collections import deque</ins> from wsgiref import simple_server  from django.core.exceptions import ImproperlyConfigured


Question: After runserver returns response body for HTTP HEAD requests Description For compliance with RFC 2616, section 4.3, response bodies must not be returned for HEAD requests. In , the stripping of the response bodies was removed from Django in favour of letting the server perform the body removal, since the common servers (gunicorn, mod_wsgi etc) already do so. However it appears that runserver does not strip the body, contrary to: As such, starting in Django 1.10 the responses from runserver for HEAD requests are no longer compliant with the spec. (In certain configurations this also results in "Broken pipe" error messages in runserver output, since compliant user agents expect to be able to terminate the connection after the headers are sent.) STR: 1) mkvirtualenv django-test 2) pip install 'Django1.10,<1.11' 3) django-admin startproject django-test 4) cd django-test 5) runserver 6) In another terminal, run curl -iX HEAD http://127.0.0.1:8000/ 7) Observe response from curl Expected: HTTP/1.0 200 OK Date: Fri, 07 Apr 2017 14:56:39 GMT Server: WSGIServer/0.2 CPython/3.4.5 Content-Type: text/html X-Frame-Options: SAMEORIGIN Actual: HTTP/1.0 200 OK Date: Fri, 07 Apr 2017 14:56:39 GMT Server: WSGIServer/0.2 CPython/3.4.5 Content-Type: text/html X-Frame-Options: SAMEORIGIN <!DOCTYPE html<html lang="en"<head<meta http-equiv="content-type" content="text/html; charset=utf-8"<meta name="robots" content="NONE,NOARCHIVE"<titleWelcome to Django</title... Tested with Python 2.7.13 and 3.4.5. Doesn't reproduce under Django 1.9.13.

def cleanup_headers(self):         super().cleanup_headers()        if (            self.environ["REQUEST_METHOD"] == "HEAD"            and "Content-Length" in self.headers        ):            del self.headers["Content-Length"]         # HTTP/1.1 requires support for persistent connections. Send 'close' if         # the content length is unknown to prevent clients from reusing the         # connection.        if "Content-Length" not in self.headers:        if (            self.environ["REQUEST_METHOD"] != "HEAD"            and "Content-Length" not in self.headers        ):             self.headers["Connection"] = "close"         # Persistent connections require threading server.         elif not isinstance(self.request_handler.server, socketserver.ThreadingMixIn):


Question: After runserver returns response body for HTTP HEAD requests Description For compliance with RFC 2616, section 4.3, response bodies must not be returned for HEAD requests. In , the stripping of the response bodies was removed from Django in favour of letting the server perform the body removal, since the common servers (gunicorn, mod_wsgi etc) already do so. However it appears that runserver does not strip the body, contrary to: As such, starting in Django 1.10 the responses from runserver for HEAD requests are no longer compliant with the spec. (In certain configurations this also results in "Broken pipe" error messages in runserver output, since compliant user agents expect to be able to terminate the connection after the headers are sent.) STR: 1) mkvirtualenv django-test 2) pip install 'Django1.10,<1.11' 3) django-admin startproject django-test 4) cd django-test 5) runserver 6) In another terminal, run curl -iX HEAD http://127.0.0.1:8000/ 7) Observe response from curl Expected: HTTP/1.0 200 OK Date: Fri, 07 Apr 2017 14:56:39 GMT Server: WSGIServer/0.2 CPython/3.4.5 Content-Type: text/html X-Frame-Options: SAMEORIGIN Actual: HTTP/1.0 200 OK Date: Fri, 07 Apr 2017 14:56:39 GMT Server: WSGIServer/0.2 CPython/3.4.5 Content-Type: text/html X-Frame-Options: SAMEORIGIN <!DOCTYPE html<html lang="en"<head<meta http-equiv="content-type" content="text/html; charset=utf-8"<meta name="robots" content="NONE,NOARCHIVE"<titleWelcome to Django</title... Tested with Python 2.7.13 and 3.4.5. Doesn't reproduce under Django 1.9.13.

self.get_stdin().read()         super().close() <ins>    def finish_response(self):        if self.environ["REQUEST_METHOD"] == "HEAD":            try:                deque(self.result, maxlen=0)  # Consume iterator.                # Don't call self.finish_content() as, if the headers have not                # been sent and Content-Length isn't set, it'll default to "0"                # which will prevent omission of the Content-Length header with                # HEAD requests as permitted by RFC 9110 Section 9.3.2.                # Instead, send the headers, if not sent yet.                if not self.headers_sent:                    self.send_headers()            finally:                self.close()        else:            super().finish_response()</ins>  class WSGIRequestHandler(simple_server.WSGIRequestHandler):     protocol_version = "HTTP/1.1"


Question: Support create defaults for updateorcreate Description I proposed the idea of extending updateorcreate to support specifying a different set of defaults for the create operation on the . There seems to be consensus it's a positive add to Django. Adam raised concerns with my proposed approach of adding a createdefaults parameter to the function since this would conflict with any fields on a model named, createdefaults. Jeff did a code search on github for that term and didn't find any matches. I suspect if someone where using a field named createdefaults, it would be a JSON or object type field. Those don't seem like reasonable candidates to be part of a UniqueConstraint, which should be underlying the look-up arguments to updateorcreate. I do like the idea of having a separate parameter for createdefaults, but if we must preserve 100% backwards compatibility, Adam's suggestion of having defaults be set to another object makes the most sense. My blocking question is, which approach should I take? From the forum post: I’ve run into a use-case in which it’d be helpful to have the ability to specify a different set of defaults for the update operation compared to the create operation. While I don’t expect my particular use case to translate, here’s a more generic one. Given the following Record model: class Record(models.Model): someid = models.CharField(unique=True) createdby = models.ForeignKey(User, ...) modifiedby = models.ForeignKey(User, null=True, blank=True, ...) When a record is created, we would want to set createdby, but if it’s being updated, we’d want to set modifiedby. This use case can’t be solved by using updateorcreate, unless it allows for us to specify a different set of default values. Record.objects.updateorcreate( someid=somevalue, defaults={"modifiedby": user}, createdefaults={"createdby": user}, )

**kwargs,         )     def update_or_create(self, defaults=None, **kwargs):    def update_or_create(self, defaults=None, create_defaults=None, **kwargs):         """         Look up an object with the given kwargs, updating one with defaults        if it exists, otherwise create a new one.        if it exists, otherwise create a new one. Optionally, an object can        be created with different values than defaults by using        create_defaults.         Return a tuple (object, created), where created is a boolean         specifying whether an object was created.         """        defaults = defaults or {}        if create_defaults is None:            update_defaults = create_defaults = defaults or {}        else:            update_defaults = defaults or {}         self._for_write = True         with transaction.atomic(using=self.db):             # Lock the row so that a concurrent update is blocked until             # update_or_create() has performed its save.            obj, created = self.select_for_update().get_or_create(defaults, **kwargs)            obj, created = self.select_for_update().get_or_create(                create_defaults, **kwargs            )             if created:                 return obj, created            for k, v in resolve_callables(defaults):            for k, v in resolve_callables(update_defaults):                 setattr(obj, k, v)             update_fields = set(defaults)            update_fields = set(update_defaults)             concrete_field_names = self.model._meta._non_pk_concrete_field_names             # update_fields does not support non-concrete fields.             if concrete_field_names.issuperset(update_fields):


Question: Support create defaults for updateorcreate Description I proposed the idea of extending updateorcreate to support specifying a different set of defaults for the create operation on the . There seems to be consensus it's a positive add to Django. Adam raised concerns with my proposed approach of adding a createdefaults parameter to the function since this would conflict with any fields on a model named, createdefaults. Jeff did a code search on github for that term and didn't find any matches. I suspect if someone where using a field named createdefaults, it would be a JSON or object type field. Those don't seem like reasonable candidates to be part of a UniqueConstraint, which should be underlying the look-up arguments to updateorcreate. I do like the idea of having a separate parameter for createdefaults, but if we must preserve 100% backwards compatibility, Adam's suggestion of having defaults be set to another object makes the most sense. My blocking question is, which approach should I take? From the forum post: I’ve run into a use-case in which it’d be helpful to have the ability to specify a different set of defaults for the update operation compared to the create operation. While I don’t expect my particular use case to translate, here’s a more generic one. Given the following Record model: class Record(models.Model): someid = models.CharField(unique=True) createdby = models.ForeignKey(User, ...) modifiedby = models.ForeignKey(User, null=True, blank=True, ...) When a record is created, we would want to set createdby, but if it’s being updated, we’d want to set modifiedby. This use case can’t be solved by using updateorcreate, unless it allows for us to specify a different set of default values. Record.objects.updateorcreate( someid=somevalue, defaults={"modifiedby": user}, createdefaults={"createdby": user}, )

obj.save(using=self.db)         return obj, False     async def aupdate_or_create(self, defaults=None, **kwargs):    async def aupdate_or_create(self, defaults=None, create_defaults=None, **kwargs):         return await sync_to_async(self.update_or_create)(             defaults=defaults,            create_defaults=create_defaults,             **kwargs,         )


Question: Admin Site shall filter LogEntries by registered models Description This ticket has been discussed here:  If an implementer registers more than one AdminSite, one might expect that only changes on models registered at that specific site are logged. This currently is not the case, all registered sites show all entries of LogEntry. It is confusing for users to access a specific site and see log entries for models they can't access.

"available_apps": self.get_app_list(request),             "is_popup": False,             "is_nav_sidebar_enabled": self.enable_nav_sidebar,<ins>            "log_entries": self.get_log_entries(request),</ins>         }      def password_change(self, request, extra_context=None):


Question: Admin Site shall filter LogEntries by registered models Description This ticket has been discussed here:  If an implementer registers more than one AdminSite, one might expect that only changes on models registered at that specific site are logged. This currently is not the case, all registered sites show all entries of LogEntry. It is confusing for users to access a specific site and see log entries for models they can't access.

context,         )     def get_log_entries(self, request):        from django.contrib.admin.models import LogEntry        return LogEntry.objects.select_related("content_type", "user")  class DefaultAdminSite(LazyObject):     def _setup(self):diff --git a/django/contrib/admin/templatetags/log.py b/django/contrib/admin/templatetags/log.py-- a/django/contrib/admin/templatetags/log.py++ b/django/contrib/admin/templatetags/log.py


Question: Admin Site shall filter LogEntries by registered models Description This ticket has been discussed here:  If an implementer registers more than one AdminSite, one might expect that only changes on models registered at that specific site are logged. This currently is not the case, all registered sites show all entries of LogEntry. It is confusing for users to access a specific site and see log entries for models they can't access.

from django import template<del>from django.contrib.admin.models import LogEntry</del>  register = template.Library()


Question: Admin Site shall filter LogEntries by registered models Description This ticket has been discussed here:  If an implementer registers more than one AdminSite, one might expect that only changes on models registered at that specific site are logged. This currently is not the case, all registered sites show all entries of LogEntry. It is confusing for users to access a specific site and see log entries for models they can't access.

return "<GetAdminLog Node>"      def render(self, context):        if self.user is None:            entries = LogEntry.objects.all()        else:        entries = context["log_entries"]        if self.user is not None:             user_id = self.user             if not user_id.isdigit():                 user_id = context[self.user].pk            entries = LogEntry.objects.filter(user__pk=user_id)        context[self.varname] = entries.select_related("content_type", "user")[            : int(self.limit)        ]            entries = entries.filter(user__pk=user_id)        context[self.varname] = entries[: int(self.limit)]         return ""


Question: Mixed-case views/templates names causes 404 on :view:/:template: directive. Description  Using a class based view, class OrderSearch(LoginRequiredMixin, UserPassesTestMixin, ListView): add a doc comment such as causes a 404 when you click on the link in the docs Page not found (404) Request Method: GET Request URL:  Raised by: I'm not sure exactly where orders becomes lowercase, but I thought it might have something to do with the getview_func

def create_reference_role(rolename, urlbase):<ins>    # Views and template names are case-sensitive.    is_case_sensitive = rolename in ["template", "view"]</ins>     def _role(name, rawtext, text, lineno, inliner, options=None, content=None):         if options is None:             options = {}


Question: Mixed-case views/templates names causes 404 on :view:/:template: directive. Description  Using a class based view, class OrderSearch(LoginRequiredMixin, UserPassesTestMixin, ListView): add a doc comment such as causes a 404 when you click on the link in the docs Page not found (404) Request Method: GET Request URL:  Raised by: I'm not sure exactly where orders becomes lowercase, but I thought it might have something to do with the getview_func

urlbase                 % (                     inliner.document.settings.link_base,                    text.lower(),                    text if is_case_sensitive else text.lower(),                 )             ),             **options,


Question: "showsaveasnew" in admin can add without this permission Description (last modified by Mariusz Felisiak) At "" file, line 102, I think you must put one more verification for this tag: "and hasaddpermission", because "saveasnew" is a add modification. I rewrite this for my project: "showsaveasnew": not ispopup and hasaddpermission # This line that I put!!! and haschangepermission and change and save_as,

and context.get("show_delete", True)             ),             "show_save_as_new": not is_popup            and has_change_permission            and has_add_permission             and change             and save_as,             "show_save_and_add_another": can_save_and_add_another,


Question: Duplicate model names in M2M relationship causes RenameModel migration failure Description Example code is here:  I have a django project with two apps, incidents and vault, that both have a model named Incident. The vault Incident model has an M2M involving the incidents Incident model. When the table is created for this M2M relationship the automatic field names are "fromincidentid" and "toincidentid" since models have the same names. If I then try to use a RenameModel in a migration... operations = [ migrations.RenameModel( oldname='Incident', newname='Folder', ), ] it fails with this traceback: Tracking file by folder pattern: migrations Operations to perform: Apply all migrations: admin, auth, contenttypes, incidents, sessions, vault Running migrations: Applying vault.0002renameincidentfolder...Traceback (most recent call last): File "/Users/zacmiller/PycharmProjects/virtualenvs/edemo/lib/python3.10/site-", line 668, in getfield return self.fieldsmap[fieldname] KeyError: 'incident' During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/Users/zacmiller/Library/Application Support/JetBrains/Toolbox/apps/PyCharm-P/ch-", line 52, in <moduleruncommand() File "/Users/zacmiller/Library/Application Support/JetBrains/Toolbox/apps/PyCharm-P/ch-", line 46, in runcommand runmodule(managefile, None, 'main', True) File "", line 209, in runmodule return runmodulecode(code, initglobals, runname, modspec) File "", line 96, in runmodulecode runcode(code, modglobals, initglobals, File "", line 86, in runcode exec(code, runglobals) File "", line 22, in <modulemain() File "", line 18, in main executefromcommandline() File "/Users/zacmiller/PycharmProjects/virtualenvs/edemo/lib/python3.10/site-", line 446, in executefromcommandline utility.execute() File "/Users/zacmiller/PycharmProjects/virtualenvs/edemo/lib/python3.10/site-", line 440, in execute self.fetchcommand(subcommand).runfromargv() File "/Users/zacmiller/PycharmProjects/virtualenvs/edemo/lib/python3.10/site-", line 402, in runfromargv self.execute(args, cmdoptions) File "/Users/zacmiller/PycharmProjects/virtualenvs/edemo/lib/python3.10/site-", line 448, in execute output = (args, options) File "/Users/zacmiller/PycharmProjects/virtualenvs/edemo/lib/python3.10/site-", line 96, in wrapped res = handlefunc(args, *kwargs) File "/Users/zacmiller/PycharmProjects/virtualenvs/edemo/lib/python3.10/site-", line 349, in handle postmigratestate = executor.migrate( File "/Users/zacmiller/PycharmProjects/virtualenvs/edemo/lib/python3.10/site-", line 135, in migrate state = self.migrateallforwards( File "/Users/zacmiller/PycharmProjects/virtualenvs/edemo/lib/python3.10/site-", line 167, in migrateallforwards state = self.applymigration( File "/Users/zacmiller/PycharmProjects/virtualenvs/edemo/lib/python3.10/site-", line 252, in applymigration state = (state, schemaeditor) File "/Users/zacmiller/PycharmProjects/virtualenvs/edemo/lib/python3.10/site-", line 130, in apply operation.databaseforwards( File "/Users/zacmiller/PycharmProjects/virtualenvs/edemo/lib/python3.10/site-", line 422, in databaseforwards (), File "/Users/zacmiller/PycharmProjects/virtualenvs/edemo/lib/python3.10/site-", line 670, in getfield raise FieldDoesNotExist( Incidentincidents has no field named 'incident'

or not new_field.remote_field.through._meta.auto_created                 ):                     continue                # Rename the M2M table that's based on this model's name.                old_m2m_model = old_field.remote_field.through                new_m2m_model = new_field.remote_field.through                schema_editor.alter_db_table(                    new_m2m_model,                    old_m2m_model._meta.db_table,                    new_m2m_model._meta.db_table,                )                # Rename the column in the M2M table that's based on this                # model's name.                schema_editor.alter_field(                    new_m2m_model,                    old_m2m_model._meta.get_field(old_model._meta.model_name),                    new_m2m_model._meta.get_field(new_model._meta.model_name),                # Rename columns and the M2M table.                schema_editor._alter_many_to_many(                    new_model,                    old_field,                    new_field,                    strict=False,                 )      def database_backwards(self, app_label, schema_editor, from_state, to_state):


Question: Formsets' addfields() method fails in some circumstances if the argument index is None. Description Formsets' addfields() method fails in some circumstances if the argument index is None. When a FormSet has the attributes self.candelete == True and self.candeleteextra == False, calling the addfields() method on that FormSet fails if the argument index is None. This occurs for example when calling FormSet.emptyform(). The result is that the method raises the exception TypeError: '<' not supported between instances of 'NoneType' and 'int'. Code example: MyFormSet = forms.formsetfactory( form=MyForm, candelete=True, candeleteextra=False, ) myformset = MyFormSet( initial=None, ) print(myformset.emptyform) The reason this happens is that in in line 493 of index is compared to initialformcount: if self.candelete and (self.candeleteextra or index < initialformcount): Checking for index not None should fix the issue: if self.candelete and (self.candeleteextra or (index is not None and index < initialformcount)): How to Reproduce A self-contained example to reproduce this bug is as follows: #!/usr/bin/env python3 import os import django from django import forms class MyForm(forms.Form): myfield = forms.CharField() if name == "main": settingsfile = ((file))[0] ( DEBUG=True, MIDDLEWARECLASSES=[], ROOTURLCONF=settingsfile, ) () MyFormSet = forms.formsetfactory( form=MyForm, candelete=True, candeleteextra=False, ) myformset = MyFormSet( initial=None, ) print(myformset.emptyform)

required=False,                     widget=self.get_ordering_widget(),                 )        if self.can_delete and (self.can_delete_extra or index < initial_form_count):        if self.can_delete and (            self.can_delete_extra or (index is not None and index < initial_form_count)        ):             form.fields[DELETION_FIELD_NAME] = BooleanField(                 label=_("Delete"),                 required=False,


Question: Make BaseConstraint arguments keyword-only Description As suggested in  I think we should change the signature of BaseConstraint to use keyword-only arguments as a separate cleanup name and violationerrormessage are already keyword-only in all the BaseConstraint subclasses in Django code base.

<ins>import warnings</ins> from enum import Enum from types import NoneType


Question: Make BaseConstraint arguments keyword-only Description As suggested in  I think we should change the signature of BaseConstraint to use keyword-only arguments as a separate cleanup name and violationerrormessage are already keyword-only in all the BaseConstraint subclasses in Django code base.

from django.db.models.query_utils import Q from django.db.models.sql.query import Query from django.db.utils import DEFAULT_DB_ALIAS<ins>from django.utils.deprecation import RemovedInDjango60Warning</ins> from django.utils.translation import gettext_lazy as _  __all__ = ["BaseConstraint", "CheckConstraint", "Deferrable", "UniqueConstraint"]


Question: Make BaseConstraint arguments keyword-only Description As suggested in  I think we should change the signature of BaseConstraint to use keyword-only arguments as a separate cleanup name and violationerrormessage are already keyword-only in all the BaseConstraint subclasses in Django code base.

default_violation_error_message = _("Constraint “%(name)s” is violated.")     violation_error_message = None     def __init__(self, name, violation_error_message=None):    # RemovedInDjango60Warning: When the deprecation ends, replace with:    # def __init__(self, *, name, violation_error_message=None):    def __init__(self, *args, name=None, violation_error_message=None):        # RemovedInDjango60Warning.        if name is None and not args:            raise TypeError(                f"{self.__class__.__name__}.__init__() missing 1 required keyword-only "                f"argument: 'name'"            )         self.name = name         if violation_error_message is not None:             self.violation_error_message = violation_error_message         else:             self.violation_error_message = self.default_violation_error_message        # RemovedInDjango60Warning.        if args:            warnings.warn(                f"Passing positional arguments to {self.__class__.__name__} is "                f"deprecated.",                RemovedInDjango60Warning,                stacklevel=2,            )            for arg, attr in zip(args, ["name", "violation_error_message"]):                if arg:                    setattr(self, attr, arg)      @property     def contains_expressions(self):


Question: Make BaseConstraint arguments keyword-only Description As suggested in  I think we should change the signature of BaseConstraint to use keyword-only arguments as a separate cleanup name and violationerrormessage are already keyword-only in all the BaseConstraint subclasses in Django code base.

raise TypeError(                 "CheckConstraint.check must be a Q instance or boolean expression."             )        super().__init__(name, violation_error_message=violation_error_message)        super().__init__(name=name, violation_error_message=violation_error_message)      def _get_check_sql(self, model, schema_editor):         query = Query(model=model, alias_cols=False)


Question: Make BaseConstraint arguments keyword-only Description As suggested in  I think we should change the signature of BaseConstraint to use keyword-only arguments as a separate cleanup name and violationerrormessage are already keyword-only in all the BaseConstraint subclasses in Django code base.

F(expression) if isinstance(expression, str) else expression             for expression in expressions         )        super().__init__(name, violation_error_message=violation_error_message)        super().__init__(name=name, violation_error_message=violation_error_message)      @property     def contains_expressions(self):


Question: floatformat() crashes on "0.0000" Description Similar to the current Django code (both 4.2b1 and latest git) crash on using the floatformat template filter with 0 values. from decimal import Decimal from django.template.defaultfilters import floatformat floatformat('0.0000', 2) floatformat(Decimal('0.0000'), 2) Both throw ValueError: valid range for prec is [1, MAXPREC] Using git bisect I tracked the bug to commit . When one uses "0.0000": floatformat:2 the current code results in a precision of 0 which is not allowed: tupl = d.astuple() # with d being "0.0000" returns (sign=0,digits=(0,),exponent=-4) units = len(tupl[1]) # equals 1 units += -tupl[2] if m else tupl[2] # 1 + (-4) prec = abs(p) + units + 1 # 2 (number of requested decimals) + (-3) + 1 equals 0 roundedd = d.quantize(exp, ROUNDHALF_UP, Context(prec=prec))

import re import types import warningsfrom decimal import ROUND_HALF_UP, Context, Decimal, InvalidOperationfrom decimal import ROUND_HALF_UP, Context, Decimal, InvalidOperation, getcontext from functools import wraps from inspect import unwrap from operator import itemgetter


Question: floatformat() crashes on "0.0000" Description Similar to the current Django code (both 4.2b1 and latest git) crash on using the floatformat template filter with 0 values. from decimal import Decimal from django.template.defaultfilters import floatformat floatformat('0.0000', 2) floatformat(Decimal('0.0000'), 2) Both throw ValueError: valid range for prec is [1, MAXPREC] Using git bisect I tracked the bug to commit . When one uses "0.0000": floatformat:2 the current code results in a precision of 0 which is not allowed: tupl = d.astuple() # with d being "0.0000" returns (sign=0,digits=(0,),exponent=-4) units = len(tupl[1]) # equals 1 units += -tupl[2] if m else tupl[2] # 1 + (-4) prec = abs(p) + units + 1 # 2 (number of requested decimals) + (-3) + 1 equals 0 roundedd = d.quantize(exp, ROUNDHALF_UP, Context(prec=prec))

units = len(tupl[1])     units += -tupl[2] if m else tupl[2]     prec = abs(p) + units + 1<ins>    prec = max(getcontext().prec, prec)</ins>      # Avoid conversion to scientific notation by accessing `sign`, `digits`,     # and `exponent` from Decimal.as_tuple() directly.


Question: Migration optimizer does not reduce multiple AlterField Description Let's consider the following operations: operations = [ migrations.AddField( modelname="book", name="title", field=models.CharField(maxlength=256, null=True), ), migrations.AlterField( modelname="book", name="title", field=models.CharField(maxlength=128, null=True), ), migrations.AlterField( modelname="book", name="title", field=models.CharField(maxlength=128, null=True, helptext="help"), ), migrations.AlterField( modelname="book", name="title", field=models.CharField(maxlength=128, null=True, helptext="help", default=None), ), ] If I run the optimizer, I get only the AddField, as we could expect. However, if the AddField model is separated from the AlterField (e.g. because of a non-elidable migration, or inside a non-squashed migration), none of the AlterField are reduced: optimizer.optimize(operations[1:], "books") [<AlterField modelname='book', name='title', field=, <AlterField modelname='book', name='title', field=, <AlterField modelname='book', name='title', field=] Indeed, the does not consider the the case where operation is also an AlterField. Is this behaviour intended? If so, could it be documented? Otherwise, would it make sense to add something like if isinstance(operation, AlterField) and self.issamefieldoperation( operation ): return [operation]

return "alter_%s_%s" % (self.model_name_lower, self.name_lower)      def reduce(self, operation, app_label):        if isinstance(operation, RemoveField) and self.is_same_field_operation(            operation        ):        if isinstance(            operation, (AlterField, RemoveField)        ) and self.is_same_field_operation(operation):             return [operation]         elif (             isinstance(operation, RenameField)


Question: Subquery referencing WINDOW expression breaks query compilation Description introduced the ability to filter on WINDOW expressions but when a WINDOW expression is referred to in a subquery, the query compiler fails: ValueError: Need either using or connection I assume it has to do with self.connection not being passed on to innerquery.getcompiler in getqualifysql introduced here:  Below is the full traceback. A dummy test is available here:  Traceback (most recent call last): File "", line 57, in testPartExecutor yield File "", line 623, in run self.callTestMethod(testMethod) File "", line 579, in callTestMethod if method() is not None: File "", line 1025, in testfiltersubquery list( File "", line 398, in iter self.fetchall() File "", line 1881, in fetchall self.resultcache = list(self.iterableclass(self)) File "", line 91, in iter results = compiler.executesql( File "", line 1545, in executesql sql, params = () File "", line 732, in assql extraselect, orderby, groupby = self.presqlsetup( File "", line 84, in presqlsetup self.setupquery(withcolaliases=withcolaliases) File "", line 73, in setupquery , self.klassinfo, self.annotationcolmap = self.getselect( File "", line 296, in getselect sql, params = self.compile(col) File "", line 542, in compile sql, params = (self, self.connection) File "", line 1536, in assql subquerysql, sqlparams = (compiler, connection) File "", line 1150, in assql sql, params = self.getcompiler(connection=connection).assql() File "", line 751, in assql result, params = self.getqualifysql() File "", line 676, in getqualifysql innerquerycompiler = innerquery.getcompiler( File "", line 298, in get_compiler raise ValueError("Need either using or connection") ValueError: Need either using or connection

def resolve_expression(self, *args, **kwargs):         col = super().resolve_expression(*args, **kwargs)        if col.contains_over_clause:            raise NotSupportedError(                f"Referencing outer query window expression is not supported: "                f"{self.name}."            )         # FIXME: Rename possibly_multivalued to multivalued and fix detection         # for non-multivalued JOINs (e.g. foreign key fields). This should take         # into account only many-to-many and one-to-many relationships.diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py-- a/django/db/models/sql/compiler.py++ b/django/db/models/sql/compiler.py


Question: Subquery referencing WINDOW expression breaks query compilation Description introduced the ability to filter on WINDOW expressions but when a WINDOW expression is referred to in a subquery, the query compiler fails: ValueError: Need either using or connection I assume it has to do with self.connection not being passed on to innerquery.getcompiler in getqualifysql introduced here:  Below is the full traceback. A dummy test is available here:  Traceback (most recent call last): File "", line 57, in testPartExecutor yield File "", line 623, in run self.callTestMethod(testMethod) File "", line 579, in callTestMethod if method() is not None: File "", line 1025, in testfiltersubquery list( File "", line 398, in iter self.fetchall() File "", line 1881, in fetchall self.resultcache = list(self.iterableclass(self)) File "", line 91, in iter results = compiler.executesql( File "", line 1545, in executesql sql, params = () File "", line 732, in assql extraselect, orderby, groupby = self.presqlsetup( File "", line 84, in presqlsetup self.setupquery(withcolaliases=withcolaliases) File "", line 73, in setupquery , self.klassinfo, self.annotationcolmap = self.getselect( File "", line 296, in getselect sql, params = self.compile(col) File "", line 542, in compile sql, params = (self, self.connection) File "", line 1536, in assql subquerysql, sqlparams = (compiler, connection) File "", line 1150, in assql sql, params = self.getcompiler(connection=connection).assql() File "", line 751, in assql result, params = self.getqualifysql() File "", line 676, in getqualifysql innerquerycompiler = innerquery.getcompiler( File "", line 298, in get_compiler raise ValueError("Need either using or connection") ValueError: Need either using or connection

)             )         inner_query_compiler = inner_query.get_compiler(            self.using, elide_empty=self.elide_empty            self.using, connection=self.connection, elide_empty=self.elide_empty         )         inner_sql, inner_params = inner_query_compiler.as_sql(             # The limits must be applied to the outer query to avoid pruning


Question: Querying with an integer larger than SQLite supports crashes with OverflowError Description Hi, i don't know, you accept this behavior Overflow on SQLite or there is max length here? Step : http://127.0.0.1:8000/admin/auth/user//change/ Error : OverflowError at /admin/auth/user//change/ Python int too large to convert to SQLite INTEGER Request Method: GET Request URL: http://127.0.0.1:8000/admin/auth/user//change/ Django Version: 1.10.2 Exception Type: OverflowError Exception Value: Python int too large to convert to SQLite INTEGER Exception Location: C:\Python27\lib\site-packages\django\db\backends\sqlite3\ in quoteparamsforlastexecutedquery, line 129 Python Executable: C:\Python27\ Python Version: 2.7.11 Python Path: ['E:/Programmer Language/NodeJS/untitled1', 'C:\Users\RaminFP\.IntelliJIdea14\config\plugins\python\helpers\pydev', 'C:\Python27\lib\site-packages\six-1.10.0-', 'C:\Python27\lib\site-packages\pisa-3.0.33-', 'C:\Python27\lib\site-packages\sqlacodegen-1.1.6-', 'C:\Python27\lib\site-packages\inflect-0.2.5-', 'C:\Python27\lib\site-packages\0x10c_asm-0.0.2-', 'C:\Python27\lib\site-packages\jpype1-0.6.1-py2.7-', 'C:\Python27\lib\site-packages\simpleaes-1.0-', 'C:\Python27\lib\site-packages\celery-3.1.23-', 'C:\Python27\lib\site-packages\kombu-3.0.35-', 'C:\Python27\lib\site-packages\anyjson-0.3.3-', 'C:\Python27\lib\site-packages\pythonnet-2.1.0.dev1-py2.7-', 'E:\Programmer Language\NodeJS\untitled1', 'C:\Windows\SYSTEM32\', 'C:\Python27\DLLs', 'C:\Python27\lib', 'C:\Python27\lib\plat-win', 'C:\Python27\lib\lib-tk', 'C:\Python27', 'C:\Python27\lib\site-packages', 'c:\python27\lib\site-packages'] Server time: Fri, 28 Oct 2016 11:43:05 +0000

import itertools import math from django.core.exceptions import EmptyResultSetfrom django.core.exceptions import EmptyResultSet, FullResultSet from django.db.models.expressions import Case, Expression, Func, Value, When from django.db.models.fields import (     BooleanField,


Question: Querying with an integer larger than SQLite supports crashes with OverflowError Description Hi, i don't know, you accept this behavior Overflow on SQLite or there is max length here? Step : http://127.0.0.1:8000/admin/auth/user//change/ Error : OverflowError at /admin/auth/user//change/ Python int too large to convert to SQLite INTEGER Request Method: GET Request URL: http://127.0.0.1:8000/admin/auth/user//change/ Django Version: 1.10.2 Exception Type: OverflowError Exception Value: Python int too large to convert to SQLite INTEGER Exception Location: C:\Python27\lib\site-packages\django\db\backends\sqlite3\ in quoteparamsforlastexecutedquery, line 129 Python Executable: C:\Python27\ Python Version: 2.7.11 Python Path: ['E:/Programmer Language/NodeJS/untitled1', 'C:\Users\RaminFP\.IntelliJIdea14\config\plugins\python\helpers\pydev', 'C:\Python27\lib\site-packages\six-1.10.0-', 'C:\Python27\lib\site-packages\pisa-3.0.33-', 'C:\Python27\lib\site-packages\sqlacodegen-1.1.6-', 'C:\Python27\lib\site-packages\inflect-0.2.5-', 'C:\Python27\lib\site-packages\0x10c_asm-0.0.2-', 'C:\Python27\lib\site-packages\jpype1-0.6.1-py2.7-', 'C:\Python27\lib\site-packages\simpleaes-1.0-', 'C:\Python27\lib\site-packages\celery-3.1.23-', 'C:\Python27\lib\site-packages\kombu-3.0.35-', 'C:\Python27\lib\site-packages\anyjson-0.3.3-', 'C:\Python27\lib\site-packages\pythonnet-2.1.0.dev1-py2.7-', 'E:\Programmer Language\NodeJS\untitled1', 'C:\Windows\SYSTEM32\', 'C:\Python27\DLLs', 'C:\Python27\lib', 'C:\Python27\lib\plat-win', 'C:\Python27\lib\lib-tk', 'C:\Python27', 'C:\Python27\lib\site-packages', 'c:\python27\lib\site-packages'] Server time: Fri, 28 Oct 2016 11:43:05 +0000

lookup_name = "lte"  <ins>class IntegerFieldOverflow:    underflow_exception = EmptyResultSet    overflow_exception = EmptyResultSet    def process_rhs(self, compiler, connection):        rhs = self.rhs        if isinstance(rhs, int):            field_internal_type = self.lhs.output_field.get_internal_type()            min_value, max_value = connection.ops.integer_field_range(                field_internal_type            )            if min_value is not None and rhs < min_value:                raise self.underflow_exception            if max_value is not None and rhs > max_value:                raise self.overflow_exception        return super().process_rhs(compiler, connection)</ins> class IntegerFieldFloatRounding:     """     Allow floats to work as query values for IntegerField. Without this, the


Question: Querying with an integer larger than SQLite supports crashes with OverflowError Description Hi, i don't know, you accept this behavior Overflow on SQLite or there is max length here? Step : http://127.0.0.1:8000/admin/auth/user//change/ Error : OverflowError at /admin/auth/user//change/ Python int too large to convert to SQLite INTEGER Request Method: GET Request URL: http://127.0.0.1:8000/admin/auth/user//change/ Django Version: 1.10.2 Exception Type: OverflowError Exception Value: Python int too large to convert to SQLite INTEGER Exception Location: C:\Python27\lib\site-packages\django\db\backends\sqlite3\ in quoteparamsforlastexecutedquery, line 129 Python Executable: C:\Python27\ Python Version: 2.7.11 Python Path: ['E:/Programmer Language/NodeJS/untitled1', 'C:\Users\RaminFP\.IntelliJIdea14\config\plugins\python\helpers\pydev', 'C:\Python27\lib\site-packages\six-1.10.0-', 'C:\Python27\lib\site-packages\pisa-3.0.33-', 'C:\Python27\lib\site-packages\sqlacodegen-1.1.6-', 'C:\Python27\lib\site-packages\inflect-0.2.5-', 'C:\Python27\lib\site-packages\0x10c_asm-0.0.2-', 'C:\Python27\lib\site-packages\jpype1-0.6.1-py2.7-', 'C:\Python27\lib\site-packages\simpleaes-1.0-', 'C:\Python27\lib\site-packages\celery-3.1.23-', 'C:\Python27\lib\site-packages\kombu-3.0.35-', 'C:\Python27\lib\site-packages\anyjson-0.3.3-', 'C:\Python27\lib\site-packages\pythonnet-2.1.0.dev1-py2.7-', 'E:\Programmer Language\NodeJS\untitled1', 'C:\Windows\SYSTEM32\', 'C:\Python27\DLLs', 'C:\Python27\lib', 'C:\Python27\lib\plat-win', 'C:\Python27\lib\lib-tk', 'C:\Python27', 'C:\Python27\lib\site-packages', 'c:\python27\lib\site-packages'] Server time: Fri, 28 Oct 2016 11:43:05 +0000

@IntegerField.register_lookupclass IntegerGreaterThanOrEqual(IntegerFieldFloatRounding, GreaterThanOrEqual):class IntegerFieldExact(IntegerFieldOverflow, Exact):     pass   @IntegerField.register_lookupclass IntegerLessThan(IntegerFieldFloatRounding, LessThan):    passclass IntegerGreaterThan(IntegerFieldOverflow, GreaterThan):    underflow_exception = FullResultSet@IntegerField.register_lookupclass IntegerGreaterThanOrEqual(    IntegerFieldOverflow, IntegerFieldFloatRounding, GreaterThanOrEqual):    underflow_exception = FullResultSet@IntegerField.register_lookupclass IntegerLessThan(IntegerFieldOverflow, IntegerFieldFloatRounding, LessThan):    overflow_exception = FullResultSet@IntegerField.register_lookupclass IntegerLessThanOrEqual(IntegerFieldOverflow, LessThanOrEqual):    overflow_exception = FullResultSet   @Field.register_lookup


Question: Field position reference for aggregate ends up in group-by clause Description Changeset introduced a regression. Aggregate queries are rejected by the database due to the aggregated field being to the GROUP BY clause. It was difficult for me to pin down, especially because it looks like the error only occurs on the second evaluation of the query. The first query is executed just fine and doesn't contain the position reference to the aggregated field in the GROUP BY, only the second one. Below is a test to reproduce the behaviour: diff --git index .. a b class AggregationTests(TestCase): lambda b: (b.name, b.authorCount), ) 1324 def testquotingaggregateorderbyf(self): 1325 author = (name="Peter Norvig") 1326 qs = ( 1327 () 1328 .annotate(num=Count("authors")) 1329 .orderby(F("num").desc()) 1330 ) 1331 list(qs.iterator()) 1332 list(qs.iterator()) 1333 def test_stddev(self): self.assertEqual( Book.objects.aggregate(StdDev("pages")),

if (                         field.nulls_first is None and field.nulls_last is None                     ) or self.connection.features.supports_order_by_nulls_modifier:                        field = field.copy()                         field.expression = select_ref                     # Alias collisions are not possible when dealing with                     # combined queries so fallback to it if emulation of NULLS                     # handling is required.                     elif self.query.combinator:                        field = field.copy()                         field.expression = Ref(select_ref.refs, select_ref.source)                 yield field, select_ref is not None                 continue


Question: ASGI http.disconnect not handled on requests with body. Description Noticed whilst reviewing PR for , we're not handling the ASGI http.disconnect message correctly. Since it's only dealt with whilst reading the request body, http.disconnect is not processed on a request that includes a body.  async def readbody(self, receive): """Reads an HTTP body from an ASGI connection.""" # Use the tempfile that auto rolls-over to a disk file as it fills up. bodyfile = tempfile.SpooledTemporaryFile( maxsize=settings.FILEUPLOADMAXMEMORYSIZE, mode="w+b" ) while True: message = await receive() if message["type"] == "http.disconnect": # This is the only place is handled. () # Early client disconnect. raise RequestAborted() # Add a body chunk from the message, if provided. if "body" in message: (message["body"]) # Quit out if that's the end. if not ("morebody", False): break (0) return bodyfile http.disconnect is designed for long-polling — so we imagine a client opening a request, with a request body, and then disconnecting before the response is generated. The protocol server (Daphne/uvicorn/...) will send the http.diconnect message, but it's not handled. This test fails on main (at — 4.2 pre-alpha) diff --git index .. --- +++ -188,6 +188,18 class ASGITest(SimpleTestCase): with self.assertRaises(asyncio.TimeoutError): await communicator.receiveoutput() async def testdisconnectwithbody(self): application = getasgiapplication() scope = self.asyncrequestfactory.basescope(path="/") communicator = ApplicationCommunicator(application, scope) await communicator.sendinput({ "type": "http.request", "body": b"some body", }) await communicator.sendinput({"type": "http.disconnect"}) with self.assertRaises(asyncio.TimeoutError): await communicator.receiveoutput() async def testwrongconnectiontype(self): application = getasgiapplication() scope = self.asyncrequestfactory.basescope(path="/", type="other") To handle this correctly it looks like we'd need something like Channel's  to keep receiving from the input queue whilst dispatching the request.

<ins>import asyncio</ins> import logging import sys import tempfile


Question: ASGI http.disconnect not handled on requests with body. Description Noticed whilst reviewing PR for , we're not handling the ASGI http.disconnect message correctly. Since it's only dealt with whilst reading the request body, http.disconnect is not processed on a request that includes a body.  async def readbody(self, receive): """Reads an HTTP body from an ASGI connection.""" # Use the tempfile that auto rolls-over to a disk file as it fills up. bodyfile = tempfile.SpooledTemporaryFile( maxsize=settings.FILEUPLOADMAXMEMORYSIZE, mode="w+b" ) while True: message = await receive() if message["type"] == "http.disconnect": # This is the only place is handled. () # Early client disconnect. raise RequestAborted() # Add a body chunk from the message, if provided. if "body" in message: (message["body"]) # Quit out if that's the end. if not ("morebody", False): break (0) return bodyfile http.disconnect is designed for long-polling — so we imagine a client opening a request, with a request body, and then disconnecting before the response is generated. The protocol server (Daphne/uvicorn/...) will send the http.diconnect message, but it's not handled. This test fails on main (at — 4.2 pre-alpha) diff --git index .. --- +++ -188,6 +188,18 class ASGITest(SimpleTestCase): with self.assertRaises(asyncio.TimeoutError): await communicator.receiveoutput() async def testdisconnectwithbody(self): application = getasgiapplication() scope = self.asyncrequestfactory.basescope(path="/") communicator = ApplicationCommunicator(application, scope) await communicator.sendinput({ "type": "http.request", "body": b"some body", }) await communicator.sendinput({"type": "http.disconnect"}) with self.assertRaises(asyncio.TimeoutError): await communicator.receiveoutput() async def testwrongconnectiontype(self): application = getasgiapplication() scope = self.asyncrequestfactory.basescope(path="/", type="other") To handle this correctly it looks like we'd need something like Channel's  to keep receiving from the input queue whilst dispatching the request.

body_file.close()             await self.send_response(error_response, send)             return        # Get the response, using the async mode of BaseHandler.        # Try to catch a disconnect while getting response.        tasks = [            asyncio.create_task(self.run_get_response(request)),            asyncio.create_task(self.listen_for_disconnect(receive)),        ]        done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)        done, pending = done.pop(), pending.pop()        # Allow views to handle cancellation.        pending.cancel()        try:            await pending        except asyncio.CancelledError:            # Task re-raised the CancelledError as expected.            pass        try:            response = done.result()        except RequestAborted:            body_file.close()            return        except AssertionError:            body_file.close()            raise        # Send the response.        await self.send_response(response, send)    async def listen_for_disconnect(self, receive):        """Listen for disconnect from the client."""        message = await receive()        if message["type"] == "http.disconnect":            raise RequestAborted()        # This should never happen.        assert False, "Invalid ASGI message after request body: %s" % message["type"]    async def run_get_response(self, request):        """Get async response."""        # Use the async mode of BaseHandler.         response = await self.get_response_async(request)         response._handler_class = self.__class__         # Increase chunk size on file responses (ASGI servers handles low-level         # chunking).         if isinstance(response, FileResponse):             response.block_size = self.chunk_size        # Send the response.        await self.send_response(response, send)        return response      async def read_body(self, receive):         """Reads an HTTP body from an ASGI connection."""


Question: AdminSite.catchallview() drops query string in redirects Description introduced AdminSite.catchallview(). However, in the process it broke the ability to redirect with settings.APPENDSLASH = True when there are query strings. Provided URL: http://127.0.0.1:8000/admin/auth/foo?id=123 Expected redirect: http://127.0.0.1:8000/admin/auth/foo/?id=123 Actual redirect: http://127.0.0.1:8000/admin/auth/foo/ This seems to be because the redirect in question does not include the query strings (such as via request.META['QUERYSTRING']): return HttpResponsePermanentRedirect("%s/" % )

pass             else:                 if getattr(match.func, "should_append_slash", True):                    return HttpResponsePermanentRedirect("%s/" % request.path)                    return HttpResponsePermanentRedirect(                        request.get_full_path(force_append_slash=True)                    )         raise Http404      def _build_app_dict(self, request, label=None):


Question: Make URLField assume "https". Description In the assumption is made that the http (no S) is a good default scheme for URLs that do not specify a scheme when submitted. Entering in a URLField will give as cleaned data. Ref:  I think URLField should assume the safe option https. I've notified the security team, and they didn't see this as a security issue.

import os import re import uuid<ins>import warnings</ins> from decimal import Decimal, DecimalException from io import BytesIO from urllib.parse import urlsplit, urlunsplit


Question: Make URLField assume "https". Description In the assumption is made that the http (no S) is a good default scheme for URLs that do not specify a scheme when submitted. Entering in a URLField will give as cleaned data. Ref:  I think URLField should assume the safe option https. I've notified the security team, and they didn't see this as a security issue.

) from django.utils import formats from django.utils.dateparse import parse_datetime, parse_duration<ins>from django.utils.deprecation import RemovedInDjango60Warning</ins> from django.utils.duration import duration_string from django.utils.ipv6 import clean_ipv6_address from django.utils.regex_helper import _lazy_re_compile


Question: Make URLField assume "https". Description In the assumption is made that the http (no S) is a good default scheme for URLs that do not specify a scheme when submitted. Entering in a URLField will give as cleaned data. Ref:  I think URLField should assume the safe option https. I've notified the security team, and they didn't see this as a security issue.

}     default_validators = [validators.URLValidator()]     def __init__(self, **kwargs):    def __init__(self, *, assume_scheme=None, **kwargs):        if assume_scheme is None:            warnings.warn(                "The default scheme will be changed from 'http' to 'https' in Django "                "6.0. Pass the forms.URLField.assume_scheme argument to silence this "                "warning.",                RemovedInDjango60Warning,                stacklevel=2,            )            assume_scheme = "http"        # RemovedInDjango60Warning: When the deprecation ends, replace with:        # self.assume_scheme = assume_scheme or "https"        self.assume_scheme = assume_scheme         super().__init__(strip=True, **kwargs)      def to_python(self, value):


Question: Make URLField assume "https". Description In the assumption is made that the http (no S) is a good default scheme for URLs that do not specify a scheme when submitted. Entering in a URLField will give as cleaned data. Ref:  I think URLField should assume the safe option https. I've notified the security team, and they didn't see this as a security issue.

if value:             url_fields = split_url(value)             if not url_fields[0]:                # If no URL scheme given, assume http://                url_fields[0] = "http"                # If no URL scheme given, add a scheme.                url_fields[0] = self.assume_scheme             if not url_fields[1]:                 # Assume that if no domain is provided, that the path segment                 # contains the domain.


Question: Added support for direct usage of Choices classes on model fields Description (last modified by T. Franzel) Hi, I would like to propose a feature addition on how Choices are handled when used on model fields. Currently, Field.choices only accepts iterables. This has 2 shortcommings imho: Rejecting a Choices class as argument to Field(choices=...) seems counter-intuitive. Providing the class directly currently results in a fields.E005 error. To make this more pythonic, the field should also accept the Choice class directly and deal with the variation internally. I really can't come up with a scenario where a user would want a different behavior or rather that a user would be surprised by the implicit resolution. forcing the user to expand the Choices class manually, essentially all meta information is lost. Downstream packages may benefit from this lost information. Specifically, as maintainer of drf-spectcular (OpenAPI generator for DRF), I am interested in the name of the choice set (e.g. Suit, Vehicle, Gender) and potentially also the docstring. This would greatly improve OpenAPI generation of choice sets and take out the unnecessary guesswork to find a proper name. (And if anyone wonders, the model field name is not a good candidate for a choice set name.) This PR allows to use Choices classes directly as argument, while being transparent. No behavioral changes otherwise. I marked this as dev, but it would be awesome if it could still slip into 4.2. Not sure if the feature window is still open, but this is more or less a trivial and backwards-compatible change with little risk. PR is still missing some docs, which I will write if this is considered. class Suit(models.IntegerChoices): """ All possible card categories in a deck """ DIAMOND = 1, ("Diamond") SPADE = 2, ("Spade") HEART = 3, ("Heart") CLUB = 4, ("Club") class Choiceful(models.Model): # CURRENTLY: fromenumold = models.IntegerField(choices=Suit.choices) # NEW: raised an fields.E005 prior to proposed PR. Now, retains reference # to class and transparently resolves via implicit call from_new = models.IntegerField(choices=Suit)

from django.core import checks, exceptions, validators from django.db import connection, connections, router from django.db.models.constants import LOOKUP_SEP<ins>from django.db.models.enums import ChoicesMeta</ins> from django.db.models.query_utils import DeferredAttribute, RegisterLookupMixin from django.utils import timezone from django.utils.datastructures import DictWrapper


Question: Added support for direct usage of Choices classes on model fields Description (last modified by T. Franzel) Hi, I would like to propose a feature addition on how Choices are handled when used on model fields. Currently, Field.choices only accepts iterables. This has 2 shortcommings imho: Rejecting a Choices class as argument to Field(choices=...) seems counter-intuitive. Providing the class directly currently results in a fields.E005 error. To make this more pythonic, the field should also accept the Choice class directly and deal with the variation internally. I really can't come up with a scenario where a user would want a different behavior or rather that a user would be surprised by the implicit resolution. forcing the user to expand the Choices class manually, essentially all meta information is lost. Downstream packages may benefit from this lost information. Specifically, as maintainer of drf-spectcular (OpenAPI generator for DRF), I am interested in the name of the choice set (e.g. Suit, Vehicle, Gender) and potentially also the docstring. This would greatly improve OpenAPI generation of choice sets and take out the unnecessary guesswork to find a proper name. (And if anyone wonders, the model field name is not a good candidate for a choice set name.) This PR allows to use Choices classes directly as argument, while being transparent. No behavioral changes otherwise. I marked this as dev, but it would be awesome if it could still slip into 4.2. Not sure if the feature window is still open, but this is more or less a trivial and backwards-compatible change with little risk. PR is still missing some docs, which I will write if this is considered. class Suit(models.IntegerChoices): """ All possible card categories in a deck """ DIAMOND = 1, ("Diamond") SPADE = 2, ("Spade") HEART = 3, ("Heart") CLUB = 4, ("Club") class Choiceful(models.Model): # CURRENTLY: fromenumold = models.IntegerField(choices=Suit.choices) # NEW: raised an fields.E005 prior to proposed PR. Now, retains reference # to class and transparently resolves via implicit call from_new = models.IntegerField(choices=Suit)

self.unique_for_date = unique_for_date         self.unique_for_month = unique_for_month         self.unique_for_year = unique_for_year        if isinstance(choices, ChoicesMeta):            choices = choices.choices         if isinstance(choices, collections.abc.Iterator):             choices = list(choices)         self.choices = choicesdiff --git a/django/forms/fields.py b/django/forms/fields.py-- a/django/forms/fields.py++ b/django/forms/fields.py


Question: Added support for direct usage of Choices classes on model fields Description (last modified by T. Franzel) Hi, I would like to propose a feature addition on how Choices are handled when used on model fields. Currently, Field.choices only accepts iterables. This has 2 shortcommings imho: Rejecting a Choices class as argument to Field(choices=...) seems counter-intuitive. Providing the class directly currently results in a fields.E005 error. To make this more pythonic, the field should also accept the Choice class directly and deal with the variation internally. I really can't come up with a scenario where a user would want a different behavior or rather that a user would be surprised by the implicit resolution. forcing the user to expand the Choices class manually, essentially all meta information is lost. Downstream packages may benefit from this lost information. Specifically, as maintainer of drf-spectcular (OpenAPI generator for DRF), I am interested in the name of the choice set (e.g. Suit, Vehicle, Gender) and potentially also the docstring. This would greatly improve OpenAPI generation of choice sets and take out the unnecessary guesswork to find a proper name. (And if anyone wonders, the model field name is not a good candidate for a choice set name.) This PR allows to use Choices classes directly as argument, while being transparent. No behavioral changes otherwise. I marked this as dev, but it would be awesome if it could still slip into 4.2. Not sure if the feature window is still open, but this is more or less a trivial and backwards-compatible change with little risk. PR is still missing some docs, which I will write if this is considered. class Suit(models.IntegerChoices): """ All possible card categories in a deck """ DIAMOND = 1, ("Diamond") SPADE = 2, ("Spade") HEART = 3, ("Heart") CLUB = 4, ("Club") class Choiceful(models.Model): # CURRENTLY: fromenumold = models.IntegerField(choices=Suit.choices) # NEW: raised an fields.E005 prior to proposed PR. Now, retains reference # to class and transparently resolves via implicit call from_new = models.IntegerField(choices=Suit)

from django.core import validators from django.core.exceptions import ValidationError<ins>from django.db.models.enums import ChoicesMeta</ins> from django.forms.boundfield import BoundField from django.forms.utils import from_current_timezone, to_current_timezone from django.forms.widgets import (


Question: Added support for direct usage of Choices classes on model fields Description (last modified by T. Franzel) Hi, I would like to propose a feature addition on how Choices are handled when used on model fields. Currently, Field.choices only accepts iterables. This has 2 shortcommings imho: Rejecting a Choices class as argument to Field(choices=...) seems counter-intuitive. Providing the class directly currently results in a fields.E005 error. To make this more pythonic, the field should also accept the Choice class directly and deal with the variation internally. I really can't come up with a scenario where a user would want a different behavior or rather that a user would be surprised by the implicit resolution. forcing the user to expand the Choices class manually, essentially all meta information is lost. Downstream packages may benefit from this lost information. Specifically, as maintainer of drf-spectcular (OpenAPI generator for DRF), I am interested in the name of the choice set (e.g. Suit, Vehicle, Gender) and potentially also the docstring. This would greatly improve OpenAPI generation of choice sets and take out the unnecessary guesswork to find a proper name. (And if anyone wonders, the model field name is not a good candidate for a choice set name.) This PR allows to use Choices classes directly as argument, while being transparent. No behavioral changes otherwise. I marked this as dev, but it would be awesome if it could still slip into 4.2. Not sure if the feature window is still open, but this is more or less a trivial and backwards-compatible change with little risk. PR is still missing some docs, which I will write if this is considered. class Suit(models.IntegerChoices): """ All possible card categories in a deck """ DIAMOND = 1, ("Diamond") SPADE = 2, ("Spade") HEART = 3, ("Heart") CLUB = 4, ("Club") class Choiceful(models.Model): # CURRENTLY: fromenumold = models.IntegerField(choices=Suit.choices) # NEW: raised an fields.E005 prior to proposed PR. Now, retains reference # to class and transparently resolves via implicit call from_new = models.IntegerField(choices=Suit)

def __init__(self, *, choices=(), **kwargs):         super().__init__(**kwargs)<ins>        if isinstance(choices, ChoicesMeta):            choices = choices.choices</ins>         self.choices = choices      def __deepcopy__(self, memo):


Question: SECRETKEYFALLBACKS is not used for sessions Description I recently rotated my secret key, made the old one available in SECRETKEYFALLBACKS and I'm pretty sure everyone on our site is logged out now. I think the docs for SECRETKEYFALLBACKS may be incorrect when stating the following: In order to rotate your secret keys, set a new SECRETKEY and move the previous value to the beginning of SECRETKEYFALLBACKS. Then remove the old values from the end of the SECRETKEYFALLBACKS when you are ready to expire the sessions, password reset tokens, and so on, that make use of them. When looking at the Django source code, I see that the saltedhmac function uses the SECRETKEY by default and the AbstractBaseUser.getsessionauthhash method does not call salted_hmac with a value for the secret keyword argument.

# Verify the session             if hasattr(user, "get_session_auth_hash"):                 session_hash = request.session.get(HASH_SESSION_KEY)                session_hash_verified = session_hash and constant_time_compare(                    session_hash, user.get_session_auth_hash()                )                if not session_hash:                    session_hash_verified = False                else:                    session_auth_hash = user.get_session_auth_hash()                    session_hash_verified = constant_time_compare(                        session_hash, session_auth_hash                    )                 if not session_hash_verified:                    request.session.flush()                    user = None                    # If the current secret does not verify the session, try                    # with the fallback secrets and stop when a matching one is                    # found.                    if session_hash and any(                        constant_time_compare(session_hash, fallback_auth_hash)                        for fallback_auth_hash in user.get_session_auth_fallback_hash()                    ):                        request.session.cycle_key()                        request.session[HASH_SESSION_KEY] = session_auth_hash                    else:                        request.session.flush()                        user = None      return user or AnonymousUser() diff --git a/django/contrib/auth/base_user.py b/django/contrib/auth/base_user.py-- a/django/contrib/auth/base_user.py++ b/django/contrib/auth/base_user.py


Question: SECRETKEYFALLBACKS is not used for sessions Description I recently rotated my secret key, made the old one available in SECRETKEYFALLBACKS and I'm pretty sure everyone on our site is logged out now. I think the docs for SECRETKEYFALLBACKS may be incorrect when stating the following: In order to rotate your secret keys, set a new SECRETKEY and move the previous value to the beginning of SECRETKEYFALLBACKS. Then remove the old values from the end of the SECRETKEYFALLBACKS when you are ready to expire the sessions, password reset tokens, and so on, that make use of them. When looking at the Django source code, I see that the saltedhmac function uses the SECRETKEY by default and the AbstractBaseUser.getsessionauthhash method does not call salted_hmac with a value for the secret keyword argument.

import unicodedata import warnings <ins>from django.conf import settings</ins> from django.contrib.auth import password_validation from django.contrib.auth.hashers import (     check_password,


Question: SECRETKEYFALLBACKS is not used for sessions Description I recently rotated my secret key, made the old one available in SECRETKEYFALLBACKS and I'm pretty sure everyone on our site is logged out now. I think the docs for SECRETKEYFALLBACKS may be incorrect when stating the following: In order to rotate your secret keys, set a new SECRETKEY and move the previous value to the beginning of SECRETKEYFALLBACKS. Then remove the old values from the end of the SECRETKEYFALLBACKS when you are ready to expire the sessions, password reset tokens, and so on, that make use of them. When looking at the Django source code, I see that the saltedhmac function uses the SECRETKEY by default and the AbstractBaseUser.getsessionauthhash method does not call salted_hmac with a value for the secret keyword argument.

"""         Return an HMAC of the password field.         """        return self._get_session_auth_hash()    def get_session_auth_fallback_hash(self):        for fallback_secret in settings.SECRET_KEY_FALLBACKS:            yield self._get_session_auth_hash(secret=fallback_secret)    def _get_session_auth_hash(self, secret=None):         key_salt = "django.contrib.auth.models.AbstractBaseUser.get_session_auth_hash"         return salted_hmac(             key_salt,             self.password,            secret=secret,             algorithm="sha256",         ).hexdigest()


Question: Migrations tries to add constraint before adding a foreign key. Description (last modified by Raphael Beekmann) Hello, I have a model, already created through previous migrations, and in a new migration I a new field with an UniqueConstraint. The migrations script try to create the constraint first and then the new field, resulting an error : NewModel has no field named 'category' To reproduce the bug : Create a project with two models linked together with a One-to-Many relation and an unique constraint : class Type(models.Model): name = models.CharField(maxlength=10) class Model(models.Model): name = models.CharField(maxlength=10) type = models.ForeignKey(Type, ondelete=models.SETNULL, null=True) date = models.DateField(autonow=True) class Meta: constraints = ( models.UniqueConstraint(fields=('date', 'type'), name='uniquetypefordate'), ) Create a migration file with makemigrations Add a new model with another One-to-Many relation and unique constraint. The models looks like this : class Type(models.Model): name = models.CharField(maxlength=10) class Category(models.Model): name = models.CharField(maxlength=10) class Model(models.Model): name = models.CharField(maxlength=10) type = models.ForeignKey(Type, ondelete=models.SETNULL, null=True) category = models.ForeignKey(Category, ondelete=models.SETNULL, null=True) date = models.DateField(autonow=True) class Meta: constraints = ( models.UniqueConstraint(fields=('date', 'type'), name='uniquetypefordate'), models.UniqueConstraint(fields=('date', 'category'), name='uniquecategoryfordate'), ) Create a new migration file. The order of the migration's steps are incorrect and the migration crash : class Migration(migrations.Migration): dependencies = [ ('app', '0001initial'), ] operations = [ migrations.CreateModel( name='Category', fields=[ ('id', models.BigAutoField(autocreated=True, primarykey=True, serialize=False, verbosename='ID')), ('name', models.CharField(maxlength=10)), ], ), migrations.AddConstraint( modelname='model', constraint=models.UniqueConstraint(fields=('date', 'category'), name='uniquecategoryfordate'), ), migrations.AddField( modelname='model', name='category', field=models.ForeignKey(null=True, , to='app.category'), ), ]

def generate_added_indexes(self):         for (app_label, model_name), alt_indexes in self.altered_indexes.items():<ins>            dependencies = self._get_dependencies_for_model(app_label, model_name)</ins>             for index in alt_indexes["added_indexes"]:                 self.add_operation(                     app_label,