2012-10-06 2 views
1

formsModelForms에 관한 문서를 거의 하루 종일 보냈습니다. 나는 기본적인 것들을 사용할 수 있었지만 모델 필드를 모델이 아닌 필드와 매핑하는 것에 대한 설명서에서 힌트를 찾지 못해서 현재 정말로 문제가 있습니다. 즉 I의 의미는 다음과 같습니다ModelForm의 비 모델 필드로 모델 필드 매핑하기

class Process(models.Model): 
    key   = models.CharField(max_length=32, default="") 
    name  = models.CharField(max_length=30) 
    path  = models.CharField(max_length=215) 
    author  = models.CharField(max_length=100) 
    canparse = models.NullBooleanField(default=False) 
    last_exec = models.DateTimeField(null = True) 
    last_stop = models.DateTimeField(null = True) 
    last_change = models.DateTimeField(null = True, auto_now=True) 

는 사용자가 수정하려고하는 유일한 필드 nameauthor 있습니다

나는이 모델이있다. path은 내 프로세스의 구성 파일의 절대 실제 경로입니다. 디렉토리가 고정되어 있고 사용자가 디렉토리가 /home/measure/conf 또는 /var/whatever인지 여부는 신경 쓰지 않습니다. 파일 이름 만 신경 써야합니다. 그래서 ModelFormfilename 필드가 필요합니다. 같은

내 양식을 보이는 :

이제
class ProcessForm(MonitorForm): 
    filename = forms.CharField(max_length=250) 
    class Meta: 
     model = Process 
     fields = ('name', 'filename', 'author') 

, 내가 원하는 것은 filenameProcess.path과 전체가 아닌 경로 저장 파일 이름을 포함, 즉 I의 의미는 다음과 같습니다

>>> from monitor.forms import ProcessForm 
>>> from remusdb.models import Process 
>>> 
>>> p = Process(name="test1", path="/tmp/config/a.cnf", author="pablo") 
>>> f = ProcessForm(instance=p) 
>>> print f["filename"].value() 
---> here I want to get "a.cnf" 

문제는 내가 로 전화하면 을 filename 필드에 쓰는 방법을 모른다는 것입니다. 나는 clean 함수에서 그것을 수행하는 것에 대해 생각했지만 이것이 좋은 곳인지 전혀 확신 할 수 없습니다. 필드가 다소 읽기 전용이기 때문에이 시점에서 너무 늦을 것이라고 가정합니다. 일단 initilaized되면 ​​값을 변경할 수 없습니다. 어떻게해야합니까? 사용자 정의 필드를 만들고 __init__을 재정의해야합니까?

나는이 아이디어를 form field default cleaning에서 읽었으며 첫 번째 테스트를 원했습니다. 나는 init을 우선 쓰지 않으려 고하고 나는 설명서 에서처럼 to_python 메쏘드로 먼저 놀았다고 생각했다. 나는이 방법이 전화를받을 때/위치를 확인하기 위해 지문을 추가

class RemusFilenameField(forms.CharField): 
    def to_python(self, value): 
     print "to_python's value is %s" % value 
     return value.upper() 

    def clean(self, value): 
     print "clean's value is %s" % value 
     return value.upper() 

filename = RemusFilenameField(max_length=250) 

ProcessFormfilename 라인을 변경 : 그래서 클래스 RemusFilenameField를 만들었습니다. 그러나이 방법은 전혀 호출되지 않습니다. 형태가 한정되어 있지 않기 때문에 나는 의심한다. 그래서 대신에 이런 짓을 :

>>> p = {"name": "test1", "filename": "a.cnf", "author": "pablo"} 
>>> f = ProcessForm(p) 
>>> f.is_valid() 
clean's value is a.cnf 
True 
>>> print f["filename"].value() 
a.cnf 

to_python 방법은라고도 점점되지 않고 나는 clean 다른 무언가를 반환하기 때문에 A.CNF를 볼 것으로 예상.

이 문제를 해결하는 방법과 이것이 전혀 좋은 아이디어인지 전혀 알 수 없습니다. 다음 번 문제는 f.save()이 실행될 때 pathfilename에서 생성되고 instance에 저장되어야합니다. 나는 이것을 clean 방법으로 할 것인가 아니면 더 좋은 선택이 될 것인가?

편집가 :

from django.forms.models import model_to_dict 
import os 

class ProcessForm(MonitorForm): 
    filename = RemusFilenameField(max_length=250) 
    def __init__(self, *args, **kwargs): 
     super(ProcessForm, self).__init__(*args, **kwargs) 
     try: 
      proc = kwargs["instance"] 
      filename = os.path.basename(proc.path) 
      self.initial.update({'filename': unicode(filename)}) 
     except: 
      pass 
    class Meta: 
     model = Process 
     fields = ('name', 'filename', 'author') 

그것은이 작품이 지금 :) 알고 : 나는 양식의 창조를위한 해결책을 가지고 생각 (나는 python2.6/site-packages/django/forms/models.pymodel_to_dict 사용을 식별하기 위해 전체 소스 코드를 읽을 수 있었다 save() 메서드를 수정하는 방법을 찾아야합니다.

답변

2

save() 메서드는 폼에 추가 저장 논리를 넣을 적절한 장소입니다. 코드가 올바른 양식의 필드에 to_python() 메소드를 호출 측면에서

def save(self, commit=True): 
    proc = super(ProcessForm, self).save(commit=False) 
    filename = cleaned_data['filename'] 
    # additional logic to alter filename 
    proc.path = filename 
    if commit: 
     proc.save() 
    return proc 
+0

감사합니다. 이는 의미가 있으며 "로드"부분보다 더 쉽습니다. 'django.forms.models'의 소스 코드를 읽은 후에는 의미가 있습니다. – Pablo

1

,하지만 당신은 cleaned_data dictionary에서 값을 얻을 수 있습니다

>>> p = {"name": "test1", "filename": "a.cnf", "author": "pablo"} 
>>> f = ProcessForm(p) 
>>> f.is_valid() 
clean's value is a.cnf 
True 
>>> f.cleaned_data['filename'] 
'A.CNF' 

을 할 수있는 저장 당신이 모델에 대한 몇 가지 논리가 필요한 경우 모델에서 save()을 무시하십시오. 또한 django docs에 설명되어 있습니다.

drewman이 설명한대로 save()method in your ModelForm을 무시해야합니다. 코드의 다른 위치에있는 모델 인스턴스의 save() 메서드를 호출 할 때 코드에 영향을 미치지 않습니다.

+0

예, 고마워요. 나는'cleaned_data'에 대해 전혀 생각하지 않았습니다. 문제는 여전히 'A.CNF'가 아니라'a.cnf'가 표시된다는 것입니다. 하지만 처음에는 제대로 작동하는 솔루션을 발견했지만, 그다지 만족스럽지 않습니다. 'ModelForm'의 내부 부분이 바뀌면 내 코드를 다시 변경해야합니다. – Pablo