Django: django 동적 정의 폼 (form) 을 어떻게 사용 하 는 지

제1 절 데이터 구조
최근 의 프로젝트 개발 은 이러한 데이터 구 조 를 사용 했다. 주로 설 비 를 관리 하 러 왔 다.
다음은 제 가 간단 한 구 조 를 열거 하 겠 습 니 다. 더 이상 필요 하지 않 습 니 다. 나머지 는 불필요 하거나 금상첨화 라 고 할 수 있 습 니 다. 설비 분류 (설비 의 큰 분류 에 해당 하 는) 의 데이터 구조 입 니 다.
class Category(models.Model):
    name         = models.CharField(max_length=40)

    구체 적 인 장치 의 데이터 구조:  
class Equipment(models.Model):
    name        = models.CharField(max_length=100)
    category    = models.ForeignKey(Category, related_name="cg_equip_list")

장치 매개 변수의 데이터 구조:
class Characteristic(models.Model):
    category  = models.ForeignKey(Category, related_name="eq_characteristics")
    name      = models.CharField(max_length=40)

 
장치 매개 변수의 값 데이터 구조:
class CharacteristicValue(models.Model):
    equipment       = models.ForeignKey(Equipment, related_name="eq_characteristic_values")
    characteristic  = models.ForeignKey(Characteristic, related_name="eq_key_values")
    value           = models.CharField(max_length=100)

 
