วันพฤหัสบดีที่ 26 กุมภาพันธ์ พ.ศ. 2558

Assignment I

Assignment I

////1st_week////
Scoop

THB - Thai Bath
USD - US Dollar
EUR - Euro
GBP - British Pound
JPY - Japanese Yen
CNY - Chinese Yuan Renminbi
MYR - Malaysian Ringgit
SGD - Singapore Dollar
etc.

Meaning
Tier 1
Tier 2



Supported Currencies

from fixer.io

Code Currency
AUD Australian Dollar
BGN Bulgarian Lev
BRL Brazilian Real
CAD Canadian Dollar
CHF Swiss Franc
CNY Chinese Yuan Renminbi
CZK Czech Koruna
DKK Danish Krone
EUR Euro
GBP Pound Sterling
HKD Hong Kong Dollar
HUF Hungarian Forint
IDR Indonesian Rupiah
ILS Israeli Shekel
INR Indian Rupee
JPY Japanese Yen
KRW South Korean Won
MXN Mexican Peso
MYR Malaysian Ringgit
NOK Norwegian Krone
NZD New Zealand Dollar
PHP Philippine Peso
RON Romanian New Leu
RUB Russian Ruble
SEK Swedish Krona
SGD Singapore Dollar
THB Thailand Baht
TRY Turkish Lira
USD United States Dollar
ZAR South African Rand
 
 
Link for more 
Use This API : http://fixer.io/
http://www.xe.com/currencyconverter/
http://www.scb.co.th/scb_api/index.jsp 
https://pypi.python.org/pypi/money 
http://www.exchangerate-api.com/python-currency-api 
https://github.com/gizmag/django-currency-exchange  

//////////////////////// 
``link for Convert Button Idea`` 
http://www.w3schools.com/css/default.asp
http://www.w3schools.com/tags/tryit.asp?filename=tryhtml5_button_formtarget
http://www.w3schools.com/tags/att_button_formaction.asp
http://www.w3schools.com/tags/tag_select.asp

Example Pics 

[ NEW UPDATE ]

Currency Exchange Page

Convert 9 USD -> 294.21 THB


Convert 9 TRY -> 219.81 INR

Convert 9 TRY -> 9 TRY

Rates Page

Russian Ruble (RUB) Rates



วันจันทร์ที่ 23 กุมภาพันธ์ พ.ศ. 2558

Chapter 6 : Getting to the Minimum Viable Site


ทำการสร้าง directory “functional_tests” ซึ่งภายในจะมีไฟล์ "__init__.py” ด้วยคำสั่ง
$ mkdir
functional_tests
$ touch
functional_tests/__init__.py
และทำการ move functional tests เข้าไปใน directory ที่เราสร้างขึ้น และเปลี่ยนชื่อเป็น tests.py ด้วยคำสั่ง
$ git mv
functional_tests.py functional_tests/tests.py
$ git
status
เมื่อรัน tree จะได้
.
├── db.sqlite3
├── functional_tests
│   ├── __init__.py
│   └── tests.py
├── lists
│   ├── admin.py
│   ├── __init__.py
│   ├── migrations
│   │   ├── 0001_initial.py
│   │   ├── 0002_item_text.py
│   │   ├── __init__.py
│   │   └── __pycache__
│   ├── models.py
│   ├── __pycache__
│   ├── templates
│   │   └── home.html
│   ├── tests.py
│   └── views.py
├── manage.py
└── superlists
    ├── __init__.py
    ├── __pycache__
    ├── settings.py
    ├── urls.py
    └── wsgi.py
จากนั้นทำการ แก้ไข functional_tests/tests.py และทำการเปลี่ยน NewVisitorTest class เป็น LiveServerTestCase
from django.test import LiveServerTestCase
from selenium import webdriver 
from selenium.webdriver.common.keys import Keys
class NewVisitorTest(LiveServerTestCase):
    def setUp(self):
        […]
จากนั้นทำการเปลี่ยน localhost เป็น live_server_url 
 def test_can_start_a_list_and_retrieve_it_later(self): 
 # Edith has heard about a cool new online to-do app. She goes
 # to check out its homepage
       
