Strange django import behavior

Can anyone explain this behavior:

django project called foo

file bar/models.py :

 class MyModelError(TypeError): pass class MyModel(models.Model): ... 

./manage.py shell

 >>> from foo.bar.models import MyModel as m1 >>> from bar.models import MyModel as m2 >>> from foo.bar.models import MyModelError as e1 >>> from bar.models import MyModelError as e2 >>> m1 is m2 True >>> e1 is e2 False 

False ?!

 >>> m1 <class 'foo.bar.models.MyModel'> >>> m2 <class 'foo.bar.models.MyModel'> >>> e1 <class 'foo.bar.models.MyModelError'> >>> e1 <class 'bar.models.MyModelError'> 

Any idea what I'm doing wrong here? My workaround (except that I am importing the "correct path") is to make the error class a member of the model itself (e.g. django model.DoesNotExists ), but I would like to know what is going on

+4
source share
2 answers

Django uses metaclasses to define models. There is a check to avoid defining the model twice, so when the class is created, if it is already defined, you get the version that was previously defined. See django.db.models.base.ModelBase :

 from django.db.models.loading import get_model # Bail out early if we have already created this class. m = get_model(new_class._meta.app_label, name, False) if m is not None: return m 

While the error classes are regular Python classes and there is no such caching, you get different versions, since the modules to which they belong are different. I think this happens because when you start Django runerver you end up in two ways of loading the same module from the path:

  • Current directory
  • Directory above current directory

This means that you can import fully qualified packages (including the name of the project) and it all works.

I try to never import the project name to avoid this problem.

+4
source

In most programming languages, error traversal has a ladder mechanism. Therefore, if an error occurs, the exception mechanism begins to look for an exception to handle the error. If an exception cannot be handled in this class, it saves the upper levels of the search through the classes from which this class is derived ... It saves this process at the highest level of inheritance ...

So, you define a ModelError class derived from TypeError . And importing this class from another path can cause the python IP interface to recognize the two as different classes.

Python Documentation

0
source

All Articles