2016-12-27 1 views
0

짧은 버전 : 장고가 양식을 렌더링 할 때마다 사용해야하는 기본 CSS 클래스 집합을 정의 할 수 있습니까?Django의 모든 내장 양식 위젯에 기본 CSS 클래스를 설정하는 방법

긴 버전 : 컨텍스트는 다음과 같습니다. 모든 양식 (http://www.w3schools.com/w3css/default.asp)에 대해 w3.css 프레임 워크에 정의 된 CSS 클래스를 사용하고 싶습니다. 장고에서는 폼 클래스 정의 나 폼 렌더링에서이 작업을 수행 할 수 있음을 알았지 만 두 경우 모두 모든 양식 필드를 명시 적으로 선언해야합니다. 즉, ModelForms의 자동 폼 생성의 모든 이점을 잃어 버렸습니다. 대신 다음과 같은 내용을 원합니다.

  1. 양식 필드/위젯과 CSS 클래스 (예 : 설정 파일) 간의 기본 매핑을 설정 파일 등에서 정의하십시오. 기본적으로 'textinput': 'my_default_css_class_for_text_inputs'
  2. , 모든 형태의 자동 생성 및 렌더링, 아니하거나 기존 형태의 클래스 특정 형태에 대한
  3. 을 최소한의 수정 (1) 사용에 정의 된 기본 CSS 클래스는, 나는 기본값을 오버로드 할 수 있습니다 다른 값을 가지고

내가 이해하는 한, 그런 행동은 장고에서는 불가능합니다. 파삭 파삭 한 형태의 포장은 그 방향으로가는 것처럼 보이지만, 그 이상의 것을 할 것 같고, 나는 모든 여분의 복잡성을 원한다는 것을 확신하지 못한다. (나는 여전히 여기 주위의 초보자이다.) 대안은 자바 스크립트를 사용하여 클라이언트 측에 클래스를 추가하는 것입니다. 그것은 나에게 나쁜 추악한 행동처럼 보입니다.

누구든지이 문제에 대한 나의 이해를 확인하고 우아한 해결책을 제시 할 수 있습니까?

감사합니다.

조나단

답변

0

는 내 질문에 대한 답을 찾기 위해 관리했습니다 내가 후대를 위해 여기를 게시하도록하겠습니다. 레이블 클래스의 경우 나는 herehere (사용자의 답변 : 2732686)이라는 영감을 받았습니다. 첫 번째 링크는 런타임에 BoundField 클래스의 label_tag 메서드를 재정의 할 것을 제안합니다. 그것은 제 2의 링크에서 제안 된 것보다 덜 장황한 솔루션이지만, 프로젝트 전체에 걸친 해킹을 들었을 때 권장하지는 않습니다. 여기서는 레이블의 두 번째 링크에서 제안 된대로 장고의 하위 클래스 매니아를 따릅니다. 프로젝트에서

settings.py, 추가

# Default css classes for widgets and labels 
DEFAULT_CSS = { 
      'error': 'w3-panel w3-red',  # displayed in the label 
      'errorlist': 'w3-padding-8 w3-red', # encloses the error list 
      'required': 'w3-text-indigo',  # used in the label and label + input enclosing box. NB: w3-validate only works if the input precedes the label! 
      'label': 'w3-label', 
      'Textarea': 'w3-input w3-border', 
      'TextInput': 'w3-input w3-border', 
      'Select': 'w3-select w3-border', 
      } 

NB를 : 떨어져 4 첫번째 ,에서 장고의 위젯 이름과 일치해야합니다. 에서

당신의 forms.py (또는 다른 곳에), 추가 : 당신은 단순히 DefaultCssModelFormDefaultCssForm 대신 ModelFormForm를 서브 클래 싱,

그런 다음 프로젝트 이름으로 <MY_PROJECT> 대체 :

from django.forms import ModelForm, inlineformset_factory, Form, BoundField 
from django.forms.utils import ErrorList 
from django.utils.html import format_html, force_text 
from django.conf import settings 

class CustErrorList(ErrorList): 
    # custom error list format to use defcss 
    def __str__(self): 
     return self.as_div() 
    def as_div(self): 
     if not self: 
      return '' 
     return format_html('<div class="{}">{}</div>', 
          settings.DEFAULT_CSS['errorlist'], 
          ' '.join([ force_text(e) for e in self ]) 
          ) 

class CustBoundField(BoundField): 
    # overload label_tag to include default css classes for labels 
    def label_tag(self, contents=None, attrs=None, label_suffix=None): 
     newcssclass = settings.DEFAULT_CSS['label'] 
     if attrs is None: 
      attrs = {} 
     elif 'class' in attrs: 
      newcssclass = ' '.join([ attrs['class'], newcssclass ]) # NB: order has no impact here (but it does in the style sheet) 
     attrs.update({ 'class': newcssclass }) 
     # return the output of the original method with the modified attrs 
     return super(CustBoundField, self).label_tag(contents, attrs, label_suffix) 

def custinit(self, subclass, *args, **kwargs): 
    # overload Form or ModelForm inits, to use default CSS classes for widgets 
    super(subclass, self).__init__(*args, **kwargs) 
    self.error_class = CustErrorList # change the default error class 

    # Loop on fields and add css classes 
    # Warning: must loop on fields, not on boundfields, otherwise inline_formsets break 
    for field in self.fields.values():    
     thiswidget = field.widget 
     if thiswidget .is_hidden: 
      continue 
     newcssclass = settings.DEFAULT_CSS[ thiswidget.__class__.__name__ ] 
     thisattrs = thiswidget.attrs 
     if 'class' in thisattrs: 
      newcssclass = ' '.join([ thisattrs['class'], newcssclass ]) # NB: order has no impact here (but it does in the style sheet) 
     thisattrs.update({ 'class': newcssclass }) 

def custgetitem(self, name): 
    # Overload of Form getitem to use the custom BoundField with 
    # css-classed labels. Everything here is just a copy of django's version, 
    # apart from the call to CustBoundField 
    try: 
     field = self.fields[name] 
    except KeyError: 
     raise KeyError(
      "Key '%s' not found in '%s'. Choices are: %s." % (
       name, 
       self.__class__.__name__, 
       ', '.join(sorted(f for f in self.fields)), 
      ) 
     ) 
    if name not in self._bound_fields_cache: 
     self._bound_fields_cache[name] = CustBoundField(self, field, name) 
     # In the original version, field.get_bound_field is called, but 
     # this method only calls BoundField. It is much easier to 
     # subclass BoundField and call it directly here 
    return self._bound_fields_cache[name]   

class DefaultCssModelForm(ModelForm): 
    # Defines the new reference ModelForm, with default css classes 
    error_css_class = settings.DEFAULT_CSS['error'] 
    required_css_class = settings.DEFAULT_CSS['required'] 

    def __init__(self, *args, **kwargs): 
     custinit(self, DefaultCssModelForm, *args, **kwargs) 

    def __getitem__(self, name): 
     return custgetitem(self, name) 

class DefaultCssForm(Form): 
    # Defines the new reference Form, with default css classes 

    error_css_class = settings.DEFAULT_CSS['error'] 
    required_css_class = settings.DEFAULT_CSS['required'] 

    def __init__(self, *args, **kwargs): 
     custinit(self, DefaultCssForm, *args, **kwargs) 

    def __getitem__(self, name): 
     return custgetitem(self, name) 

NB를 양식을 정의 할 때. formsets의 경우이 클래스를 기본 클래스로 사용하십시오.설명 :

class MyForm(DefaultCssModelForm): 
    class Meta: 
     model = MyModel 
     fields = '__all__' 

MyFormSet = inlineformset_factory(..., ..., form=DefaultCssModelForm, ...)    
관련 문제