I've made a django app, which is designed to be easily pluggable, and only has 1 view, and 1 model that project planning to use the app need to be aware of.
For ease, I'd like to just make the view and model available from the app-level. So rather than:
from mything.views import MyView
from mything.models import MyModel
You can instead just do:
from mything import MyView, MyModel
I changed the __init__.py file in the app to be like this:
from .views import MyView
from .models import MyModel
Of course I get the old django.core.exceptions.AppRegistryNotReady raised, since it's attempting to run the models.py code before the apps are loaded.
So I came up with the following workaround, and I'm wondering if it's a reasonable pattern to use or not. Now in __init__.py I have:
def _expose_items():
from .views import MyView
from .models import MyModel
globals()['MyView'] = MyView
globals()['MyModel'] = MyModel
And in my app's apps.py:
from . import _expose_items
class MyThingConfig(AppConfig):
name = 'mything'
def ready(self):
_expose_items()
So now indeed, I can directly import the view and model from the outside. Is this useful, or horrible?
Most Django apps do not collect views or models to the top level module. Refer to django.contrib.auth as an example.
Most Django apps do not collect views or models to the top level module. Use clear documentation to demonstrate how to import from your app. Hacks including globals() will probably create more trouble than help.
Refer to django.contrib.auth as an example.
Related
If I do that :
from myapp import models
User.objects.first()
I got that error :
NameError : name 'User' is not defined
whereas if I do that
import myapp
myapp.models.User.objects.first()
it works
I don't understand at all why I have that problem
Thank you very much for your help !
Replace:
from myapp import models
with the following:
This way, you are telling Django which model classes to import rather than leaving Django guessing what to do with it.
It prevents you from loading unnecessary models which might not be used right away and could potentially increase load time.
from myapp.models import User
In your example, your have not imported class User actually. You have imported it's module called models
You can do one of these:
from myapp import models
models.User.objects.first()
Or:
from myapp.models import User
User.objects.first()
I am relatively new to django, and trying to trigger a function on login. I have tested the function itself, and it works fine. The django-allauth login is also correctly configured. However, i cannot seem to trigger the signal below on login.
See code below... Any help would be appreciated...
pages/apps.py
from django.apps import AppConfig
class PagesConfig(AppConfig):
name = 'pages'
def ready(self):
import apps.pages.signals
pages/signals.py
from allauth.account.signals import user_logged_in
from django.dispatch.dispatcher import receiver
from django.utils import timezone
from datetime import timedelta
from .models import Token
#receiver(user_logged_in)
def user_logged_in_(request, user, **kwargs):
is_valid = Token.objects.filter(valid_until__gte=timezone.now() + timezone.timedelta(seconds=10800)).values()
if not is_valid:
new = Token(token='valid', valid_until=timezone.now())
else:
new = Token(token='not valid', valid_until=timezone.now())
new.save()
Managed to resolve this after much digging online...
You need to use the full python path to the application. This needs to be consistent with in settings.py, apps.py and init.py i.e.
settings.py
INSTALLED_APPS = ['dir.appname',]
apps.py
from django.apps import AppConfig
class AppnameConfig(AppConfig):
name = 'dir.appname'
def ready(self):
import dir.appname.signals
init.py
default_app_config = 'dir.appname.apps.AppnameConfig'
This following articles were useful in helping resolve the issue -
Django : Can't import 'module'. Check that module AppConfig.name is correct
How do I hook a django-allauth signal?
after customizing django oscar app (address) and adding a new field named 'area' when I run migrate it gave me Unknown field(s) (area) specified for UserAddress
I used the command
./manage.py oscar_fork_app address myappsfolder/
after creating the folder and __init__.py file in it
then I started to customize the app like this:
#myappsfolder/address/models.py
from django.db import models
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
from oscar.apps.address.abstract_models import AbstractAddress
class Address(AbstractAddress):
area = models.CharField(_("Area"), max_length=120,
choices=settings.AREA_CHOICES, blank=True)
from oscar.apps.address.models import *
#myappsfolder/address/forms.py
from oscar.apps.address import forms as base_forms
class UserAddressForm(base_forms.UserAddressForm):
class Meta(base_forms.UserAddressForm.Meta):
fields = ['area']
I didn't touch the admin.py , config.py and __init__.py that have been created by the command ./manage.py oscar_fork_app address myappsfolder/
also the __init__.py that I created in myappsfolder is empty, should I add something to these files ?
What should I do to customize this app ? or any other app ?
If I edited the models in oscar/apps/address/abstract_models.py it only apply in local host and the error in forms disappear , which means that django still reading the models from oscar/apps not from myappsfolder.
You cannot override AbstractAddress in that way because the changes will not propagate to other models such as UserAddress that directly subclass AbstractAddress. Instead you need to override the specific address models that you want to change. So if you want to change UserAddress then override that particular model:
from oscar.apps.address.abstract_models import AbstractUserAddress
class UserAddress(AbstractUserAddress):
area = models.CharField(_("Area"), max_length=120, choices=settings.AREA_CHOICES, blank=True)
... after which your changes to UserAddressForm should work.
If you need to override ShippingAddress as well, then you will also have to fork the shipping app and do the same thing there, because that is where the model lives.
I am using this code in my admin.py
from django.db.models import get_models, get_app
for model in get_models(get_app('myapp')):
admin.site.register(model)
But i get warning that get_models is deprecated
How can i do that in django 1.8
This should work,
from django.apps import apps
apps.get_models()
The get_models method returns a list of all installed models. You can also pass three keyword arguments include_auto_created, include_deferred and include_swapped.
If you want to get the models for a specific app, you can do something like this.
from django.apps import apps
myapp = apps.get_app_config('myapp')
myapp.models
This will return an OrderedDict instance of the models for that app.
I've got a weird problem.
I am building a Flask app with SQLAlchemy. I have a file with models, namely, models.py. And I have a User model there.
If I open my "views.py" and insert a string
import models
and then use the User model like
u=models.User.query.filter_by(name='John',password='Doe').first()
everything works fine.
But if instead of "import models" i put
from models import User
Python crashes and says:
ImportError: cannot import name User
how can this be possible?
you most likely have a circular import; your, lets say 'app' module:
# app.py
import models
...
def doSomething():
models.User....
but your models module also imports app
import app
class User:
...
since models imports app, and app imports models, python has not finished importing models at the point app tries to import models.User; the User class has not been defined (yet). Either break the cyclic import (make sure models doesn't import anything that also imports models), or you'll just have to make do with models.User instead of the shorter User in app.
Instead of
from models import User
use
from models import *
In this case, you are importing the models into views.py therefore if you need a class from models, import it from views.py and the circular import problem will be resolved.