2

自定义管理命令 oauth.py 需要来自另一个模块的模型。当我包含“from appname.authentication.models import Contact”时,我得到“AttributeError:'module'对象没有属性'models'。” - 我坚持使用 django 1.6,直到我能够构建一个测试套件来帮助升级。 如何正确导入联系人?

其他值得注意的SO答案:

/app 以外的每个目录都有一个__init__.py. /app 在 sys.path/ django 目录下,/app:

util
-management
--commands
---oauth.py
appname
-authentication
--models.py
extouth.py

extoauth.py 是具有相同导入和工作的独立脚本,但仅在 manage.py shell 中。自定义管理命令会更好。

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

控制台输出:

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 - 设置没有被导入 所以我的设置必须像使用 manage.py shell 一样进行设置,因为如果我在文件顶部包含: from django.conf import settings settings.configure()

我得到:

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 - 更深层次的语法错误(无论如何都应该破坏生产) 在我的应用程序文件中搜索出现的 models.model 会产生四个结果,每个结果都有正确的 models.Model 大写。

hypo - 联系人已经导入 当我注释掉导入并运行我得到的命令时:

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

来自 authentication/models.py 的片段,用于 hynekcer 的评论

# 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:
4

1 回答 1

0

(这是一个需要很多地方的评论,还不是答案。)

当我在您的应用程序代码中看到来自我的数据库后端的一行时,我认为我的眼睛在欺骗,也许在同一模块中也有一个具体的模型。我看到您粘贴的代码基于较旧的 django-salesforce 0.5.x 代码。好的,希望你也使用包 0.5.x。它可能无法与当前的 django-salesforce 0.6 一起使用,否则没人会期待它

最安全的方式是使用公共 API。更脆弱的风格是也使用未记录的功能。最脆弱的是从其他包的核心复制粘贴代码并忘记您开始使用新版本。做这样的事情,必须有足够的理由和足够的时间。(我为每个 Django 版本做了六次,因为 django-salesforce 后端对我来说已经足够有趣了,但我不推荐给你。)

你可以简单地写:

class MySalesforceModel(salesforce.models.SalesforceModel):
    def ...  # your custom method

    class Meta:
        managed = False
        abstract = True

优点是即使使用下一版本的 Django 和 django-salesforce,这也将使用正确的当前 SalesforceModel。

如果您确实需要自定义后端,请遵守将后端和应用程序代码合理分离到不同模块的要求,以便在不导入任何具体模型的情况下导入后端。否则你很容易得到丑陋的依赖。非空的“ init .py”也可能导致愚蠢的依赖

如果您拥有完整的源代码,那么您不需要对这些简单的事情进行假设(“hypo”)。您可以简单地记录(打印)该信息,例如放置import sys; print("settings imported", "my_project.settings" in sys.modules)或验证设置是否正确配置 - 在有问题的地方之前暂时放置一行:from django.conf import settings; print(settings.INSTALLED_APPS) # any valid name

在寻求帮助之前,您应该检查语法错误。对于子目录树的任何特定 Python 版本,它可以轻松完成,例如通过python2.7 -m compileall $(pwd)

使用一般处理非常疯狂,except Exception:尤其是在调试时。想象一下 try...except 之间的代码会引发 ImportError 并且你会吞下它。

通过重构代码来解决依赖关系比以后维护脆弱的代码更容易。想象一下,您在一个函数中导​​入,并且仅当模块仅从 Apache 中的线程导入时,您才会从您的朋友那里收到一条奇怪的 ImportError 消息,但如果您从主线程导入它,它就会成功。显式导入是有利的。

于 2015-07-22T19:03:21.863 回答