2016-07-12 4 views
0

일반적인 작업의 기본 구현을 포함하는 '핵심'Django 제품이 있지만 그 구현을 재정의하거나 (쉽게 사용자 정의 할 수 있도록 사용자 정의 할 수 있습니다).어떻게 장고에서 함수를 재정의 할 수 있습니까?

핵심 제품에서 예를 들어, 나는 사용자가 '모든 알림'다시 전송 버튼을 클릭 할 수있는 전망이있을 수 있습니다 아마도,이 제품의 일부 배포에 다음

# in core/views.py 
... imports etc... 
from core.tasks import resend_notifications 

def handle_user_resend_request(request, user_id): 
    user = get_object_or_404(id=user_id) 

    if request.method == 'POST': 
     for follower in user.followers: 
      resend_notifications(follower.id) 

    ... etc etc ... 


# in core/tasks.py 
... imports etc... 

def resend_notifications(id): 
    send_email(User.objects.get(id=id)) 

그리고를 '

# in customer_specific/tasks.py 
... imports etc ... 

def resend_notifications(id): 
    person = User.objects.get(id=id) 
    if '@super-hack.email.com' in person.email: 
     # This is not a real email, send via the magic portal 
     send_via_magic(person) 
    else: 
     send_email(person) 
    # and send via fax for good measure 
    send_fax(person) 

가 어떻게이 customer_specific 버전을 가리 키도록 views.py 파일에 resend_notifications 기능을합니까 : 같은 resend_notifications의 요구는보고 하는가?

장고 설정에서이를 정의하고 액세스를 공유해야합니까? 작업이 실제로 셀러리 작업 일 경우 어떻게해야합니까?

NB : 실제로 내가 가지고있는 작업은 셀러 리 작업으로 정의됩니다. (나는이 질문을 좀 더 일반적이라고 생각하기 때문에이 세부 사항을 제거했습니다). 전역 객체를 변경하는 사용자 정의 데코레이터 태그를 사용해 보았습니다. 그러나 그 방법은 여러 가지 이유로 명확히 구분됩니다.

추신 : 나는 이것이 의존성 주입 질문이라고 생각하지만, 장고에서는 공통점이 없다.

답변

0

이것은 결국 배치 설정에 의해 재구성 될 수있는 장고 설정 객체를 통해 해결되었습니다. 이 기술에 크게 영향을 받았습니다 : settings.py from django-rest-framework.

예를 들어, 내가 설정을 내 프로젝트에서이 같은 파일이 있습니다 사용

  • :

    프로젝트 _/settings.py

    """ 
    Settings for <YOUR PROJECT> are all namespaced in the YOUR_PROJECT config option. 
    For example your project's config file (usually called `settings.py` or 'production.py') might look like this: 
    
    YOUR_PROJECT = { 
        'PROCESS_TASK': (
         'your_project.tasks.process_task', 
        ) 
    } 
    
    This module provides the `yourproject_settings` object, that is used 
    to access settings, checking for user settings first, then falling 
    back to the defaults. 
    """ 
    # This file was effectively borrow from https://github.com/tomchristie/django-rest-framework/blob/8385ae42c06b8e68a714cb67b7f0766afe316883/rest_framework/settings.py 
    
    from __future__ import unicode_literals 
    from django.conf import settings 
    from django.utils.module_loading import import_string 
    
    
    DEFAULTS = { 
        'RESEND_NOTIFICATIONS_TASK': 'core.tasks.resend_notifications', 
    } 
    
    
    # List of settings that may be in string import notation. 
    IMPORT_STRINGS = (
        'RESEND_NOTIFICATIONS_TASK', 
    ) 
    
    
    MANDATORY_SETTINGS = (
        'RESEND_NOTIFICATIONS_TASK', 
    ) 
    
    
    def perform_import(val, setting_name): 
        """ 
        If the given setting is a string import notation, 
        then perform the necessary import or imports. 
        """ 
        if val is None: 
         return None 
        if callable(val): 
         return val 
        if isinstance(val, (list, tuple)): 
         return [perform_import(item, setting_name) for item in val] 
    
        try: 
         return import_string(val) 
        except (ImportError, AttributeError) as e: 
         msg = "Could not import '%s' for setting '%s'. %s: %s." % (val, setting_name, e.__class__.__name__, e) 
         raise ImportError(msg) 
    
    
    class YourProjectSettings(object): 
        """ 
        A settings object, that allows settings to be accessed as properties. 
        For example: 
    
         from your_project.settings import yourproject_settings as the_settings 
         print(the_settings.RESEND_NOTIFICATIONS_TASK) 
    
        Any setting with string import paths will be automatically resolved 
        and return the class, rather than the string literal. 
        """ 
        namespace = 'YOUR_PROJECT' 
    
        def __init__(self, mandatory=None, defaults=None, import_strings=None): 
         self.mandatory = mandatory or MANDATORY_SETTINGS 
         self.defaults = defaults or DEFAULTS 
         self.import_strings = import_strings or IMPORT_STRINGS 
    
         self.__check_settings() 
    
        @property 
        def user_settings(self): 
         if not hasattr(self, '_user_settings'): 
          self._user_settings = getattr(settings, self.__class__.namespace, {}) 
         return self._user_settings 
    
        def __getattr__(self, attr): 
         if attr not in self.defaults and attr not in self.mandatory: 
          raise AttributeError("Invalid Pyrite setting: '%s'" % attr) 
    
         try: 
          # Check if present in user settings 
          val = self.user_settings[attr] 
         except KeyError: 
          # Fall back to defaults 
          val = self.defaults[attr] 
    
         # Coerce import strings into classes 
         if attr in self.import_strings: 
          val = perform_import(val, attr) 
    
         # Cache the result 
         setattr(self, attr, val) 
         return val 
    
        def __check_settings(self): 
         for setting in self.mandatory: 
          if setting not in self.user_settings: 
           raise RuntimeError(
            'The "{}" setting is required as part of the configuration for "{}", but has not been supplied.'.format(
            setting, self.__class__.namespace)) 
    
    
    yourproject_settings = YourProjectSettings(MANDATORY_SETTINGS, DEFAULTS, IMPORT_STRINGS) 
    

    이 중 하나에 나를 수 있습니다 기본값 (즉, 'core.tasks.resend_notications ');

    ... other django settings like DB/DEBUG/Static files etc 
    
    YOUR_PROJECT = { 
        'RESEND_NOTIFICATIONS_TASK': 'customer_specific.tasks.resend_notifications', 
    } 
    
    ... etc. ... 
    