self.browser.get(self.live_server_url)
ทดสอบรัน FT


ทำการ commit ไว้
$ git status #
functional_tests.py renamed + modified, new __init__.py
$ git add functional_tests
$ git diff --staged -M
$ git
commit  # msg eg "make functional_tests an app, use
LiveServerTestCase"
จากนั้นทำการรัน Unit Test






และเราสามารถรันเฉพาะบางส่วนได้ ยกตัวอย่างให้รัน lists






Useful Commands Updated



To run the functional tests
python3 manage.py test functional_tests
To run the unit tests 
       python3 manage.py test lists
 
ทำการเข้าไปเพิ่มในส่วนท้ายของ ไฟล์ functional_tests/tests.py ในส่วน def test_can_start_a_list_and_retrieve_it_later(self): ว่า

    # Edith wonders whether the site will remember her list. Then she sees
    # that the site has generate a unique URL for her -- there is some
    # explanatory text to that effect.
    self.fail('Finish the test!')

    # She visits that URL - her to-do list is still there.
 
    # Satisfied, she goes back to sleep

REST

Idea ของ data structure คือ Model-View-Controller (MVC) สำหรับในแต่ละ lists และ lists item ก็จะมี URL ของมันเอง
    /lists/<list identifier>/
ถ้าต้องการสร้าง list ใหม่ ก็จะมี URL พิเศษที่มันสามารถ accept POST request ได
    /lists/new
ถ้าต้องการสร้าง list item ใหม่จาก list ที่มีอยู่แล้ว เราจะมีการ separate URL ซึ่งเราจะสามารถส่ง POST request ได้

    /lists/<list identifier>/add_item
**เราแค่จะใช้แนวคิดของ REST มาใช้**

Implementing the New Design Using TDD

ให้มองหา inputbox.send_keys('Buy peacock feathers') ใน functional_tests/tests.py. แล้วทำการแก้ไขดังนี้
    inputbox.send_keys('Buy peacock feathers')
    # When she hits enter, she is taken to a new URL,
    # and now the page lists "1: Buy peacock feathers" as an item in a
    # to-do list table
    inputbox.send_keys(Keys.ENTER)
    edith_list_url = self.browser.current_url
    self.assertRegex(edith_list_url,'/lists/.+') 
    self.check_for_row_in_list_table('1: Buy peacock feathers')

    # There is still a text box inviting her to add another item. She
    [...]
และแก้ไขเพิ่มเติม

    [...]
    # The page updates again, and now shows both items on her list
    self.check_for_row_in_list_table('2: Use peacock feathers to make a fly')
    self.check_for_row_in_list_table('1: Buy peacock feathers')
    # Now a new user, Francis, comes along to the site.
 
    ## We use a new browser session to make sure that no information
    ## of Edith's is coming through from cookies etc 
    self.browser.quit()
    self.browser = webdriver.Firefox()
 
    # Francis visits the home page.  There is no sign of Edith's
    # list
    self.browser.get(self.live_server_url)
    page_text = self.browser.find_element_by_tag_name('body').text
    self.assertNotIn('Buy peacock feathers', page_text)
    self.assertNotIn('make a fly', page_text)
 
    # Francis starts a new list by entering a new item. He
    # is less interesting than Edith...
    inputbox = self.browser.find_element_by_id('id_new_item')
    inputbox.send_keys('Buy milk')
    inputbox.send_keys(Keys.ENTER)

    # Francis gets his own unique URL
    francis_list_url = self.browser.current_url
    self.assertRegex(francis_list_url, '/lists/.+')
    self.assertNotEqual(francis_list_url, edith_list_url)
 
    # Again, there is no trace of Edith's list
    page_text = self.browser.find_element_by_tag_name('body').text
    self.assertNotIn('Buy peacock feathers', page_text)
    self.assertIn('Buy milk', page_text)
 
    # Satisfied, they both go back to sleep
และทดลองรัน FT


Commit ไว้ก่อน 
 $ git commit -a

Iterating Towards the New Design

