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

37 views
Skip to first unread message

Ladislav Michlíček

unread,
Oct 21, 2016, 9:40:44 AM10/21/16
to Django users
Hello,
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'>
Reply all
Reply to author
Forward
0 new messages