1
0
mirror of https://github.com/django/django.git synced 2025-06-05 03:29:12 +00:00

Merge branch 'django:main' into skushagra-patch-1-issue-35119

This commit is contained in:
Kushagra S 2024-01-24 09:52:45 +05:30 committed by GitHub
commit 3d4e918620
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 154 additions and 39 deletions

View File

@ -1087,6 +1087,6 @@ A big THANK YOU goes to:
Ian Bicking for convincing Adrian to ditch code generation. Ian Bicking for convincing Adrian to ditch code generation.
Mark Pilgrim for "Dive Into Python" (https://www.diveinto.org/python3/). Mark Pilgrim for "Dive Into Python" (https://diveintopython3.net/).
Guido van Rossum for creating Python. Guido van Rossum for creating Python.

View File

@ -39,6 +39,7 @@
True True True True
""" """
import sys import sys
import warnings
from binascii import b2a_hex from binascii import b2a_hex
from ctypes import byref, c_char_p, c_double, c_ubyte, c_void_p, string_at from ctypes import byref, c_char_p, c_double, c_ubyte, c_void_p, string_at
@ -50,6 +51,7 @@ from django.contrib.gis.gdal.prototypes import geom as capi
from django.contrib.gis.gdal.prototypes import srs as srs_api from django.contrib.gis.gdal.prototypes import srs as srs_api
from django.contrib.gis.gdal.srs import CoordTransform, SpatialReference from django.contrib.gis.gdal.srs import CoordTransform, SpatialReference
from django.contrib.gis.geometry import hex_regex, json_regex, wkt_regex from django.contrib.gis.geometry import hex_regex, json_regex, wkt_regex
from django.utils.deprecation import RemovedInDjango60Warning
from django.utils.encoding import force_bytes from django.utils.encoding import force_bytes
@ -206,18 +208,21 @@ class OGRGeometry(GDALBase):
"Return 0 for points, 1 for lines, and 2 for surfaces." "Return 0 for points, 1 for lines, and 2 for surfaces."
return capi.get_dims(self.ptr) return capi.get_dims(self.ptr)
def _get_coord_dim(self): @property
def coord_dim(self):
"Return the coordinate dimension of the Geometry." "Return the coordinate dimension of the Geometry."
return capi.get_coord_dim(self.ptr) return capi.get_coord_dim(self.ptr)
def _set_coord_dim(self, dim): # RemovedInDjango60Warning
@coord_dim.setter
def coord_dim(self, dim):
"Set the coordinate dimension of this Geometry." "Set the coordinate dimension of this Geometry."
msg = "coord_dim setter is deprecated. Use set_3d() instead."
warnings.warn(msg, RemovedInDjango60Warning, stacklevel=2)
if dim not in (2, 3): if dim not in (2, 3):
raise ValueError("Geometry dimension must be either 2 or 3") raise ValueError("Geometry dimension must be either 2 or 3")
capi.set_coord_dim(self.ptr, dim) capi.set_coord_dim(self.ptr, dim)
coord_dim = property(_get_coord_dim, _set_coord_dim)
@property @property
def geom_count(self): def geom_count(self):
"Return the number of elements in this Geometry." "Return the number of elements in this Geometry."

View File

@ -17,6 +17,7 @@ from django.db.utils import (
from django.utils.connection import ConnectionProxy from django.utils.connection import ConnectionProxy
__all__ = [ __all__ = [
"close_old_connections",
"connection", "connection",
"connections", "connections",
"router", "router",

View File

@ -95,12 +95,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
"db_functions.datetime.test_extract_trunc.DateFunctionWithTimeZoneTests." "db_functions.datetime.test_extract_trunc.DateFunctionWithTimeZoneTests."
"test_trunc_week_before_1000", "test_trunc_week_before_1000",
}, },
"Oracle extracts seconds including fractional seconds (#33517).": {
"db_functions.datetime.test_extract_trunc.DateFunctionTests."
"test_extract_second_func_no_fractional",
"db_functions.datetime.test_extract_trunc.DateFunctionWithTimeZoneTests."
"test_extract_second_func_no_fractional",
},
"Oracle doesn't support bitwise XOR.": { "Oracle doesn't support bitwise XOR.": {
"expressions.tests.ExpressionOperatorTests.test_lefthand_bitwise_xor", "expressions.tests.ExpressionOperatorTests.test_lefthand_bitwise_xor",
"expressions.tests.ExpressionOperatorTests.test_lefthand_bitwise_xor_null", "expressions.tests.ExpressionOperatorTests.test_lefthand_bitwise_xor_null",

View File

@ -165,6 +165,9 @@ END;
def datetime_extract_sql(self, lookup_type, sql, params, tzname): def datetime_extract_sql(self, lookup_type, sql, params, tzname):
sql, params = self._convert_sql_to_tz(sql, params, tzname) sql, params = self._convert_sql_to_tz(sql, params, tzname)
if lookup_type == "second":
# Truncate fractional seconds.
return f"FLOOR(EXTRACT(SECOND FROM {sql}))", params
return self.date_extract_sql(lookup_type, sql, params) return self.date_extract_sql(lookup_type, sql, params)
def datetime_trunc_sql(self, lookup_type, sql, params, tzname): def datetime_trunc_sql(self, lookup_type, sql, params, tzname):
@ -188,6 +191,12 @@ END;
return f"CAST({sql} AS DATE)", params return f"CAST({sql} AS DATE)", params
return f"TRUNC({sql}, %s)", (*params, trunc_param) return f"TRUNC({sql}, %s)", (*params, trunc_param)
def time_extract_sql(self, lookup_type, sql, params):
if lookup_type == "second":
# Truncate fractional seconds.
return f"FLOOR(EXTRACT(SECOND FROM {sql}))", params
return self.date_extract_sql(lookup_type, sql, params)
def time_trunc_sql(self, lookup_type, sql, params, tzname=None): def time_trunc_sql(self, lookup_type, sql, params, tzname=None):
# The implementation is similar to `datetime_trunc_sql` as both # The implementation is similar to `datetime_trunc_sql` as both
# `DateTimeField` and `TimeField` are stored as TIMESTAMP where # `DateTimeField` and `TimeField` are stored as TIMESTAMP where

View File

@ -261,6 +261,10 @@ class Field:
result.validators = self.validators[:] result.validators = self.validators[:]
return result return result
def _clean_bound_field(self, bf):
value = bf.initial if self.disabled else bf.data
return self.clean(value)
class CharField(Field): class CharField(Field):
def __init__( def __init__(
@ -694,6 +698,10 @@ class FileField(Field):
def has_changed(self, initial, data): def has_changed(self, initial, data):
return not self.disabled and data is not None return not self.disabled and data is not None
def _clean_bound_field(self, bf):
value = bf.initial if self.disabled else bf.data
return self.clean(value, bf.initial)
class ImageField(FileField): class ImageField(FileField):
default_validators = [validators.validate_image_file_extension] default_validators = [validators.validate_image_file_extension]

View File

@ -6,7 +6,7 @@ import copy
import datetime import datetime
from django.core.exceptions import NON_FIELD_ERRORS, ValidationError from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
from django.forms.fields import Field, FileField from django.forms.fields import Field
from django.forms.utils import ErrorDict, ErrorList, RenderableFormMixin from django.forms.utils import ErrorDict, ErrorList, RenderableFormMixin
from django.forms.widgets import Media, MediaDefiningClass from django.forms.widgets import Media, MediaDefiningClass
from django.utils.datastructures import MultiValueDict from django.utils.datastructures import MultiValueDict
@ -329,13 +329,8 @@ class BaseForm(RenderableFormMixin):
def _clean_fields(self): def _clean_fields(self):
for name, bf in self._bound_items(): for name, bf in self._bound_items():
field = bf.field field = bf.field
value = bf.initial if field.disabled else bf.data
try: try:
if isinstance(field, FileField): self.cleaned_data[name] = field._clean_bound_field(bf)
value = field.clean(value, bf.initial)
else:
value = field.clean(value)
self.cleaned_data[name] = value
if hasattr(self, "clean_%s" % name): if hasattr(self, "clean_%s" % name):
value = getattr(self, "clean_%s" % name)() value = getattr(self, "clean_%s" % name)()
self.cleaned_data[name] = value self.cleaned_data[name] = value

View File

@ -71,6 +71,9 @@ details on these changes.
* Support for passing positional arguments to ``Model.save()`` and * Support for passing positional arguments to ``Model.save()`` and
``Model.asave()`` will be removed. ``Model.asave()`` will be removed.
* The setter for ``django.contrib.gis.gdal.OGRGeometry.coord_dim`` will be
removed.
.. _deprecation-removed-in-5.1: .. _deprecation-removed-in-5.1:
5.1 5.1

View File

@ -27,8 +27,8 @@ For this tutorial, we expect that you have at least a basic understanding of
how Django works. This means you should be comfortable going through the how Django works. This means you should be comfortable going through the
existing tutorials on :doc:`writing your first Django app</intro/tutorial01>`. existing tutorials on :doc:`writing your first Django app</intro/tutorial01>`.
In addition, you should have a good understanding of Python itself. But if you In addition, you should have a good understanding of Python itself. But if you
don't, `Dive Into Python`__ is a fantastic (and free) online book for don't, `Dive Into Python`_ is a fantastic (and free) online book for beginning
beginning Python programmers. Python programmers.
Those of you who are unfamiliar with version control systems and Trac will find Those of you who are unfamiliar with version control systems and Trac will find
that this tutorial and its links include just enough information to get started. that this tutorial and its links include just enough information to get started.
@ -45,8 +45,8 @@ so that it can be of use to the widest audience.
`#django-dev on irc.libera.chat`__ to chat with other Django users who `#django-dev on irc.libera.chat`__ to chat with other Django users who
might be able to help. might be able to help.
__ https://diveinto.org/python3/table-of-contents.html
__ https://web.libera.chat/#django-dev __ https://web.libera.chat/#django-dev
.. _Dive Into Python: https://diveintopython3.net/
.. _Django Forum: https://forum.djangoproject.com/ .. _Django Forum: https://forum.djangoproject.com/
What does this tutorial cover? What does this tutorial cover?
@ -350,7 +350,7 @@ This test checks that the ``make_toast()`` returns ``'toast'``.
* After reading those, if you want something a little meatier to sink * After reading those, if you want something a little meatier to sink
your teeth into, there's always the Python :mod:`unittest` documentation. your teeth into, there's always the Python :mod:`unittest` documentation.
__ https://diveinto.org/python3/unit-testing.html __ https://diveintopython3.net/unit-testing.html
Running your new test Running your new test
--------------------- ---------------------

View File

@ -32,10 +32,12 @@ place: read this material to quickly get up and running.
`list of Python resources for non-programmers`_ `list of Python resources for non-programmers`_
If you already know a few other languages and want to get up to speed with If you already know a few other languages and want to get up to speed with
Python quickly, we recommend `Dive Into Python`_. If that's not quite your Python quickly, we recommend referring the official
style, there are many other `books about Python`_. `Python documentation`_, which provides comprehensive and authoritative
information about the language, as well as links to other resources such as
a list of `books about Python`_.
.. _python: https://www.python.org/ .. _python: https://www.python.org/
.. _list of Python resources for non-programmers: https://wiki.python.org/moin/BeginnersGuide/NonProgrammers .. _list of Python resources for non-programmers: https://wiki.python.org/moin/BeginnersGuide/NonProgrammers
.. _Dive Into Python: https://diveinto.org/python3/table-of-contents.html .. _Python documentation: https://docs.python.org/3/
.. _books about Python: https://wiki.python.org/moin/PythonBooks .. _books about Python: https://wiki.python.org/moin/PythonBooks

View File

@ -76,7 +76,7 @@ After the previous tutorials, our project should look like this:
static/ static/
polls/ polls/
images/ images/
background.gif background.png
style.css style.css
templates/ templates/
polls/ polls/

View File

@ -553,8 +553,12 @@ coordinate transformation:
.. attribute:: coord_dim .. attribute:: coord_dim
Returns or sets the coordinate dimension of this geometry. For example, the Returns the coordinate dimension of this geometry. For example, the value
value would be 2 for two-dimensional geometries. would be 2 for two-dimensional geometries.
.. deprecated:: 5.1
The ``coord_dim`` setter is deprecated. Use :meth:`.set_3d` instead.
.. attribute:: is_3d .. attribute:: is_3d

View File

@ -99,7 +99,8 @@ connections.
If a connection is created in a long-running process, outside of Djangos If a connection is created in a long-running process, outside of Djangos
request-response cycle, the connection will remain open until explicitly request-response cycle, the connection will remain open until explicitly
closed, or timeout occurs. closed, or timeout occurs. You can use ``django.db.close_old_connections()`` to
close all old or unusable connections.
Encoding Encoding
-------- --------

View File

@ -1797,9 +1797,9 @@ allows for the following options by default:
.. django-admin-option:: --pythonpath PYTHONPATH .. django-admin-option:: --pythonpath PYTHONPATH
Adds the given filesystem path to the Python `import search path`_. If this Adds the given filesystem path to the Python :py:data:`sys.path` module
isn't provided, ``django-admin`` will use the :envvar:`PYTHONPATH` environment attribute. If this isn't provided, ``django-admin`` will use the
variable. :envvar:`PYTHONPATH` environment variable.
This option is unnecessary in ``manage.py``, because it takes care of setting This option is unnecessary in ``manage.py``, because it takes care of setting
the Python path for you. the Python path for you.
@ -1810,8 +1810,6 @@ Example usage:
django-admin migrate --pythonpath='/home/djangoprojects/myproject' django-admin migrate --pythonpath='/home/djangoprojects/myproject'
.. _import search path: https://diveinto.org/python3/your-first-python-program.html#importsearchpath
.. django-admin-option:: --settings SETTINGS .. django-admin-option:: --settings SETTINGS
Specifies the settings module to use. The settings module should be in Python Specifies the settings module to use. The settings module should be in Python

View File

@ -2484,8 +2484,8 @@ individual elements of the sequence.
Returns a slice of the list. Returns a slice of the list.
Uses the same syntax as Python's list slicing. See Uses the same syntax as Python's list slicing. See the `Python documentation
https://diveinto.org/python3/native-datatypes.html#slicinglists for an <https://docs.python.org/3/tutorial/introduction.html#lists>`_ for an
introduction. introduction.
Example: Example:

View File

@ -378,6 +378,9 @@ Miscellaneous
* Passing positional arguments to :meth:`.Model.save` and :meth:`.Model.asave` * Passing positional arguments to :meth:`.Model.save` and :meth:`.Model.asave`
is deprecated in favor of keyword-only arguments. is deprecated in favor of keyword-only arguments.
* Setting ``django.contrib.gis.gdal.OGRGeometry.coord_dim`` is deprecated. Use
:meth:`~django.contrib.gis.gdal.OGRGeometry.set_3d` instead.
Features removed in 5.1 Features removed in 5.1
======================= =======================

View File

@ -1608,7 +1608,7 @@ Helper functions
Defaults to :setting:`settings.LOGIN_URL <LOGIN_URL>` if not supplied. Defaults to :setting:`settings.LOGIN_URL <LOGIN_URL>` if not supplied.
* ``redirect_field_name``: The name of a ``GET`` field containing the * ``redirect_field_name``: The name of a ``GET`` field containing the
URL to redirect to after log out. Overrides ``next`` if the given URL to redirect to after login. Overrides ``next`` if the given
``GET`` parameter is passed. ``GET`` parameter is passed.
.. _built-in-auth-forms: .. _built-in-auth-forms:

View File

@ -44,9 +44,8 @@ by using an environment variable, :envvar:`DJANGO_SETTINGS_MODULE`.
The value of :envvar:`DJANGO_SETTINGS_MODULE` should be in Python path syntax, The value of :envvar:`DJANGO_SETTINGS_MODULE` should be in Python path syntax,
e.g. ``mysite.settings``. Note that the settings module should be on the e.g. ``mysite.settings``. Note that the settings module should be on the
Python `import search path`_. Python :py:data:`sys.path`.
.. _import search path: https://diveinto.org/python3/your-first-python-program.html#importsearchpath
The ``django-admin`` utility The ``django-admin`` utility
---------------------------- ----------------------------

View File

@ -11,6 +11,7 @@ from django.contrib.gis.gdal import (
from django.template import Context from django.template import Context
from django.template.engine import Engine from django.template.engine import Engine
from django.test import SimpleTestCase from django.test import SimpleTestCase
from django.utils.deprecation import RemovedInDjango60Warning
from ..test_data import TestDataMixin from ..test_data import TestDataMixin
@ -727,3 +728,95 @@ class OGRGeomTest(SimpleTestCase, TestDataMixin):
msg = "Input to 'set_3d' must be a boolean, got 'None'" msg = "Input to 'set_3d' must be a boolean, got 'None'"
with self.assertRaisesMessage(ValueError, msg): with self.assertRaisesMessage(ValueError, msg):
geom.set_3d(None) geom.set_3d(None)
def test_wkt_and_wkb_output(self):
tests = [
# 2D
("POINT (1 2)", "0101000000000000000000f03f0000000000000040"),
(
"LINESTRING (30 10,10 30)",
"0102000000020000000000000000003e400000000000002"
"44000000000000024400000000000003e40",
),
(
"POLYGON ((30 10,40 40,20 40,30 10))",
"010300000001000000040000000000000000003e400000000000002440000000000000"
"44400000000000004440000000000000344000000000000044400000000000003e4000"
"00000000002440",
),
(
"MULTIPOINT (10 40,40 30)",
"0104000000020000000101000000000000000000244000000000000044400101000000"
"00000000000044400000000000003e40",
),
(
"MULTILINESTRING ((10 10,20 20),(40 40,30 30,40 20))",
"0105000000020000000102000000020000000000000000002440000000000000244000"
"0000000000344000000000000034400102000000030000000000000000004440000000"
"00000044400000000000003e400000000000003e400000000000004440000000000000"
"3440",
),
(
"MULTIPOLYGON (((30 20,45 40,10 40,30 20)),((15 5,40 10,10 20,15 5)))",
"010600000002000000010300000001000000040000000000000000003e400000000000"
"0034400000000000804640000000000000444000000000000024400000000000004440"
"0000000000003e40000000000000344001030000000100000004000000000000000000"
"2e40000000000000144000000000000044400000000000002440000000000000244000"
"000000000034400000000000002e400000000000001440",
),
(
"GEOMETRYCOLLECTION (POINT (40 10))",
"010700000001000000010100000000000000000044400000000000002440",
),
# 3D
(
"POINT (1 2 3)",
"0101000080000000000000f03f00000000000000400000000000000840",
),
(
"LINESTRING (30 10 3,10 30 3)",
"0102000080020000000000000000003e40000000000000244000000000000008400000"
"0000000024400000000000003e400000000000000840",
),
(
"POLYGON ((30 10 3,40 40 3,30 10 3))",
"010300008001000000030000000000000000003e400000000000002440000000000000"
"08400000000000004440000000000000444000000000000008400000000000003e4000"
"000000000024400000000000000840",
),
(
"MULTIPOINT (10 40 3,40 30 3)",
"0104000080020000000101000080000000000000244000000000000044400000000000"
"000840010100008000000000000044400000000000003e400000000000000840",
),
(
"MULTILINESTRING ((10 10 3,20 20 3))",
"0105000080010000000102000080020000000000000000002440000000000000244000"
"00000000000840000000000000344000000000000034400000000000000840",
),
(
"MULTIPOLYGON (((30 20 3,45 40 3,30 20 3)))",
"010600008001000000010300008001000000030000000000000000003e400000000000"
"0034400000000000000840000000000080464000000000000044400000000000000840"
"0000000000003e4000000000000034400000000000000840",
),
(
"GEOMETRYCOLLECTION (POINT (40 10 3))",
"0107000080010000000101000080000000000000444000000000000024400000000000"
"000840",
),
]
for geom, wkb in tests:
with self.subTest(geom=geom):
g = OGRGeometry(geom)
self.assertEqual(g.wkt, geom)
self.assertEqual(g.wkb.hex(), wkb)
class DeprecationTests(SimpleTestCase):
def test_coord_setter_deprecation(self):
geom = OGRGeometry("POINT (1 2)")
msg = "coord_dim setter is deprecated. Use set_3d() instead."
with self.assertWarnsMessage(RemovedInDjango60Warning, msg):
geom.coord_dim = 3
self.assertEqual(geom.coord_dim, 3)