当前位置: 动力学知识库 > 问答 > 编程问答 >

Class.object.filter does not work properly after project migration from django 1.6 to 1.8

问题描述:

project was written in django 1.6 and recently migrated to django 1.8.15. It works quite well but project tests showed a failure during executing line:

objs = Agent.objects.filter(Q(first_name__icontains=term) | Q(last_name__icontains=term) | Q(accord_id__icontains=term) | Q(company__icontains=term))

Traceback (most recent call last):

File ".../project/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 132, in get_response

response = wrapped_callback(request, *callback_args, **callback_kwargs)

File ".../project/local/lib/python2.7/site-packages/django/views/generic/base.py", line 71, in view

return self.dispatch(request, *args, **kwargs)

File ".../project/local/lib/python2.7/site-packages/django_select2/views.py", line 57, in dispatch

return super(Select2View, self).dispatch(request, *args, **kwargs)

File ".../project/local/lib/python2.7/site-packages/django/views/generic/base.py", line 89, in dispatch

return handler(request, *args, **kwargs)

File ".../project/local/lib/python2.7/site-packages/django_select2/views.py", line 76, in get

self.get_results(request, term, page, context)

File ".../project/local/lib/python2.7/site-packages/django_select2/views.py", line 194, in get_results

return field.get_results(request, term, page, context)

File ".../project/project/app/fields.py", line 33, in get_results

objs = Agent.objects.filter(Q(first_name__icontains=term) | Q(last_name__icontains=term) | Q(accord_id__icontains=term) | Q(company__icontains=term))

File ".../project/local/lib/python2.7/site-packages/django/db/models/manager.py", line 127, in manager_method

return getattr(self.get_queryset(), name)(*args, **kwargs)

File ".../project/local/lib/python2.7/site-packages/django/db/models/query.py", line 679, in filter

return self._filter_or_exclude(False, *args, **kwargs)

File ".../project/local/lib/python2.7/site-packages/django/db/models/query.py", line 697, in _filter_or_exclude

clone.query.add_q(Q(*args, **kwargs))

File ".../project/local/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1310, in add_q

clause, require_inner = self._add_q(where_part, self.used_aliases)

File ".../project/local/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1332, in _add_q

current_negated, allow_joins, split_subq)

File ".../project/local/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1338, in _add_q

allow_joins=allow_joins, split_subq=split_subq,

File ".../project/local/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1150, in build_filter

lookups, parts, reffed_expression = self.solve_lookup_type(arg)

File ".../project/local/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1036, in solve_lookup_type

_, field, _, lookup_parts = self.names_to_path(lookup_splitted, self.get_meta())

File ".../project/local/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1407, in names_to_path

for int_model in opts.get_base_chain(model):

TypeError: 'NoneType' object is not iterable

Internal Server Error: /some/json/file.json

Traceback (most recent call last):

File ".../project/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 132, in get_response

response = wrapped_callback(request, *callback_args, **callback_kwargs)

File ".../project/local/lib/python2.7/site-packages/django/views/generic/base.py", line 71, in view

return self.dispatch(request, *args, **kwargs)

File ".../project/local/lib/python2.7/site-packages/django_select2/views.py", line 57, in dispatch

return super(Select2View, self).dispatch(request, *args, **kwargs)

File ".../project/local/lib/python2.7/site-packages/django/views/generic/base.py", line 89, in dispatch

return handler(request, *args, **kwargs)

File ".../project/local/lib/python2.7/site-packages/django_select2/views.py", line 76, in get

self.get_results(request, term, page, context)

File ".../project/local/lib/python2.7/site-packages/django_select2/views.py", line 194, in get_results

return field.get_results(request, term, page, context)

File ".../project/project/app/fields.py", line 33, in get_results

Q(company__icontains=term))

File ".../project/local/lib/python2.7/site-packages/django/db/models/manager.py", line 127, in manager_method

return getattr(self.get_queryset(), name)(*args, **kwargs)

File ".../project/local/lib/python2.7/site-packages/django/db/models/query.py", line 679, in filter

return self._filter_or_exclude(False, *args, **kwargs)

File ".../project/local/lib/python2.7/site-packages/django/db/models/query.py", line 697, in _filter_or_exclude

clone.query.add_q(Q(*args, **kwargs))