많은 사람들 이 장치 의 매개 변수 값 을 장치 의 데이터 구조 에 직접 정의 하지 않 느 냐 고 물 을 것 이다.제 대답 은 이렇게 하면 더 많은 장 치 를 스스로 정의 할 수 있 습 니 다. 모든 장치 의 매개 변 수 는 다 릅 니 다. 예 를 들 어 컴퓨터 의 매개 변 수 는 기본적으로 CPU 주파수, 메모리 크기, 하 드 디스크 크기, 디 스 플레이 유형, 디 스 플레이 크기 등 입 니 다.
프린터 의 인 자 는 다음 과 같 습 니 다. 최대 인쇄 용지 폭, 프린터 종류 등.
이렇게 두 가지 서로 다른 매개 변 수 를 가 진 장 치 는 어떻게 그들의 데 이 터 를 데이터베이스 에 저장 해 야 합 니까?방금 위의 질문 에 따 르 면, 우 리 는 2 개의 표, 컴퓨터 표 와 프린터 표를 만들어 야 하 며, 각각 해당 하 는 매개 변 수 를 열 에 포함 시 켜 야 합 니 다. 그러면 카메라 와 같은 장치 가 더 많 으 면, 우 리 는 데이터 표를 한 장 더 만들어 야 하 며, 데이터 베 이 스 를 유지 하 는 데 지 쳐 야 합 니 다.
그러나 매개 변수 와 설비 의 분리 에 따라 매개 변수 표 의 형식 으로 각종 설비 의 매개 변 수 를 정의 하고 외부 키 로 설비 분류 표 에 연결 한 다음 에 구체 적 인 설비 의 각종 매개 변수의 값 을 매개 변수 값 표 에 넣 으 면 각 설비 의 매개 변 수 를 저장 할 수 있다.
매개 변수 값 의 데이터 시트 에서 하나의 매개 변 수 는 어느 장치 에 속 하 는 지, 주로 장치 의 id 와 매개 변수의 id 에 따라 확정 합 니 다. 이러한 표 구 조 는 상대 적 으로 통용 되 습 니 다.
비교적 번 거 로 운 것 은 장 치 를 추가 할 때 해당 하 는 매개 변수 값 을 증가 해 야 한 다 는 것 이다. 그 매개 변 수 는 장치 표 에 있 지 않 기 때문에 매개 변수 표를 통 해 조회 해 야 한다. 매개 변수 표 에서 매개 변수의 장치 분류 id = 구체 적 인 장치 의 소속 장치 분류 id 줄 은 바로 이 장치 가 가지 고 있 는 매개 변수 이다.
예 를 들 면:
장치 분류 표 의 데이터: id  name1   데스크 톱 컴퓨터   프린터
매개 변 수 는 매개 변수 표 에 다음 과 같은 몇 줄 의 데 이 터 를 저장 합 니 다: id name      category    1  CPU 주파수    1 2  MAC 주소    1 3  메모리 크기   1 4  모니터 크기  모니터 종류 16  하드디스크 크기   1 7  최대 인쇄 폭 2
데스크 톱 컴퓨터 에는 6 개의 인자 가 있 고 프린터 에는 1 개의 인자 가 있다 는 것 을 한눈 에 알 수 있다.
제2 절 해결 방안 의 선택
데이터 구조 가 명확 해 졌 습 니 다. 현재 의 문 제 는 이 매개 변수의 값 을 어떻게 입력 하 느 냐 하 는 것 입 니 다.어려움 은 모든 장치 의 매개 변수의 개수 가 확실 하지 않다 는 것 이다. 따라서 form 을 정의 할 때 우 리 는 고정 적 으로 고정 적 으로 고정 적 으로 고정 적 으로 고정 적 으로 고정 적 으로 고정 적 으로 고정 적 으로 고정 적 으로 고정 적 으로 고정 적 으로 고정 적 으로 고정 적 으로 고정 적 으로 고정 적 으로 고정 적 으로 고정 적 으로 고정 적 으로 고정 적 으로 고정 적 으로 고정 적 으로 고정 적 으로 고정 적 으로 고정 적 으로 고정 적 으로 고정 적 으로 고정 적 으로 증가 하고 감소 하 는 field
여기 서 제 생각 은 매개 변수 개수 가 데이터베이스 에 저 장 된 이상 데이터 베 이 스 를 조회 하여 동적 으로 생 성 해 야 한 다 는 것 입 니 다. 그렇다면 django 를 사용 하려 면 어떤 구체 적 인 방법 을 사용 해 야 합 니까?
나 자신 은 많은 방법 을 시험 해 보 았 고, 또한 디 버 깅 과정 에서 천천히 이 문 제 를 해결 하 는 방법 을 찾 았 다.
과정 은 다음 과 같 습 니 다. 제 가 생각 하기 시작 한 해결 방안 은 다음 과 같 습 니 다. 1. ajax 를 사용 하여 동적 으로 form 2 를 생 성 합 니 다. admin 의 방법 을 사용 하여 inline 의 방법 으로 장 치 를 추가 하 는 동시에 몇 개의 인 자 를 추가 합 니 다. formset 를 사용 하여 4. formtools 의 formwizard (폼 마법사) 를 사용 하여 만 듭 니 다.
문제 의 곤경 은 주로 매개 변수 값 의 표 에 두 개의 외부 키 가 있 기 때문에 어떻게 해 야 할 지 확실 하지 않다. 앞의 세 가지 방법 을 나 는 단지 시험 해 보 았 을 뿐 하루 이틀 동안 디 버 깅 을 하고 포기 했다. 주요 원인 은 1. ajax 나 는 아직 잘 모 르 기 때문에 그것 을 잘 사용 하려 면 관련 된 자바 script 라 이브 러 리 를 배 워 야 한다. 당분간 잘 하지 못 할 것 이다. 2. admin 중의 inline 은 데이터 model 을 대상 으로 하 는 것 이다.증가 하 는 매개 변수 값 도 같 습 니 다. 예 를 들 어 6 개의 CPU 매개 변수 로 증가 할 수 있 습 니 다. 또한 admin 에 사 용 된 것 입 니 다. 자신 이 사용 하 는 것 도 귀 찮 습 니 다. 3. formset 의 form 도 같은 데이터 모델 을 요구 하지만 매개 변수 값 표 에서 2 개의 외부 키 가 높 은 당신 은 formset 를 사용 할 수 없습니다.formset 는 간단 한 데이터 구조 에서 데 이 터 를 입력 하 는 데 사 용 됩 니 다. formset 는 하나의 함수 가 add 입 니 다.fields, 이 함 수 는 비교적 유용 하지만 form 에는 이 함수 가 없습니다. 원 리 를 이해 하면 간단 합 니 다. form [field name] = forms. CharField () 와 같은 것 은 하나의 form 인 스 턴 스 에 field 를 추가 할 수 있 습 니 다. 저 는 formset 가 문 제 를 해결 할 수 있다 고 생각 합 니 다. 그러나 전 제 는 formset 를 구성 하기 전에 formset 에 몇 개의 매개 변수 값 이 있 는 form 이 안에 있 는 지 미리 알 아야 합 니 다.(특정한 분 류 된 장치 에 몇 개의 매개 변수 가 있 는 지 알 아야 한다. 예 를 들 어 formset 에서 몇 개의 form, CharacteristicValue 의 form 을 구축 하고 모든 form 은 서로 다른 매개 변 수 를 사용 하여 initial 을 초기 화 하 는 것 이다). 한 페이지 에서 먼저 장치 의 form 을 추가 합 니 다. 장치 의 매개 변수 개 수 는 고정 되 어 있 지 않 기 때문에 몇 개의 매개 변수 값 폼 을 포함 하 는 formset 를 동적 으로 증가 시 켜 야 합 니 다. 그러면 장치 의 매개 변 수 를 선택 할 수 있 습 니 다. formset 는 고정 개수 의 form 을 사용 하 는 데 비교적 적 용 됩 니 다. 그래서 formset 를 사용 하 는 데 어려움 을 주 었 습 니 다. 이런 방식 을 사용 하려 면 최종 적 으로 ajax 를 사용 하여 루트 를 사용 해 야 합 니 다.사용자 가 장치 형식 을 선택 할 때 동적 생 성 formset. formset 는 view 에서 초기 화 해 야 합 니 다.
그래서 이런 방식 을 나 는 채택 하지 않 았 다.
저 는 폼 가이드 방식 을 사 용 했 습 니 다. jango 의 contrib 에서 formtools 를 제 공 했 습 니 다. 사용 해 봐 야 좋 을 것 같 습 니 다. 저 는 영어 문 서 를 보면 서 조금씩 배 워 서 사용 하 는 것 이 정말 편리 합 니 다. 하지만 위의 4 가지 해결 방안 의 실현 과정 은 매우 어 려 웠 습 니 다. 저 는 3 일 만 에 실 마 리 를 잡 았 습 니 다.
제3 절 구체 적 인 실현
django 에서 폼 마법사 가 사용 하기 쉬 워 요.
from django.utils.translation import ugettext_lazy as _
from django import forms
from django.forms.formsets import BaseFormSet
from django.forms.fields import FileField
from django.forms.util import ValidationError

