Django Admin stopped working - 'module' object is not iterable - django

I'm getting started with Django. I can't get the admin to work (it used to work, I'm not sure what update made it break...).
As soon as I register a model in the admin, the website crashes with this error on any URL:
'module' object is not iterable
In the trace it happens to bug on this:
/Library/Python/2.7/site-packages/django/contrib/admin/sites.py in register
for model in model_or_iterable:
admin_class
<class 'django.contrib.admin.options.ModelAdmin'>
options
{}
model_or_iterable
<module 'model.Branch' from '...../farmpower/src/model/Branch.pyc'>
self
<django.contrib.admin.sites.AdminSite object at 0x1098196d0>
I've tried with different models, in that example, with Branch (code in admin.py):
from django.contrib import admin
from models import *
admin.site.register(Branch)
models.py:
import Page, Promotion, Branch, Contact
Branch.py
from django.db import models
from django.utils.translation import ugettext_lazy as _
class Branch(models.Model):
name = models.CharField
[...]
class Meta:
app_label = "model"
db_table = "cms_branch"
def __unicode__(self):
return self.name
Thank you for your help !

There are several things in your code that are not very neat. One of them might lead to the error you're seeing, though I don't know which one of 'em is it.
You use relative imports (from models import ...). It is more robust do do an absolute import like from yourapp.models import ...).
You use a "star import": from models import *. You don't really know what you're importing exactly in the file where you're doing this. Also automatic code checkers (like pyflakes) cannot check whether you're missing imports anymore.
You mention models.yml as the filename. That's not a .py extension, so python doesn't do a thing with that one.
The app name you set in the Meta on your models is model. Note that "models" and "model" are quite django-internal names. So having an app called "model" with a "models.py" could easily go wrong. Why is the app not yourapp or something like that?
Here are some ways in which it could go wrong:
Star import: perhaps you've imported a different admin in models.py? Which overwrites, through the star import, the one in admin.py?
The models.yml: if that really is the name, what does from models import * return? With a non-existing models.py? Try to import Branch explicitly: from models import Branch and see if it fails.
App name: if your app is really called "model", a relative import from models import * could perhaps get you the top-level "model" module instead of the "model.models" that you mean in case you mis-type something.

It's your
from models import *
it should be
from appName.models import className

Related

How do I import from current app in Django without using the app name?

My app is full of statements like this:
from my_app.model import Customer
While it works, I'll like to have a way to reference the current app without hard coding the app name into the import. Something like:
from keyword_for_current_app.model import Customer
Is there a clean way of achieving this with Django?
This is more of a python question than a Django one as it relates to how imports work. As far as I know, there isn't a way to do it as you describe, unless you change the structure of your files.
However, it isn't impossible to do something using Django's functionality to dynamically import models. You could swap some of this with importlib if you need a more general import rather than just returning the model class:
from django.apps import apps
# option 1
model = apps.get_model('app.Model')
# option 2
def get_model(model_name):
return apps.get_model(f'myapp.{model_name}')
# option 3
def get_model(model_name):
for model in apps.get_models():
if model.__name__ == model_name:
return model
The problem with option 1 for your use case is that you still need to specify the app name. Option 2 is an improvement, but you are hardcoding the app name into the function. Option 3 is the best, but might be problematic if you have models with the same name but in different apps/tables.
In my opinion, you should import each model explicitly at the top of your files. This is the cleanest and most readable way - if someone were to read your code, they would expect models to be imported this way.

How to retrieve data from a model of an App in the views of another application?

Hello django python developers. Indeed, I developed a django project composed of 2 applications.
MyApp and Blog
I want to retrieve the data from the MyApp App models from the database on the App Blog views without rewriting the same functions
How do I do it
You can import anything from one app to another. Just add in the top of you file proper from ... import ... to use it at it is.
If you want to use your class models, just do import with from starting from app level:
from MyApp.models import MyModel
my_model = MyModel.objects.first()
my_model.some_method()
If you have more things you want to import from a file, you can separate them with comma:
from MyApp.models import MyModel, some_function
my_model = MyModel.objects.first()
some_function(my_model)

How can I add inlines to the ModelAdmin of another app, without a circular dependency?