File ".../project/local/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1310, in add_q

clause, require_inner = self._add_q(where_part, self.used_aliases)

File ".../project/local/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1332, in _add_q

current_negated, allow_joins, split_subq)

File ".../project/local/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1338, in _add_q

allow_joins=allow_joins, split_subq=split_subq,

File ".../project/local/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1150, in build_filter

lookups, parts, reffed_expression = self.solve_lookup_type(arg)

File ".../project/local/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1036, in solve_lookup_type

_, field, _, lookup_parts = self.names_to_path(lookup_splitted, self.get_meta())

File ".../project/local/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1407, in names_to_path

for int_model in opts.get_base_chain(model):

TypeError: 'NoneType' object is not iterable

....

But in django 1.6 all works well. So i make some inspection.

In project there is a class Agent (class Agent(AbstractUser, AnotherClass):), metaclass Agent2Metaclass (class Agent2Metaclass(models.base.ModelBase):) and class Agent2 (class Agent2(TimeStampedModel):) using Agent2Metaclass:

class Agent(AbstractUser, AnotherClass):

...

CHANGE_FIELDS_WITH_APPROVAL= ('first_name', 'last_name', 'email', ... )

...

class Agent2Metaclass(models.base.ModelBase):

def __new__(cls, name, bases, attrs):

attrs = collections.OrderedDict(attrs)

for field in Agent.CHANGE_FIELDS_WITH_APPROVAL:

attrs[field] = Agent._meta.get_field(field)

return super(Agent2Metaclass, cls).__new__(cls, name, bases, attrs)

class Agent2(TimeStampedModel):

__metaclass__ = Agent2Metaclass

agent = models.OneToOneField(Agent)

...

And now what is going on showed in console:

Django 1.6:

 In [1]: from app.models import Agent

In [2]: print Agent._meta.fields

[<django.db.models.fields.AutoField: id>, <django.db.models.fields.CharField: password>, <django.db.models.fields.DateTimeField: last_login>, <django.db.models.fields.BooleanField: is_superuser>, <django.db.models.fields.CharField: username>, ...]

In [3]: print Agent._meta.fields[2]

<django.db.models.fields.DateTimeField: last_login>

In [4]: print Agent._meta.fields[3]

<django.db.models.fields.BooleanField: is_superuser>

In [5]: print Agent._meta.fields[4]

<django.db.models.fields.CharField: username>

In [6]: print Agent._meta.fields[5]

<django.db.models.fields.CharField: first_name>

In [7]: print Agent._meta.fields[6]

<django.db.models.fields.CharField: last_name>

In [8]: print type(Agent._meta.fields[6])

<class 'django.db.models.fields.CharField'>

In [9]: print Agent._meta.fields[3]

<django.db.models.fields.BooleanField: is_superuser>

In [10]: print Agent._meta.fields[3].__class__

<class 'django.db.models.fields.BooleanField'>

In [11]: print Agent._meta.fields[3].__class__.__class__

<type 'type'>

In [12]: print Agent.objects.filter(first_name="Petr")

[<Agent: John Adams>, <Agent: Igor Hnizdo>, '...(remaining elements truncated)...']

Django 1.8:

 In [1]: from app.models import Agent

In [2]: print Agent._meta.fields

(<django.db.models.fields.AutoField: id>, <django.db.models.fields.CharField: password>, <django.db.models.fields.DateTimeField: last_login>, <django.db.models.fields.BooleanField: is_superuser>, <django.db.models.fields.CharField: username>, <django.db.models.fields.CharField: first_name>, ...)

In [3]: print Agent._meta.fields[1]

app.Agent.password

In [4]: print Agent._meta.fields[2]

app.Agent.last_login

In [5]: print Agent._meta.fields[3]

app.Agent.is_superuser

In [6]: print Agent._meta.fields[4]

app.Agent.username

In [7]: print Agent._meta.fields[5]

app.Agent2.first_name

#this seems to me as strange behaviour - why is field of Agent presented as field of Agent2?

In [8]: print Agent._meta.fields[5].__class__

<class 'django.db.models.fields.CharField'>

In [9]: print Agent._meta.fields[4].__class__

<class 'django.db.models.fields.CharField'>

In [10]: from app.models import Agent2

In [11]: print Agent2.objects.filter(first_name="Petr")

