diff --git a/django/core/validators.py b/django/core/validators.py index 862140bcda84..fe1e8b066c59 100644 --- a/django/core/validators.py +++ b/django/core/validators.py @@ -152,7 +152,7 @@ class URLValidator(RegexValidator): ) message = _("Enter a valid URL.") schemes = ["http", "https", "ftp", "ftps"] - unsafe_chars = frozenset("\t\r\n") + unsafe_chars = frozenset("\t\r\n\x00") max_length = MAX_URL_LENGTH def __init__(self, schemes=None, **kwargs): diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py index ef188783d400..4972f29d61a7 100644 --- a/django/db/models/sql/compiler.py +++ b/django/db/models/sql/compiler.py @@ -1052,6 +1052,11 @@ def get_distinct(self): for target in targets: if name in self.query.annotation_select: result.append(self.connection.ops.quote_name(name)) + elif name in self.query.annotations: + raise FieldError( + f"Cannot select the {name!r} alias. Use annotate() to " + "promote it." + ) else: r, p = self.compile(transform_function(target, alias)) result.append(r) diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py index adf0663bebaa..e3b97ec425bf 100644 --- a/django/db/models/sql/query.py +++ b/django/db/models/sql/query.py @@ -1800,8 +1800,8 @@ def names_to_path(self, names, opts, allow_many=True, fail_on_missing=False): raise FieldDoesNotExist field = opts.get_field(name) except FieldDoesNotExist: - if name in self.annotation_select: - field = self.annotation_select[name].output_field + if name in self.annotations: + field = self.annotations[name].output_field elif name in self._filtered_relations and pos == 0: filtered_relation = self._filtered_relations[name] if LOOKUP_SEP in filtered_relation.relation_name: diff --git a/tests/annotations/tests.py b/tests/annotations/tests.py index 42fccca7d6eb..fd5f6716dcc7 100644 --- a/tests/annotations/tests.py +++ b/tests/annotations/tests.py @@ -1481,6 +1481,12 @@ def test_order_by_alias(self): self.assertIs(hasattr(qs.first(), "other_age"), False) self.assertQuerySetEqual(qs, [34, 34, 35, 46, 57], lambda a: a.age) + def test_order_by_alias_transform(self): + qs = Book.objects.alias(other_pubdate=F("pubdate")).order_by( + "-other_pubdate__year" + ) + self.assertQuerySetEqual(qs, [2008, 2007, 1995, 1991], lambda a: a.pubdate.year) + def test_order_by_alias_aggregate(self): qs = ( Author.objects.values("age") @@ -1536,9 +1542,9 @@ def test_defer_only_alias(self): @skipUnlessDBFeature("can_distinct_on_fields") def test_distinct_on_alias(self): qs = Book.objects.alias(rating_alias=F("rating") - 1) - msg = "Cannot resolve keyword 'rating_alias' into field." + msg = "Cannot select the 'rating_alias' alias. Use annotate() to promote it." with self.assertRaisesMessage(FieldError, msg): - qs.distinct("rating_alias").first() + qs.distinct("rating_alias").order_by("rating_alias").first() def test_values_alias(self): qs = Book.objects.alias(rating_alias=F("rating") - 1) diff --git a/tests/validators/tests.py b/tests/validators/tests.py index e9ef60174aad..2937c519f5dc 100644 --- a/tests/validators/tests.py +++ b/tests/validators/tests.py @@ -265,6 +265,10 @@ "http://[::\rffff:192.9.5.5]", "http://\twww.djangoproject.com/", "http://\t[::ffff:192.9.5.5]", + # Null characters are not accepted. + "http://www.djangoproject.com/\x00", + "http://www.django\x00project.com/", + "http://www.djangoproject.com/\x00@example.com/", # Trailing junk does not take forever to reject. "http://www.asdasdasdasdsadfm.com.br ", "http://www.asdasdasdasdsadfm.com.br z",