ทำการเปลี่ยนแปลง locationใน lists/tests.py หาในส่วนของ test_home_page_redirects_after_POST
 self.assertEqual(response.status_code, 302)
 self.assertEqual(response['location'], '/lists/the-only-list-in-the-world/')
และทดลองรัน UT











ให้ทำการเข้าไปแก้ไข home_page redirect ที่ lists/views.py.

def home_page(request):
    if request.method == 'POST':
       
        Item.objects.create(text=request.POST['item_text'])
        return redirect('/lists/the-only-list-in-the-world/')

    items = Item.objects.all()
    return render(request, 'home.html', {'items': items})
เมื่อรัน Unit Test จะ OK แต่ถ้ารัน FT จะพบว่า URL /the-only-list-in-the-world/ ไม่ได้มีอยู่จริง

Testing Views, Templates, and URLs Together with the Django Test Client

A New Test Class

ให้ทดลอง test client โดยเปิด lists/tests.py แล้ว copy method test_home_page_displays_all_ list_items จาก HomePageTest แล้วทำการเปลี่ยนแปลงค่าเล็กน้อย

class ListViewTest(TestCase):

    def test_displays_all_items(self):
        Item.objects.create(text='itemey 1')
        Item.objects.create(text='itemey 2')

        response = self.client.get('/lists/the-only-list-in-the-world/')
 
       
        self.assertContains(response, 'itemey 1') 

        self.assertContains(response, 'itemey 2') 
ทดลอง รัน UT


จะพบว่า 404 != 200 ซึ่งเราจะต้องไปเพิ่มในส่วนของ URLs

A New URL

เข้าไปที่ superlists/urls.py. แล้วทำการแก้ไขเพิ่มเติม

urlpatterns = patterns('',
    url(r'^$', 'lists.views.home_page', name='home'),
    url(r'^lists/the-only-list-in-the-world/$', 'lists.views.view_list',
        name='view_list'
    ),
    # url(r'^admin/', include(admin.site.urls)),
)
รัน Unit Test อีกครั้ง


จะพบว่า จะต้องมี view function เพิ่มเติมด้วย

A New View Function

ทำการสร้าง dummy view function ใน lists/views.py:

def view_list(request):
    pass
ถ้าพอจำได้ การส่งค่า pass ธรรมดา จะรันไม่ได้ เพราะต้องการ HttpRespone ให้ทำการเพิ่มเติมส่วน return

def view_list(request):
    items = Item.objects.all()
    return render(request, 'home.html', {'items': items})
ทำการรัน Unit Test


และทดลองรัน FT


Green? Refactor

รันคำสั่ง $ grep -E "class|def" lists/tests.py


และเข้าไปทำการลบ test_home_page_displays_all_list_items method ใน lists/tests.py และทดลองรัน manage.py test lists


A Separate Template for Viewing Lists

ทดลองรัน Test ใหม่เพื่อตรวจสอบการใช้งาน template และให้เข้าไปเพิ่มเติมใน  lists/views.py.

class ListViewTest(TestCase):

    def test_uses_list_template(self):
        response = self.client.get('/lists/the-only-list-in-the-world/')
        self.assertTemplateUsed(response, 'list.html')
    def test_displays_all_items(self):
        [...]
เมื่อทดลองรันทดสอบ assert จะได้ว่า

AssertionError: False is not true : Template 'list.html' was not a template
used to render the response. Actual template(s) used: home.html
และให้เข้าไปแก้ไขใน lists/views.py. อีกที
def view_list(request):
    items = Item.objects.all()
    return render(request, 'list.html', {'items': items})
ทดลองรัน UT จะได้

django.template.base.TemplateDoesNotExist: list.html
จากนั้นให้เข้าไปทำการสร้างไฟล์ใหม่ ที่ lists/templates/list.html

$ touch lists/templates/list.html
และทำการ copy ไฟล์ home.html ไปเป็น list.html

cp lists/templates/home.html lists/templates/list.html
ทดลองรัน UT จะเห็นว่ารันผ่าน และทำการเปลี่ยนแปลงภายในไฟล์ lists/templates/home.html.

<body>
    <h1>Start a new To-Do list</h1>
    <form method="POST">
        <input name="item_text" id="id_new_item" placeholder="Enter a to-do item" />
        {% csrf_token %}
    </form>