[<Agent2: Petr Pavel>, <Agent2: Petr Petrovic>, <Agent2: Petr Cech>, ...]

In [12]: print Agent.objects.filter(first_name="Petr")

--------------------------------------------------------------------------------------------------------------------------------

TypeError Traceback (most recent call last)

and errors like above are shown.

It seems like fields of Agent were changed during execution of Agent2Metaclass in order to set _forward_fields_map[] in django.db.models.options. Fields of Agent are set to Agent before executing the Agent2Metaclass.

And the error appears in django.db.models.sql.query in def names_to_path because opts.get_base_chain(model) is None or NoneType.

If i paste a condition "if opts.get_base_chain(model) is not None:" before the for cycle it seems it works ok. But it is a good solution?

It is OK when some fields of Agent are set as fields of Agent2 after executing Agent2Metaclass?

It is a good behaviour of django, that the Agent.object.filter(first_name="Petr") ends with error?

If i am wrong, how can i filter Agent?

Thank you.

========================================================================

List from def names_to_path (before my if condition) during Agent.object.filter("somestring") in django 1.6:

-------------------------------

model: None

names: ['session_key']

opts: sessions.session

opts.model: <class 'django.contrib.sessions.models.Session'>

-------------------------------

model: None

names: ['expire_date']

opts: sessions.session

opts.model: <class 'django.contrib.sessions.models.Session'>

-------------------------------

model: None

names: ['pk']

opts: app.agent

opts.model: <class 'app.models.Agent'>

-------------------------------

model: None

names: ['first_name']

opts: app.agent

opts.model: <class 'app.models.Agent'>

-------------------------------

model: None

names: ['last_name']

opts: app.agent

opts.model: <class 'app.models.Agent'>

-------------------------------

model: None

names: ['company']

opts: app.agent

opts.model: <class 'app.models.Agent'>

-------------------------------

model: None

names: ['date_joined']

opts: app.agent

opts.model: <class 'app.models.Agent'>

List from def names_to_path (before my if condition) during Agent.object.filter("somestring") in django 1.8:

-------------------------------

model: <class 'django.contrib.sessions.models.Session'>

names: ['session_key']

opts: sessions.session

opts.model: <class 'django.contrib.sessions.models.Session'>

-------------------------------

model: <class 'django.contrib.sessions.models.Session'>

names: ['session_key']

opts: sessions.session

opts.model: <class 'django.contrib.sessions.models.Session'>

-------------------------------

model: <class 'django.contrib.sessions.models.Session'>

names: ['expire_date', 'gt']

opts: sessions.session

opts.model: <class 'django.contrib.sessions.models.Session'>

-------------------------------

model: <class 'django.contrib.sessions.models.Session'>

names: ['expire_date']

opts: sessions.session

opts.model: <class 'django.contrib.sessions.models.Session'>

-------------------------------

model: <class 'app.models.Agent'>

names: ['pk']

opts: app.agent

opts.model: <class 'app.models.Agent'>

-------------------------------

model: <class 'app.models.Agent'>

names: ['pk']

opts: app.agent

opts.model: <class 'app.models.Agent'>

-------------------------------

model: <class 'app.models.Agent2'>

names: ['first_name', 'icontains']

opts: app.agent

opts.model: <class 'app.models.Agent'>

-------------------------------

model: <class 'app.models.Agent2'>

names: ['first_name']

opts: app.agent

opts.model: <class 'app.models.Agent'>

-------------------------------

model: <class 'app.models.Agent2'>

names: ['last_name', 'icontains']

opts: app.agent

opts.model: <class 'app.models.Agent'>

-------------------------------

model: <class 'app.models.Agent2'>

names: ['last_name']

opts: app.agent

opts.model: <class 'app.models.Agent'>

-------------------------------

model: <class 'app.models.Agent2'>

names: ['company', 'icontains']

opts: app.agent

opts.model: <class 'app.models.Agent'>

-------------------------------

model: <class 'app.models.Agent2'>

names: ['company']

opts: app.agent

opts.model: <class 'app.models.Agent'>

-------------------------------

model: <class 'app.models.Agent'>

names: ['date_joined']

opts: app.agent

opts.model: <class 'app.models.Agent'>

分享给朋友:
您可能感兴趣的文章:
随机阅读: