2013-02-03 2 views
2

표준 ModelChoiceField 위젯 대신 사용자 정의 django 위젯이 있습니다.django widget 쿼리가 업데이트되지 않습니다.

class SelectModelWidget(forms.TextInput): 
    """ 
    @Usage: field = ModelChoiceField(queryset=Model.objects.all(), 
            widget=SelectModelWidget(attrs={})) 
    """ 

    def __init__(self, attrs=None, title=None, 
       template="widgets/select_widget.html"): 
     super(SelectModelWidget, self).__init__(attrs) 
     self.template = template 
     self.title = title 

    def render(self, name, value, attrs=None): 
     if value is None: value = '' 

     # TODO: the queryset does not update 
     # Set the title for the selection page, use model name as default 
     model_queryset = self.choices.queryset 
     if model_queryset is not None and self.title is None: 
      self.title = model_queryset.model._meta.verbose_name.title() 

     # Get the currently selected instance if it exists 
     try: 
      instance = model_queryset.get(pk=value) 
      text = instance 
     except (ValueError, model_queryset.model.DoesNotExist): 
      text = '' 

     form_id = attrs.pop("id") 
     widget_template = loader.get_template(self.template) 
     context = Context({ 
          "attrs": attrs, 
          "id": form_id, 
          "name": name, 
          "value": value, 
          "text": text, 
          "title": self.title, 
          "queryset": model_queryset, 
          }) 

     return widget_template.render(context) 

문제는이 지역 주위에 나타납니다

model_queryset = self.choices.queryset 
    if model_queryset is not None and self.title is None: 
     self.title = model_queryset.model._meta.verbose_name.title() 

self.choices.queryset 라인은 ModelChoiceField에 전달 된 검색어 세트를 취득해야하고, 내가하는 방법에 대한 이해 부족 생각 처음으로 페이지를로드 할 때 모델 쿼리 세트가 잘 채우기 때문에 초기화됩니다. 그러나 해당 모델의 새 인스턴스를 추가하고 페이지를 다시로드하면 쿼리 세트가 새 인스턴스를 포함하도록 업데이트되지 않습니다. 새 인스턴스를 목록에 표시하려면 서버를 다시 시작해야합니다. 쿼리 세트가 한 번만 초기화되고 결코 업데이트되지 않는 이유는 무엇입니까?

편집 : 폼에서 위젯을 제거했을 때 위젯 코드를 사용하면 기본 위젯을 사용할 수 있으므로 위젯 코드라고 확신합니다.이 위젯은 완벽하게 작동하며 예상대로 작동합니다. model_queryset 변수가 새로운 쿼리 세트로 결코 업데이트되지 않는 이유는 없습니다.

내 프로젝트에서이 위젯 관련 양식 코드는 말 그대로 그냥 :

address = forms.ModelChoiceField(queryset=models.Address.objects.all(), 
          widget=widgets.SelectModelWidget()) 
+0

model_queryset이 ​​None이 아니고 self.title이 None :'이 줄에서'None'을'False'로 바꾸어보십시오. 빈 값은 '거짓'이 아니라 '없음'입니다. –

+0

나는 그것이 사실이라고 생각하지 않는다. 그리고 그 부분에 상관없이 쿼리 세트 자체에 아무런 영향을주지 않으며 왜 변경되지 않는지 – PT114

+0

위젯/필드/폼 인스턴스가 모듈 변수에 저장되고 한 번만 초기화 된 것처럼 보입니다. 양식 정의 및 인스턴스 작성 코드를 공유하십시오. 또 다른 설명은 django-cache-machine이나 jonnycache와 같은 데이터베이스 캐시 미들웨어를 사용하는 효과 일 수 있지만,이 경우에는이 aspect를 공유했을 것입니다. – Marat

답변

2
나는 내가 검색어 세트 자체에 대한 액세스를 필요로하지 않았다는 것을 결정했다 결국

, 그래서보다는 self.choices.queryset , 나는 단지 self.choices (그리고 modelchoicefields에 의해 기본적으로 넣어지는 빈 선택을 제거)를 사용하고있다.

내 직접적인 문제가 해결되었지만 self.choices.queryset이 ​​self.choices와 다른 동작을하는 이유를 알고 싶습니다. 버그인지 이해할 수없는 기능인지는 불분명합니다.

+0

I self.choices.queryset은 게으른 객체이고 self.choices는 인스턴스화 될 때마다 확인되는 속성이라는 사실과 관련이 있다고 생각합니다. 이 이전 지원 티켓에 설명 된 내부 '__deepcopy__' 메소드로 발생하는 캐싱이 있습니다. https://code.djangoproject.com/ticket/18272 - 문제의 원인 일 수 있습니까? – souldeux

3

self.choices.queryset.all()이 작동해야합니다.

1

문제는 렌더링 된 템플릿 또는 쿼리 집합의 캐싱 어딘가에 있다고 생각합니다. 하지만 그 대신 django의 템플릿 엔진을 사용하여 모든 필드를 사용자 정의 할 수있는 훌륭한 패키지 인 django-crispy-forms을 사용하는 것이 좋습니다. 장고에서 렌더링 위젯을 사용자 정의하려는 수많은 시도 후, 그게 내가 찾을 수있는 가장 좋은 해결책이었고, 너무 간단한 것으로 밝혀졌다.

관련 문제