</body>
และทดลองรัน UT อีกครั้ง ก็ยังผ่านเหมือนเดิม ให้เข้าไปแก้ไขใน lists/views.py.

def home_page(request):
    if request.method == 'POST':
        Item.objects.create(text=request.POST['item_text'])
        return redirect('/lists/the-only-list-in-the-world/')
    return render(request, 'home.html')
รัน UT อีกครั้งก็จะยัง รันผ่านเหมือนเดิม และให้ทดลองรัน FT






เรายังติดปัญหาที่ input ตัวที่ 2 สามารถแก้ไขได้โดยเข้าไปที่ lists/templates/list.html:

    <form method="POST" action="/">
และทดลองรัน FT อีกครั้ง






โอเค เราได้ URL ที่ไม่ซ้ำกันแล้วสำหรับ 1 list ของเรา และต่อไปให้ทำการ git commit ไว้ก่อน

$ git status # should show 4 changed files and 1 new file, list.html
$ git add lists/templates/list.html
$ git diff # should show we've simplified home.html,
           # moved one test to a new class in lists/tests.py added a new view
           # in views.py, and simplified home_page and made one addition to
           # urls.py
$ git commit -a # add a message summarising the above, maybe something like
                # "new URL, view and template to display lists"

Another URL and View for Adding List Items

A Test Class for New List Creation

เปิด lists/tests.py, แล้วทำการเพิ่มเติม class

class
NewListTest(TestCase):

    def
test_saving_a_POST_request(self):
        self.client.post(
            '/lists/new',
            data={'item_text':
'A new list item'}
        )
        self.assertEqual(Item.objects.count(),
1)
        new_item =
Item.objects.first()
        self.assertEqual(new_item.text,
'A new list item')


    def
test_redirects_after_POST(self):
        response =
self.client.post(
            '/lists/new',
            data={'item_text':
'A new list item'}
        )
        self.assertEqual(response.status_code,
302)
       
self.assertEqual(response['location'],
'/lists/the-only-list-in-the-world/')

A URL and View for New List Creation

เปิด superlists/urls.py. และแก้ไข



urlpatterns
= patterns('',
    url(r'^$',
'lists.views.home_page', name='home'),
    url(r'^lists/the-only-list-in-the-world/$',
'lists.views.view_list',
        name='view_list'
    ),
    url(r'^lists/new$',
'lists.views.new_list',
name='new_list'),
    # url(r'^admin/',
include(admin.site.urls)),
)



เปิด lists/views.py. และแก้ไข

def
new_list(request):
    return
redirect('/lists/the-only-list-in-the-world/')



จะได้ว่า




เข้าไป lists/views.py. และแก้ไขอีกครั้ง

def
new_list(request):
   
Item.objects.create(text=request.POST['item_text'])
    return
redirect('/lists/the-only-list-in-the-world/') 



จะพบว่า
AssertionError:
'http://testserver/lists/the-only-list-in-the-world/' !=
'/lists/the-only-list-in-the-world/'
-
http://testserver/lists/the-only-list-in-the-world/
? -----------------
+
/lists/the-only-list-in-the-world/
ให้เข้าไปแก้ไขที่ lists/tests.py. เปลี่ยนเป็น AssertRedirect

    def
test_redirects_after_POST(self):
        response =
self.client.post(
            '/lists/new',
            data={'item_text':
'A new list item'}
        )
       
self.assertRedirects(response,
'/lists/the-only-list-in-the-world/')

ผลที่ได้ 
Ran 8 tests in 0.018s

OK

Removing Now-Redundant Code and Tests

เราสามารถ remove if request.method == 'POST' ได้หรือเปล่า (สิ่งที่ซับซ้อน) เข้าไปใน lists/views.py.
 
def
home_page(request):
    return
render(request, 'home.html')
ผลที่ได้
Ran 8 tests in 0.017s

OK


และเรายังสามารถ remove test_home_page_only_saves_ items_when_necessary test ได้อีกด้วย
ผลที่ได้
Ran 7 tests in 0.016s

OK

Pointing Our Forms at the New URL