from django.shortcuts import render_to_response
from django.contrib.formtools.wizard import FormWizard

from ddtcms.office.equipment.models import Equipment,Characteristic,CharacteristicValue

class EquipmentForm(forms.ModelForm):

    class Meta:
        model = Equipment

class CharacteristicValueForm(forms.Form):
    def clean(self):
        a=self.fields
        s=self.data
        self.cleaned_data = {}
        #       for    django forms.py   full_clean      
        for name, field in self.fields.items():
            # value_from_datadict() gets the data from the data dictionaries.
            # Each widget type knows how to retrieve its own data, because some
            # widgets split data over several HTML fields.
            value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
            try:
                if isinstance(field, FileField):
                    initial = self.initial.get(name, field.initial)
                    value = field.clean(value, initial)
                else:
                    value = field.clean(value)
                self.cleaned_data[name] = value
                if hasattr(self, 'clean_%s' % name):
                    value = getattr(self, 'clean_%s' % name)()
                    self.cleaned_data[name] = value
            except ValidationError, e:
                self._errors[name] = self.error_class(e.messages)
                if name in self.cleaned_data:
                    del self.cleaned_data[name]
        #cl=self.cleaned_data
        #debug()<<<    ,  cl  ,    self.cleaned_data  ,  return ,     
        return self.cleaned_data

class EquipmentCreateWizard(FormWizard):
    def done(self, request, form_list):
        return render_to_response('equipment/done.html',
        {
        'form_data': [form.cleaned_data for form in form_list],
        })


    def get_form(self, step, data=None):
        "Helper method that returns the Form instance for the given step."
        form     = self.form_list[step](data, prefix=self.prefix_for_step(step), initial=self.initial.get(step, None))
        
        if step == 1:
            if data:
                cg       = data.get('0-category', 1)
                cs       = Characteristic.objects.all().filter(category__id=cg)
                for c in cs:
                    form.fields['Characteristic-'+str(c.id)] = forms.CharField(label = c.name)
                g=form.fields
                #debug()
        return form
        
    #  wizard.py          .    
    def render(self, form, request, step, context=None):
        "Renders the given Form object, returning an HttpResponse."
        old_data = request.POST
        prev_fields = []
        if old_data:
            hidden = forms.HiddenInput()
            # Collect all data from previous steps and render it as HTML hidden fields.
            for i in range(step):
                old_form = self.get_form(i, old_data)
                hash_name = 'hash_%s' % i
                prev_fields.extend([bf.as_hidden() for bf in old_form])
                prev_fields.append(hidden.render(hash_name, old_data.get(hash_name, self.security_hash(request, old_form))))
            if step == 1:
                cg       = old_data.get('0-category', 1)
                cs       = Characteristic.objects.all().filter(category__id=cg)
                for c in cs:
                    form.fields['Characteristic-'+str(c.id)] = forms.CharField(label = c.name)
                g=form.fields
                #debug()
            if step == 2:
                debug()
        return super(EquipmentCreateWizard, self).render(form, request, step, context=None)
        

    def get_template(self, step):
        return 'equipment/wizard_%s.html' % step




 
