Custom management command, oauth.py, needs a model from another module. When I include "from appname.authentication.models import Contact" I get "AttributeError: 'module' object has no attribute 'models'." - Im stuck on django 1.6 until I able to build an test suite to help with the upgrade. How do I correctly import Contact?
Other notable SO answers:
Each directory other than /app has an __init__.py
. /app is in sys.path/ django directory, /app:
util
-management
--commands
---oauth.py
appname
-authentication
--models.py
extouth.py
extoauth.py is standalone script with the same import and works, but only in manage.py shell. The custom management command will be better.
oauth.py:
import sys
from optparse import make_option
from provider.oauth2.models import Client
from appname.authentication.models import Contact
from django.core.management.base import BaseCommand
class Command(BaseCommand):
help = 'Creates OAUTH user and gets access token.'
option_list = BaseCommand.option_list + (
make_option('--create-client',
dest='create_client',
help='''Returns tuple of <id,secret>...'''),
make_option('--get-access-token',
dest='get_access_token',
help='''Returns time limited access token...'''),
)
def handle(self, *args, **options):
if options['create_client']:
return self.create_client(options['create_client'])
elif options['get_access_token']:
self.get_access_token()
def create_client(self, user):
return user
def get_access_token(self):
pass
Console out:
Traceback (most recent call last):
File "manage.py", line 10, in <module>
execute_from_command_line(sys.argv)
File "/usr/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 399, in execute_from_command_line
utility.execute()
File "/usr/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 392, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/usr/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 272, in fetch_command
klass = load_command_class(app_name, subcommand)
File "/usr/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 75, in load_command_class
module = import_module('%s.management.commands.%s' % (app_name, name))
File "/usr/local/lib/python2.7/site-packages/django/utils/importlib.py", line 40, in import_module
__import__(name)
File "/app/waapiutil/management/commands/oauth.py", line 4, in <module>
from wowza.authentication.models import Contact
File "/app/wowza/authentication/models.py", line 80, in <module>
class
SalesforceModel(with_metaclass(salesforce.models.SalesforceModelBase, models.Model)):
AttributeError: 'module' object has no attribute 'models'
hypo - settings is not getting imported So my settings must be getting set just as they do with the manage.py shell usage because if I include at the top of my file: from django.conf import settings settings.configure()
I get:
Traceback (most recent call last):
File "manage.py", line 10, in <module>
execute_from_command_line(sys.argv)
File "/usr/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 399, in execute_from_command_line
utility.execute()
File "/usr/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 392, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/usr/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 272, in fetch_command
klass = load_command_class(app_name, subcommand)
File "/usr/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 75, in load_command_class
module = import_module('%s.management.commands.%s' % (app_name, name))
File "/usr/local/lib/python2.7/site-packages/django/utils/importlib.py", line 40, in import_module
__import__(name)
File "/app/waapiutil/management/commands/oauth.py", line 2, in <module>
settings.configure()
File "/usr/local/lib/python2.7/site-packages/django/conf/__init__.py", line 89, in configure
raise RuntimeError('Settings already configured.')
RuntimeError: Settings already configured.
hypo - deeper syntax error (that should have broken production anyway) searching for occurrences of models.model in my app files yields four results, each has the correct capitalization of models.Model.
hypo - Contact is already imported When I comment out the import and run the command i get:
Traceback (most recent call last):
File "manage.py", line 10, in <module>
execute_from_command_line(sys.argv)
File "/usr/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 399, in execute_from_command_line
utility.execute()
File "/usr/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 392, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/usr/local/lib/python2.7/site-packages/django/core/management/base.py", line 242, in run_from_argv
self.execute(*args, **options.__dict__)
File "/usr/local/lib/python2.7/site-packages/django/core/management/base.py", line 285, in execute
output = self.handle(*args, **options)
File "/app/waapiutil/management/commands/oauth.py", line 23, in handle
return self.create_client(options['create_client'])
File "/app/waapiutil/management/commands/oauth.py", line 32, in create_client
c = Client(user=Contact.objects.get_by_email(e), name=n,
NameError: global name 'Contact' is not defined
Snippets from authentication/models.py for hynekcer's comment
# Core Django imports
from django.db import models
from django.core.validators import MinLengthValidator
from django.utils.six import with_metaclass
# Third-party imports
import pycountry
from rest_framework.compat import oauth2_provider
import salesforce
from salesforce import fields
from salesforce.backend import manager
...
class SalesforceManager(manager.SalesforceManager):
"""
Override the default Salesforce manager so we can get some proper REST framework exceptions
"""
def get(self, *args, **kwargs):
try:
result = self.get_queryset().get(*args, **kwargs)
except self.model.MultipleObjectsReturned:
raise MultipleUniqueRecords()
except Exception as e:
logger.warning("SalesForce exception %s", str(e))
raise NoRecord()
return result
class SalesforceModel(with_metaclass(salesforce.models.SalesforceModelBase, models.Model)):
"""
Abstract model class for Salesforce objects.
"""
_base_manager = objects = SalesforceManager()
_salesforce_object = True
class Meta:
managed = False
abstract = True
Id = fields.SalesforceAutoField(primary_key=True)
def clean_fields(self, *args, **kwargs):
# Override the default clean_fields method so we can catch validation exceptions
try:
super(SalesforceModel, self).clean_fields(*args, **kwargs)
except Exception as validation_exception:
detail = ''
for field, message in validation_exception.error_dict.items():
detail += field + ': ' + message[0].messages[0]
raise ValidationError(detail)
def save(self, *args, **kwargs):
# Override the default save method so we can remove fields that Salesforce manages
if self._meta.model_name in ['contact', 'account', 'license', 'sslcertificate']:
if not self.Id:
for field in self._meta.fields:
if field.attname == 'created_date' or field.attname == 'certificate_id':
self._meta.fields.remove(field)
else:
update_fields = self._meta.get_all_field_names()
remove_list = []
if self._meta.model_name == 'contact':
remove_list = ['created_date', 'accesstoken', 'refreshtoken', 'oauth2_client', 'grant', 'Id', 'entitlement_plan']
elif self._meta.model_name == 'account':
remove_list = ['created_date', 'account', 'Id']
elif self._meta.model_name == 'license':
remove_list = ['created_date', 'Id']
elif self._meta.model_name == 'sslcertificate':
remove_list = ['certificate_id', 'created_date', 'Id']
for remove_field in remove_list:
if remove_field in update_fields:
update_fields.remove(remove_field)
kwargs['update_fields'] = update_fields
# Retry five times if there's a SalesforceError
delay = 1
for retry in range(5):
try:
super(SalesforceModel, self).save(*args, **kwargs)
break
except Exception as e:
logger.error("Saving {0} resulted in an error {1}, retry {2}".format(str(self),str(e),retry))
if retry < 4 and "SERVER_UNAVAILABLE" in str(e):
time.sleep(delay)
delay *= 2
else: