mirror of
https://github.com/django/django.git
synced 2024-12-22 09:05:43 +00:00
Fixed #35837 -- Added missing alters_data=True to QuerySet and UserManager methods.
Thank you to Jason Chambers for the report and to Mariusz Felisiak for the review.
This commit is contained in:
parent
03c0a3de72
commit
611bf6c2e2
@ -174,11 +174,15 @@ class UserManager(BaseUserManager):
|
|||||||
extra_fields.setdefault("is_superuser", False)
|
extra_fields.setdefault("is_superuser", False)
|
||||||
return self._create_user(username, email, password, **extra_fields)
|
return self._create_user(username, email, password, **extra_fields)
|
||||||
|
|
||||||
|
create_user.alters_data = True
|
||||||
|
|
||||||
async def acreate_user(self, username, email=None, password=None, **extra_fields):
|
async def acreate_user(self, username, email=None, password=None, **extra_fields):
|
||||||
extra_fields.setdefault("is_staff", False)
|
extra_fields.setdefault("is_staff", False)
|
||||||
extra_fields.setdefault("is_superuser", False)
|
extra_fields.setdefault("is_superuser", False)
|
||||||
return await self._acreate_user(username, email, password, **extra_fields)
|
return await self._acreate_user(username, email, password, **extra_fields)
|
||||||
|
|
||||||
|
acreate_user.alters_data = True
|
||||||
|
|
||||||
def create_superuser(self, username, email=None, password=None, **extra_fields):
|
def create_superuser(self, username, email=None, password=None, **extra_fields):
|
||||||
extra_fields.setdefault("is_staff", True)
|
extra_fields.setdefault("is_staff", True)
|
||||||
extra_fields.setdefault("is_superuser", True)
|
extra_fields.setdefault("is_superuser", True)
|
||||||
@ -190,6 +194,8 @@ class UserManager(BaseUserManager):
|
|||||||
|
|
||||||
return self._create_user(username, email, password, **extra_fields)
|
return self._create_user(username, email, password, **extra_fields)
|
||||||
|
|
||||||
|
create_superuser.alters_data = True
|
||||||
|
|
||||||
async def acreate_superuser(
|
async def acreate_superuser(
|
||||||
self, username, email=None, password=None, **extra_fields
|
self, username, email=None, password=None, **extra_fields
|
||||||
):
|
):
|
||||||
@ -203,6 +209,8 @@ class UserManager(BaseUserManager):
|
|||||||
|
|
||||||
return await self._acreate_user(username, email, password, **extra_fields)
|
return await self._acreate_user(username, email, password, **extra_fields)
|
||||||
|
|
||||||
|
acreate_superuser.alters_data = True
|
||||||
|
|
||||||
def with_perm(
|
def with_perm(
|
||||||
self, perm, is_active=True, include_superusers=True, backend=None, obj=None
|
self, perm, is_active=True, include_superusers=True, backend=None, obj=None
|
||||||
):
|
):
|
||||||
|
@ -660,9 +660,13 @@ class QuerySet(AltersData):
|
|||||||
obj.save(force_insert=True, using=self.db)
|
obj.save(force_insert=True, using=self.db)
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
create.alters_data = True
|
||||||
|
|
||||||
async def acreate(self, **kwargs):
|
async def acreate(self, **kwargs):
|
||||||
return await sync_to_async(self.create)(**kwargs)
|
return await sync_to_async(self.create)(**kwargs)
|
||||||
|
|
||||||
|
acreate.alters_data = True
|
||||||
|
|
||||||
def _prepare_for_bulk_create(self, objs):
|
def _prepare_for_bulk_create(self, objs):
|
||||||
from django.db.models.expressions import DatabaseDefault
|
from django.db.models.expressions import DatabaseDefault
|
||||||
|
|
||||||
@ -835,6 +839,8 @@ class QuerySet(AltersData):
|
|||||||
|
|
||||||
return objs
|
return objs
|
||||||
|
|
||||||
|
bulk_create.alters_data = True
|
||||||
|
|
||||||
async def abulk_create(
|
async def abulk_create(
|
||||||
self,
|
self,
|
||||||
objs,
|
objs,
|
||||||
@ -853,6 +859,8 @@ class QuerySet(AltersData):
|
|||||||
unique_fields=unique_fields,
|
unique_fields=unique_fields,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
abulk_create.alters_data = True
|
||||||
|
|
||||||
def bulk_update(self, objs, fields, batch_size=None):
|
def bulk_update(self, objs, fields, batch_size=None):
|
||||||
"""
|
"""
|
||||||
Update the given fields in each of the given objects in the database.
|
Update the given fields in each of the given objects in the database.
|
||||||
@ -941,12 +949,16 @@ class QuerySet(AltersData):
|
|||||||
pass
|
pass
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
get_or_create.alters_data = True
|
||||||
|
|
||||||
async def aget_or_create(self, defaults=None, **kwargs):
|
async def aget_or_create(self, defaults=None, **kwargs):
|
||||||
return await sync_to_async(self.get_or_create)(
|
return await sync_to_async(self.get_or_create)(
|
||||||
defaults=defaults,
|
defaults=defaults,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
aget_or_create.alters_data = True
|
||||||
|
|
||||||
def update_or_create(self, defaults=None, create_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
|
Look up an object with the given kwargs, updating one with defaults
|
||||||
@ -992,6 +1004,8 @@ class QuerySet(AltersData):
|
|||||||
obj.save(using=self.db)
|
obj.save(using=self.db)
|
||||||
return obj, False
|
return obj, False
|
||||||
|
|
||||||
|
update_or_create.alters_data = True
|
||||||
|
|
||||||
async def aupdate_or_create(self, defaults=None, create_defaults=None, **kwargs):
|
async def aupdate_or_create(self, defaults=None, create_defaults=None, **kwargs):
|
||||||
return await sync_to_async(self.update_or_create)(
|
return await sync_to_async(self.update_or_create)(
|
||||||
defaults=defaults,
|
defaults=defaults,
|
||||||
@ -999,6 +1013,8 @@ class QuerySet(AltersData):
|
|||||||
**kwargs,
|
**kwargs,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
aupdate_or_create.alters_data = True
|
||||||
|
|
||||||
def _extract_model_params(self, defaults, **kwargs):
|
def _extract_model_params(self, defaults, **kwargs):
|
||||||
"""
|
"""
|
||||||
Prepare `params` for creating a model instance based on the given
|
Prepare `params` for creating a model instance based on the given
|
||||||
|
@ -392,6 +392,22 @@ Miscellaneous
|
|||||||
* The :func:`~django.template.context_processors.debug` context processor is no
|
* The :func:`~django.template.context_processors.debug` context processor is no
|
||||||
longer included in the default project template.
|
longer included in the default project template.
|
||||||
|
|
||||||
|
* The following methods now have ``alters_data=True`` set to prevent side
|
||||||
|
effects when :ref:`rendering a template context <alters-data-description>`:
|
||||||
|
|
||||||
|
* :meth:`.UserManager.create_user`
|
||||||
|
* :meth:`.UserManager.acreate_user`
|
||||||
|
* :meth:`.UserManager.create_superuser`
|
||||||
|
* :meth:`.UserManager.acreate_superuser`
|
||||||
|
* :meth:`.QuerySet.create`
|
||||||
|
* :meth:`.QuerySet.acreate`
|
||||||
|
* :meth:`.QuerySet.bulk_create`
|
||||||
|
* :meth:`.QuerySet.abulk_create`
|
||||||
|
* :meth:`.QuerySet.get_or_create`
|
||||||
|
* :meth:`.QuerySet.aget_or_create`
|
||||||
|
* :meth:`.QuerySet.update_or_create`
|
||||||
|
* :meth:`.QuerySet.aupdate_or_create`
|
||||||
|
|
||||||
.. _deprecated-features-5.2:
|
.. _deprecated-features-5.2:
|
||||||
|
|
||||||
Features deprecated in 5.2
|
Features deprecated in 5.2
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from unittest import mock, skipIf
|
from unittest import mock, skipIf
|
||||||
|
|
||||||
|
from django.contrib.auth.models import User
|
||||||
from django.template import TemplateSyntaxError
|
from django.template import TemplateSyntaxError
|
||||||
from django.test import RequestFactory
|
from django.test import RequestFactory, TestCase
|
||||||
|
|
||||||
from .test_dummy import TemplateStringsTests
|
from .test_dummy import TemplateStringsTests
|
||||||
|
|
||||||
@ -135,3 +136,31 @@ class Jinja2Tests(TemplateStringsTests):
|
|||||||
self.assertEqual(len(debug["source_lines"]), 0)
|
self.assertEqual(len(debug["source_lines"]), 0)
|
||||||
self.assertTrue(debug["name"].endswith("nonexistent.html"))
|
self.assertTrue(debug["name"].endswith("nonexistent.html"))
|
||||||
self.assertIn("message", debug)
|
self.assertIn("message", debug)
|
||||||
|
|
||||||
|
|
||||||
|
@skipIf(jinja2 is None, "this test requires jinja2")
|
||||||
|
class Jinja2SandboxTests(TestCase):
|
||||||
|
engine_class = Jinja2
|
||||||
|
backend_name = "jinja2"
|
||||||
|
options = {"environment": "jinja2.sandbox.SandboxedEnvironment"}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
super().setUpClass()
|
||||||
|
params = {
|
||||||
|
"DIRS": [],
|
||||||
|
"APP_DIRS": True,
|
||||||
|
"NAME": cls.backend_name,
|
||||||
|
"OPTIONS": cls.options,
|
||||||
|
}
|
||||||
|
cls.engine = cls.engine_class(params)
|
||||||
|
|
||||||
|
def test_set_alters_data(self):
|
||||||
|
template = self.engine.from_string(
|
||||||
|
"{% set test = User.objects.create_superuser("
|
||||||
|
"username='evil', email='a@b.com', password='xxx') %}"
|
||||||
|
"{{ test }}"
|
||||||
|
)
|
||||||
|
with self.assertRaises(jinja2.exceptions.SecurityError):
|
||||||
|
template.render(context={"User": User})
|
||||||
|
self.assertEqual(User.objects.count(), 0)
|
||||||
|
Loading…
Reference in New Issue
Block a user