Equipment Create Wizard 도 views. py 에 넣 을 수 있 고 좀 더 합 리 적 이 라 고 생각 합 니 다. Equipment Create Wizard 에서 process step 함 수 를 수정 해 보 았 지만 정확 한 결 과 를 얻 지 못 했 습 니 다. 나중에 get form 을 수정 하 였 습 니 다. 모두 django 의 formtools 의 wizard. py 에서 복사 하여 수정 하려 고 했 습 니 다. get form 의 수정 도 정확 한 결 과 를 얻 지 못 했 습 니 다. 나중에 ren 을 수정 하 였 습 니 다.der 함수, 두 번 째 단계 에서 저 는 동적 매개 변수 개 수 를 보 여 주 었 습 니 다. 그러나 마지막 에 done 을 끝 낸 부분 에서 얻 은 formdata 에서 두 번 째 form 은 데이터 가 없고 빈 {} 입 니 다. 그래서 저 는 get form 함 수 를 다시 수정 하 였 습 니 다. 두 번 째 단계 인지 아 닌 지 판단 한 다음 에 두 번 째 form 동태 에 몇 개의 field 를 추가 하 는 것 이 아 닙 니 다.
if step == 1:
    cg       = old_data.get('0-category', 1)
    cs       = Characteristic.objects.all().filter(category__id=cg)
    for c in cs:
        form.fields['Characteristic-'+str(c.id)] = forms.CharField(label = c.name)
    g=form.fields
    #debug()

 
이 코드 는 get form 과 render 에 있 습 니 다. 모두 두 번 째 단계 인지 아 닌 지 를 판단 한 다음 에 첫 번 째 단계 에서 선택 한 장치 의 분류 에 따라 구체 적 인 분 류 를 조회 한 다음 에 분류 에 따라 이 분 류 된 장치 에 어떤 매개 변수 가 있 는 지 를 얻 은 다음 에 매개 변수 개수 에 따라 form 의 매개 변수 field 의 개 수 를 수정 합 니 다. 'Characteristic -' + str (c. id)나중에 데 이 터 를 저장 할 때 split 이 문자열 은 매개 변수의 id 를 얻 고 매개 변수 값 표 에 Characteristic - 1, Characteristic - 2... 의 value 를 저장 합 니 다.
g=form.fields#debug()
매개 변수 field 가 몇 개 있 는 지, 수정 에 성 공 했 는 지 정지점 에서 볼 수 있 습 니 다.   
=========================
from django.conf.urls.defaults import *
from ddtcms.office.equipment.forms import EquipmentForm,CharacteristicValueForm,EquipmentCreateWizard


urlpatterns = patterns('ddtcms.office.equipment.views',
    url(r'^$', 'index', name="equipment_index"), 
    url(r'^add/$', 'equipment_create', name="equipment_create"),
    url(r'^add-by-wizard/$',EquipmentCreateWizard([EquipmentForm, CharacteristicValueForm]), name="equipment_create_by_wizard"), )
	    ,csdnbolg       $  ,     ,        .

==========================wizard_0.html
{% block content %}

 <h2>  /      </h2>
 <p>  {{ step }}  ,   {{ step_count }}  .</p>
 <p>        </p>

    <form method="POST" action="">{% csrf_token %}
        <table>
            {{ form }}
        </table>
        <input type="hidden" name="{{ step_field }}" value="{{ step0 }}" />
        {{ previous_fields|safe }}
        <input type="submit" value="Submit" />
    </form>

{% endblock %}


 
===================wizard_1.html
{% block content %}

 <h2>  /      </h2>
 <p>  {{ step }}  ,   {{ step_count }}  .</p>
 <p>      ,           ,        .</p>

    <form method="POST" action="">{% csrf_token %}
        <table>
            {{ form }}
        </table>
        <input type="hidden" name="{{ step_field }}" value="{{ step0 }}" />
        {{ previous_fields|safe }}
        <input type="submit" value="Submit" />
    </form>

{% endblock %}


 
====================done.html
{% block content %}

 <h2>  /      </h2>
 <p>            .</p>

    {{form_data}}
   
{% endblock %}


============
또한 다른 form 으로 formwizard 를 실현 할 수 있 습 니 다. 바로 첫 번 째 form 1 입 니 다. 주로 사용자 가 장치 의 분 류 를 선택 하도록 합 니 다. form 2 는 앞의 것 에 따라 동적 으로 매개 변 수 를 생 성 하 는 폼 입 니 다. 원 리 는 같 습 니 다.
그리고 view 2 개 를 써 서 formwizard 를 모 의 하 는 것 입 니 다. 첫 번 째 view 는 장 치 를 추가 하고 두 번 째 view 는 장치 id 라 는 매개 변 수 를 가 져 오 면 장치 의 인 자 를 효과적으로 증가 할 수 있 습 니 다.

좋은 웹페이지 즐겨찾기