그런 다음 내보기 기능에, 나는 설정을 통해 올바른 기능에 액세스

site_config/special.py : 또는

  • 는 내 설정 파일에 바인딩을 다시 정의하려면 :

    코어/views.py

    ... imports etc... 
    from yourproject.settings import yourproject_settings as my_settings 
    
    def handle_user_resend_request(request, user_id): 
        user = get_object_or_404(id=user_id) 
    
        if request.method == 'POST': 
         for follower in user.followers: 
          my_settings.RESEND_NOTIFICATIONS_TASK(follower.id) 
    
        ... etc etc ... 
    
  • 0

    이와 비슷한 상황에서 나는 이와 같은 해결책을 찾아 냈다. 나는 이것을 애플리케이션의 Organization 모델에 넣었다. (GitHub 조직의 equiv).

    @property 
    def forms(self): 
        if self.ldap: 
         from portal.ldap import forms 
        else: 
         from portal.users import forms 
    
        return forms 
    

    나는 본질적으로 조직이 인증 된 사용자가 LDAP가 구성한에 속하는 경우 다른 양식 클래스를 사용하고 싶어 - 필요에 따라서 초대 생성/사용자 양식이 다를 수. 난 당신이, 당신의 시나리오에서 비슷한 작업을 수행하는 버전을 결정하는 프록시 추상화에 기능 (들)을 포장 할 수 있습니다 상상

    def get_form_class(self): 
        return self.request.user.organization.forms.CreateUserForm 
    

    :

    나는 다음과 같이 해당 뷰에 get_form_class을 덮어 사용 - env ​​변수, 설정 또는 요청을 기반으로합니다.

    +0

    나는 이것이 좋은 선택임을 분명히 볼 수 있습니다. 그러나 제 경우에는 '코어'모듈과 '사용자 정의'모듈 모두에서이 불가 지론적인 액세스를 가질 수 있어야합니다. 나는 이것이 커스텀 모듈에 대한 명백한 지식을 요구하는 코어없이 '코어'에 포함될 수있는 방법을 생각할 수 없다. ie'def forms() : ...'함수를'core/tasks.py'에 넣어야하지만'customer_specific'에서 아무것도 가져올 수 없습니다. – Doddie

    +0

    흠, 몇 번 더 대답을 읽었습니다. 나는 당신이 옳을 수도 있다고 생각하지만'def forms() : ..'스타일 함수는 어떤 종류의 설정/app config를 사용해야합니다. – Doddie

    +0

    당신은 본질적으로 파이썬 모듈 수준에서 추상화 패턴을 사용하려고합니다. 그리고 제가 이것을하기 위해 내놓은 가장 실용적인 방법은 제가 일반적으로 상호 작용하는 모듈을 작성하는 것입니다.이 모듈은 다른 개념의 모듈을 (적어도 개념적으로)) 호환 인터페이스. – Steve

    관련 문제