16

Is there any downside to using something like

from django.db.models.loading import get_model

def get_something():
    model = get_model('app', 'Model')
    return model.something()

instead of

from app.models import Model

def get_something():
    return Model.something()

The second example can lead to circular dependencies while the first example does not, but the second example is seen much more often.

Update: You would get circular dependency errors if the second example was in a model called Other_Model and Model imported Other_Model as well -- a simple circular import.

5
  • Can you please update your question with an example of how there are MRO issues with the second example? Commented May 29, 2013 at 1:27
  • if you are getting an object with a pk, i would recommend get_object_or_404(Model, pk=pk) Commented May 29, 2013 at 1:29
  • karthikr: sure, but that's just an example. Imaging you were accessing a method on Model instead. Commented May 29, 2013 at 1:34
  • Perhaps your issue is with circular dependencies, not MRO. See stackoverflow.com/questions/8466726/…. A full Model example of what you're trying to achieve would help. Commented May 29, 2013 at 1:40
  • You are right -- I mean circular dependencies. The key question here is are there any traps in using get_model(). Commented May 29, 2013 at 1:43

2 Answers 2

13

Generally, the get_model functionality is reserved for times when a model needs to be loaded dynamically (say, if you don't know if someone will pass a service a myapp.Person, a myapp.Place, or a myapp.Thing and they all have the same interface). I will go so far as to say that any other use should be auto-flagged in code review if for no other reason than the fact that it introduces the unexpected.

As to internal mechanics, there really isn't a substantial difference. Inevitably the get_model version will call __import__. That said, it is not without bugs. Use of actual import statements will avoid this problem.


As to MRO issues, it is a rare situation where circular imports could not be resolved by refactoring. If you have two apps which are so interdependent that they cause a circular import, then you really need to re-think those apps. (My guess is that you are really dealing with one app.)

Sign up to request clarification or add additional context in comments.

6 Comments

Oh, and I suppose that technically you could argue that use of a function call is almost always slightly slower.
+1 Calling get_model will initialise the AppCache on the first call, and use the cache for all subsequent calls. If get_model is called as part of model definition, who know what problems may ensue.
I'll have to do some reading on Django's AppCache. It seems if I confine my use of get_model() to class methods, I will avoid these model loading issues.
@Erik Confining use of get_model() to class methods is probably ok. As suggested in this answer though, you're better off refactoring to avoid the need for circular imports. Cyclic dependencies often indicate a design problem.
@Austin: agreed. I'm looking at refactoring a working app to using get_model() instead of imports. That way I can move the method around if I would like to without worrying about imports. I'm not sold on it yet -- which is why I am posting here.
|
4

Using get_model may be confusing if your app path is not so straight forward.

For example, if your model exists in apps.MyApp.models.misc.MyModel, then the call would be get_model('MyApp', 'misc.MyModel') which isn't too intuitive. You'll probably have to figure it out by trial and error or digging into the source.

(Note that this applies for Django 1.6 and before. Django 1.7+ has a lot of changes to the app naming and this may have changed)


Another way to avoid circular dependencies is to do the import directly in the method like so:

def get_something():
    from app.models import Model
    return Model.something()

This will defer the import until the first invocation of the method.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.