Sunday, September 26, 2010

Learning Django: Form

การสร้าง form เป็นเรื่องจำเป็นสำหรับ web app ทั่วไป ในหัวข้อนี้จะกล่าวเกี่ยวกับเรื่อง Form ใน Django

Getting Data from the Request Object

เราสามารถรับค่าจาก request object (browser) ได้ ใน view แต่ละ view จะมี HttpRequest เป็นพารามิเตอร์แรก ลองดูตัวอย่าง hello view ของเรา


from django.http import HttpResponse
def hello(request):
    return HttpResponse("Hello world")

ในตัว request มี attributes และ methods ดังนี้
- request.path
- request.get_host()
- request.get_full_path()
- request.is_secure()
- request.META เป็น python dictionary ปกติจะมี ข้อมูลดังนี้
    - HTTP_REFERER
    - HTTP_USER_AGENT
    - REMOTE_ADDR
- request.GET เป็น python dictionary
- request.POST เป็น python dictionary


Form example

เราลองมาสร้าง form จาก application ของเรากันดู



1. สร้าง template search_form.html โดยมี input ประมาณนี้

<form action="/search/" method="get">
<input type="text" name="q">
<input type="submit" value="Search">
</form>


2. สร้าง template สำหรับ search_results.html

<p>You searched for: <strong>{{ query }}</strong></p>
{% if books %}
<p>Found {{ books|length }} book{{ books|pluralize }}.</p>
<ul>
{% for book in books %}
<li>{{ book.title }}</li>
{% endfor %}
</ul>
{% else %}
<p>No books matched your search criteria.</p>
{% endif %}

3. สร้าง view สำหรับ input form และ search ใน books/views.py

from django.http import HttpResponse


from django.shortcuts import render_to_response



from mysite.books.models import Book


def search_form(request):
    return render_to_response('search_form.html')



def search(request):
    if 'q' in request.GET and request.GET['q']:
        q = request.GET['q']
        books = Book.objects.filter(title__icontains=q)
        return render_to_response('search_results.html',
        {'books': books, 'query': q})
    else:
        return HttpResponse('Please submit a search term.')

3. map input form และ search ใน urls.py




urlpatterns = patterns('',
    # ...
    (r'^search-form/$', views.search_form),
    (r'^search/$', views.search),
    # ...
)


ลองมาดูตัวอย่างที่ซับซ้อนขึ้น เราจะสร้าง contact form โดยมีลักษณะดังนี้


1. สร้าง contact_form.html ที่เป็น template สำหรับกรอกข้อมูล
2. contact_form.html ส่งข้อมูลไปยัง contact
3. contact ตรวจสอบข้อมูล
    -ถ้าไม่มีข้อผิดพลาดส่งเมลล์ แล้ว ไปยัง thank
    -ถ้าเกิดข้อผิดพลาดไปยังหน้า contact_form.html ใหม่


ตัวอย่างของ views.py กับ contact_form.html จะมีลักษณะดังนี้


views.py



def contact(request):
    errors = []
    if request.method == 'POST':
        if not request.POST.get('subject', ''):
            errors.append('Enter a subject.')
        if not request.POST.get('message', ''):
            errors.append('Enter a message.')
        if request.POST.get('e-mail') and '@' not in request.POST['e-mail']:
            errors.append('Enter a valid e-mail address.')
        if not errors:
            send_mail(
                request.POST['subject'],




            



                request.POST['message'],

                request.POST.get('e-mail', 'noreply@example.com'),
                ['siteowner@example.com'],
            )
            return HttpResponseRedirect('/contact/thanks/')
    return render_to_response('contact_form.html', {
        'errors': errors,
        'subject': request.POST.get('subject', ''),
        'message': request.POST.get('message', ''),
        'e-mail': request.POST.get('e-mail', ''),
    })

contact_form.html

<html>
<head>
<title>Contact us</title>
</head>
<body>
<h1>Contact us</h1>
{% if errors %}
<ul>
{% for error in errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
<form action="/contact/" method="post">
<p>Subject: <input type="text" name="subject" value="{{ subject }}"></p>
<p>Your e-mail (optional):
<input type="text" name="e-mail" value="{{ e-mail }}">

</p>
<p>Message:
<textarea name="message" rows="10" cols="50">
**{{ message }}**
</textarea>
</p>
<input type="submit" value="Submit">
</form>
</body>
</html>






พบว่าในกรณีที่มีหลายๆ field แล้วมีการ validate ด้วยการสร้าง form และ view จะยุ่งยากมาก Django มี library ที่ชื่อ django.forms ที่ช่วยเราจัดการเรื่อง form ได้


Django Form

การสร้าง form ของ Django (จะยกตัวอย่างจาก contact form ข้างต้น)
1. กำหนด form ขึ้นมา ใน form.py (จริงๆ เขียนใส่ใน views.py ไปเลยก็ได้)

from django import forms


class ContactForm(forms.Form):
    subject = forms.CharField()
    e-mail = forms.EmailField(required=False)
    message = forms.CharField()


2.เปลี่ยน contact view ใหม่โดยใช้ Django form แทนที่ requst.POST


from django.shortcuts import render_to_response
from mysite.contact.forms import ContactForm


def contact(request):
    if request.method == 'POST':
        form = ContactForm(request.POST)
    if form.is_valid():
        cd = form.cleaned_data
            send_mail(
            cd['subject'],
            cd['message'],
            cd.get('e-mail', 'noreply@example.com'),
            ['siteowner@example.com'],
        )
        return HttpResponseRedirect('/contact/thanks/')
    else:
        form = ContactForm()
    return render_to_response('contact_form.html', {'form': form})


3. สร้าง contact_form.html


<html>
<head>
<title>Contact us</title>
</head>
<body>
<h1>Contact us</h1>

{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<form action="" method="post">
<table>
{{ form.as_table }}
</table>
<input type="submit" value="Submit">
</form>
</body>
</html>




นอกจากนี้ยังมีวิธีการปรับแต่ง form อื่นๆ อีกเช่น

1. กำหนดวิธีการแสดงผลของ field
2. ตั้งค่า maximum
3. กำหนด label
4. การเพิ่ม custom validation 



from django import forms


class ContactForm(forms.Form):
    subject = forms.CharField(max_length=100)
    e-mail = forms.EmailField(required=False, label='Your e-mail address')
    message = forms.CharField(widget=forms.Textarea)


    def clean_message(self):
        message = self.cleaned_data['message']
        num_words = len(message.split())
        if num_words &lt; 4:
            raise forms.ValidationError("Not enough words!")
        return message



5. การตั้งค่า initial ให้กับ form

form = ContactForm(
    initial={'subject': 'I love your site!'}
)
return render_to_response('contact_form.html', {'form': form})





No comments:

Post a Comment