Code

Opened 6 years ago

Closed 6 years ago

#7095 closed (fixed)

Error with Many2Many filter() in models managers after queryset-refactor merge

Reported by: fcaprioli@… Owned by: nobody
Component: Database layer (models, ORM) Version: master
Severity: Keywords:
Cc: Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: UI/UX:

Description

Hi,
first of all, thank you all for your excellent work; after the qs-rf branch merge, there is a small regression that cause a python error in where.py during an update() if a custom Manager tries to .filter() thru a ManyToManyField in get_query_set().
This breaks, for example, CurrentSiteManager with a M2M 'site' field.

So, if you have a model like:

from django.db import models
from django.contrib.sites.models import Site
from django.contrib.sites.managers import CurrentSiteManager

class Dummy(models.Model):
    dumb = models.TextField()
    site = models.ManyToManyField(Site)
    
    objects = CurrentSiteManager()

def dummy_view(request):
    t = Dummy.objects.create(dumb='abc')
    t.site.add(settings.SITE_ID)
    t.save()

t.save() would give a TypeError: object of type 'Query' has no len().
At some point, a Query object get passed to make_atom rather than a list.
This is the traceback:

Traceback:
File "D:\Arturo\django\core\handlers\base.py" in get_response
  82.                 response = callback(request, *callback_args, **callback_kwargs)
File "D:\Arturo\arturo5\magazine\views_manager_article.py" in article_add
  45.     t.save()
File "D:\Arturo\django\db\models\base.py" in save
  298.         self.save_base()
File "D:\Arturo\django\db\models\base.py" in save_base
  338.                     manager.filter(pk=pk_val)._update(values)
File "D:\Arturo\django\db\models\query.py" in _update
  299.         query.execute_sql(None)
File "D:\Arturo\django\db\models\sql\subqueries.py" in execute_sql
  112.         super(UpdateQuery, self).execute_sql(result_type)
File "D:\Arturo\django\db\models\sql\query.py" in execute_sql
  1432.             sql, params = self.as_sql()
File "D:\Arturo\django\db\models\sql\subqueries.py" in as_sql
  136.         where, params = self.where.as_sql()
File "D:\Arturo\django\db\models\sql\where.py" in as_sql
  61.                     sql, params = self.make_atom(child, qn)
File "D:\Arturo\django\db\models\sql\where.py" in make_atom
  130.             return ('%s IN (%s)' % (field_sql, ', '.join(['%s'] * len(value))),

Exception Type: TypeError at /arturo/magazine/add/
Exception Value: object of type 'Query' has no len()

Attachments (0)

Change History (4)

comment:1 Changed 6 years ago by mtredinnick

(In [7494]) Allow Query objects to be values in query filters. This already existed for
relations, but not for normal fields. The latter comes up naturally in some
update statements.

Refs #7095

comment:2 Changed 6 years ago by mtredinnick

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Triage Stage changed from Unreviewed to Accepted

The above commit fixes the problem for SQLite and PostgreSQL. Unfortunately, it reveals another bug that affects MySQL users because of MySQL's non-standard UPDATE syntax rules. Working on that piece of the puzzle now.

comment:3 Changed 6 years ago by mtredinnick

(In [7495]) Added a test to demonstrate the remaining problem in #7095.

Only fails for MySQL (because they've made some interesting syntax choices).
Refs #7095.

comment:4 Changed 6 years ago by mtredinnick

  • Resolution set to fixed
  • Status changed from new to closed

(In [7496]) Made some types of nested update queries very slightly more efficient at the
database level. Also worked around the fact that MySQL (and maybe other
backends we don't know about) cannot select from the table they're updating.

Fixed #7095.

Add Comment

Modify Ticket

Change Properties
<Author field>
Action
as closed
as The resolution will be set. Next status will be 'closed'
The resolution will be deleted. Next status will be 'new'
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.