Let's say I have two models, in different apps. App Two knows about app One, but not the other way around:
# one/models.py
from django.db import models
class One(models.Model):
pass
# two/models.py
from django.db import models
from one.models import One
class Two(models.Model):
one = models.ForeignKey(One)
I also have One registered in the admin site:
# one/admin.py
from django.contrib import admin
from .models import One
admin.site.register(One)
How do I register Two as an Inline on One's admin page, without introducing a circular dependency between the two apps?
You can do this pretty simply, providing you don't mind accessing a 'private' attribute on the ModelAdmin. (Attributes beginning with an underscore are treated as private by convention.)
# two/admin.py
from django.contrib import admin
from one.models import One
from .models import Two
class TwoInline(admin.StackedInline):
model = Two
admin.site._registry[One].inlines.append(TwoInline)
I had the same issue but solved it more gentle way.
# one/admin.py
class OneAdmin(admin.ModelAdmin):
model = One
admin.site.register(One, OneAdmin)
# two/admin.py
class TwoInline(admin.TabularInline):
model = Two
import one.admin
class OneAdmin(one.admin.OneAdmin):
inlines = [TwoInline]
admin.site.unregister(One)
admin.site.register(One, OneAdmin)
As you see I extended the original ModelAdmin from first app and added inlines from second app. Don't forget to unregister the model from first app before registering it again.
It's safe and much better than to access private member of the class as was suggested.
I would try the following:
# one/admin.py
from django.contrib import admin
from one.models import One
from two.models import Two
class TwoInline(admin.StackedInline):
model = Two
class OneAdmin(admin.ModelAdmin):
inlines = [TwoInline,]
admin.site.register(One, OneAdmin)
You can read more at the docs.

Override Oscar models using other Oscar models from the same app

I need achieve something like this:
from oscar.apps.catalogue.abstract_models import AbstractProduct
from oscar.apps.catalogue.models import ProductClass
Product(AbstractProduct):
#property
display(self):
if self.product_class = ProductClass.objects.get(pk=1):
#do something
else:
#do something else
But when I do a from catalogue.models import Product elsewhere I invariably get the default Oscar Product and not my overridden Product with the display() property.
I believe this is because the built-in Oscar Product is being registered before my custom one when I do the import ProductClass.
However to achieve the functionality I need it's vital I have access to ProductClass in the forked version of Product!
How can I get around this catch-22?
When overriding Oscar models you need to move any non-abstract imports below the class definitions that are meant to replace models that come with Oscar. Here's an example.
In your case it should be safe to just move the models import below:
from oscar.apps.catalogue.abstract_models import AbstractProduct
Product(AbstractProduct):
#property
display(self):
if self.product_class == ProductClass.objects.get(pk=1):
#do something
else:
#do something else
from oscar.apps.catalogue.models import *
The display property will continue to work since by the time it is called for the first time, the module scope will already contain all the necessary models.
I've changed the import to * to make sure that all other models are loaded from Oscar.
Please note that the star import will inevitably try to import the Product model as well but Oscar will notice that a model by that name is already registered and will simply discard the other definition. It is ugly and confusing but that's the Oscar's recommended method.

Can someone explain me how to get sorl-thumbnail working on the Admin page of Django?

I've got sorl-thumbnail up and running in templates with Redis to store the thumbnails. Great stuff!! However, I would like to have thumbails in my Admin. I used the example in the documentation (see below) but with no luck.
from gallery.models import Photo
from django.contrib import admin
from sorl.thumbnail.admin import AdminImageMixin
class PhotoAdmin(AdminImageMixin, admin.ModelAdmin):
pass
admin.site.register(Photo, PhotoAdmin)
What am I doing wrong?
I do something very similar and it works for me. However, I use a slightly different method, importing my admin from a utils/admin.py in my site base instead, allowing easy inheritance across my models with other apps such as django-reversion, django-guardian, and django-markitup.
gallery/admin.py:
#from django.contrib import admin
from utils import admin
from gallery.models import Photo
class PhotoAdmin(admin.ModelAdmin):
#your customizations
admin.site.register(Photo,PhotoAdmin)
utils/admin.py:
from django.contrib.admin import *
from django.db import models
from sorl.thumbnail.admin import AdminImageMixin
class ModelAdmin(AdminImageMixin, ModelAdmin):
pass
Your model's ImageFields need to be sorl's ImageField (from sorl.thumbnail.fields import ImageField) instead of the standard django.db.models.ImageField.
This field is a drop-in replacement, so just updating this should fix the issue, or at least it did for me. If you are using South for database migrations, note that it will generate one for this, which is fine.