/srv/irclogs.ubuntu.com/2010/02/26/#ubuntu-classroom.txt

=== edson is now known as ecanto
=== kermiac_ is now known as kermiac
=== nha is now known as Guest14985
=== Homer is now known as Guest29756
=== kermiac is now known as kermiac_
=== leoquant is now known as soonerorlater
=== soonerorlater is now known as leoquant
=== andylockran is now known as zrmt
=== zrmt is now known as andylockran
=== test is now known as Guest13870
=== goat is now known as Guest68340
=== Knightlust is now known as Igorots
=== einand is now known as Real_einand
=== Real_einand is now known as einand
* shadeslayer is excited about tomorrow13:04
=== eXe is now known as Guest23458
=== Igorots is now known as Knightlust
cjohnstontomorrow?14:13
shadeslayercjohnston: eh?14:15
shadeslayercjohnston: oh ill be giving a packaging session ;)14:15
cjohnstongotcha14:15
shadeslayer:D14:16
Pendulumcjohnston: and hggdh is giving a bug q&a14:16
cjohnstonI knew about hggdh's14:16
cjohnstonI knew about the PPA thing too..14:16
cjohnstonjust fergot about it14:16
Pendulumheh14:16
cjohnstonsince I put it on the calendar..14:17
cjohnstonlol14:17
shadeslayer:P14:17
cjohnstonshadeslayer: PM...14:17
shadeslayerim just writing notes write now on it14:17
hggdhwhat happens with me?15:18
cjohnstonhggdh: you are doing a bug q&a later15:32
hggdhcjohnston: yes, indeed. Adn you wanted to talk with me15:32
cjohnstonyup.. Got a few?15:33
hggdhyes15:35
cjohnstonPM hggdh15:35
=== ShadowChild is now known as lukjad86
=== ChanServ changed the topic of #ubuntu-classroom to: Welcome to the Ubuntu Classroom - http://wiki.ubuntu.com/Classroom || Support in #ubuntu || Upcoming Schedule: http://is.gd/8rtIi || Event: Intro to Django - Current Session: Learning Django - Part 3 - Instructor: mhall119|work || Questions in #ubuntu-classroom-chat
mhall119|workhello and good afternoon17:01
mhall119|worktoday we're going to do a double class, since I had to cancel yesterday17:01
mhall119|workfor those of you who misses yesterday, logs from the first two sessions can be found here: https://launchpad.net/classroom-scheduler17:02
mhall119|workA quick recap of what we covered yesterday...17:02
mhall119|workwe made Django Models for Session (a single online class), Course (a collection of classes), and LernidSession (a derivative of Session, that includes a URL for slides)17:03
mhall119|workwe also configured the Django Admin application so we can view our Models and create instances of them in the database17:04
mhall119|worktoday we finally get to the rewarding part of Django, creating the views and forms that will let our users interact with our models17:04
mhall119|worknow, before we begin, I made some changes to the application that are going to require you to modify your database17:05
mhall119|workIf you go to https://wiki.ubuntu.com/mhall119/classes/LearningDjango and scroll down to the section for Day 317:06
mhall119|workyou will see my note17:06
mhall119|workI'll briefly explain what changes I made and why17:06
mhall119|work"class" is a python keyword for defining, what else, classes17:07
mhall119|workby calling my application 'class' initially, I caused a conflict with this keyword when I tried to use it as a namescape in python17:07
mhall119|workso, I renamed the application to "classroom" to avoid the conflict17:08
mhall119|workhowever, when django created tables in the database, it defaults to naming them "application_model"17:08
mhall119|workby changing the name of the application, I also changed the name of the tables it will use17:08
mhall119|workso, once you run "bzr pull -r tag:day3.1"17:09
mhall119|workyou will need to either re-run "python manage.py syncdb", or just download the classroom_scheduler.db I uploaded here: https://wiki.ubuntu.com/mhall119/classes/LearningDjango?action=AttachFile&do=view&target=classroom_scheduler.db17:10
mhall119|workI'll give a few minutes for everyone to get their local copy updated to day3.117:10
mhall119|workask a QUESTION: if you have trouble with this17:11
mhall119|workif you update your old database, go into the admin and create a session and course for testing17:12
mhall119|workalright, time to get started17:13
mhall119|workday3.1 brought in several updates17:13
mhall119|workit creates a new view method "schedule_view"17:14
mhall119|workalong with templates/schedule_view.html17:14
mhall119|workand wired them up to the url /schedule/17:14
mhall119|workif you again run "python manage.py runserver" you should see something like this: http://www.growingupfree.org:8001/schedule/17:15
mhall119|worklet's look into classroom/views.py17:16
mhall119|workas you can see, schedule_view is very simple17:16
mhall119|workSession.objects.filter() returns a list of Session objects from the database17:17
mhall119|workyou can add key/value pairs to filter() to restrict what is returned, we'll see that in action later17:17
mhall119|worknext it creates a Context instance, and adds the list of sessions to it17:17
mhall119|workit then calls render_to_response, passing it the name of the template and the context17:18
mhall119|workrender_to_response is a utility method that will render the template into an HttpResponse object for us17:18
mhall119|worknow look at classroom/templates/schedule_view.html17:19
mhall119|workDjango templates are HTML with additional markup17:19
mhall119|work{% %} blocks are "tags" that perform logic operations17:20
mhall119|work{{ }} blocks will inline the value of the contained expression into the HTML17:20
mhall119|workDjango supplies many built in tags for you to use, and you can see we are using the {% for value in list %} tag here to iterate through our list of sessions17:21
mhall119|workyou'll also notice that the {{ }} blocks let you properties of a variable as well17:21
mhall119|workso {{ session.course.title }} will try to get the title of the course this session is a part of17:22
mhall119|workany questions so far?17:22
mhall119|workalright, moving on17:23
mhall119|workrun: "bzr pull -r tag:day3.2"17:24
mhall119|workthen "bzr diff -r tag:day3.1"17:24
mhall119|workhere you can see that we are using the {% if %}{% else %}{% endif %} blocks17:25
mhall119|workthen do exactly what you would expect17:25
mhall119|work{% if value %} will be true if value has a non-false value in python17:26
mhall119|workso, None, 0 and empty lists will execute the {% else %} block17:26
mhall119|work{% else %} is optional17:26
mhall119|worknow we are currently returning the datatime as python's default string representation17:27
mhall119|workbut if you look at the schedule on the wiki https://wiki.ubuntu.com/Classroom you see that the date and time are split into 2 columns17:28
mhall119|workif you run "bzr pull -r tag:day3.3", then "bzr diff -r tag:day3.2"17:28
mhall119|workyou will see that i split it into 2 columns, and use template "filters" to format what is displayed17:29
mhall119|workagain, Django provides a number of built in filters such as "date"17:29
mhall119|workfilters use the syntax: {{variable|filter:"extra"}}17:30
mhall119|workthe :"extra" is optional, not all filters need it17:30
mhall119|workfilters are used to act on the value of a variable, and return a different result17:31
mhall119|workNow you should be seeing something like this: http://www.growingupfree.org:8001/schedule/17:31
mhall119|workwe're starting to look a lot more like the wiki schedule now17:31
ClassBothemanth asked: can the filtering of time and date be done as per the clients local time?17:32
mhall119|workI don't think so, if store your time in UTC, you will have to change it to local time before using the filter17:33
mhall119|worknow, looking back at https://wiki.ubuntu.com/Classroom#Schedule17:33
mhall119|workyou will see that their times are links to an external site that does give times in several locations17:34
ClassBothemanth asked: can't we get the location of the client and do UTC +/- ?17:34
mhall119|workyes, and in fact python has a helpful method of doing this in datetime.timedelta17:35
mhall119|workalright, so next we want to turn out time display into a link17:35
mhall119|workwe can do this in our template itself, but this is used all the time within the Ubuntu wiki when times are displayed, and we don't really want to copy/paste it into every template we make17:36
mhall119|workinstead, we're going to make our own template filter to do it17:36
mhall119|workrun "bzr pull -r tag:day3.4"17:36
mhall119|workand then "bzr diff -r tag:day3.3"17:37
mhall119|workyou will see the new file classroom/templatetags/scheduler_tools.py17:37
mhall119|workthis a file that will contain any number of custom tags and filters17:38
mhall119|workwe use {% load scheduler_tools %} to include them in our schedule_view.html template17:38
mhall119|workthen we can get the URL for our link by simply using {{session.start_time|timelink}}17:39
mhall119|workif you look at classroom/templatetags/scheduler_tools.py, you see that filters are pretty easy to write17:39
mhall119|workthey are basically a function that takes the associated variable as an argument (and optionally any "extra" values)17:40
=== edsoncanto is now known as ecanto
mhall119|workand returns a value to be inlined into the HTML17:40
=== ecanto is now known as edson
=== yofel_ is now known as yofel
mhall119|work@register.filter is a python decorator that registers your filter with Django when {% load %} is called on the file17:41
mhall119|worknow, just as Filters are exceptionally easy to write, Tags are quite hard17:41
mhall119|workwhich is why I am not covering them in this series17:41
mhall119|workbut if you are curious, you can view them in the Django source files to see how they are implemented17:42
mhall119|workany questions at this point?17:42
mhall119|workanyone need a break before we get started on the next hour?17:43
ClassBotlsteeger asked: yes. how about 5 mins?17:44
mhall119|workokay, we'll take a short break then17:45
mhall119|workokay, is everyone back?17:52
mhall119|workalright17:53
mhall119|worktime to get into forms!17:53
mhall119|workmuch like a model, a Form is a collection of Field instances that map python values to HTTP parameters17:54
mhall119|workthat makes it easy to pass the contents of request.GET or request.POST to a Form, and get the right python data types out17:55
mhall119|workform fields will validate their own content, and raise an exception of it can not be converted into the right python data type17:55
mhall119|workfor example, if you pass "abc" to an IntegerField, it will raise an exception17:56
mhall119|workyou call form.is_valid() to determine if all the fields in a form contain well formatted values17:57
mhall119|workyou can then get the corresponding python data type from form.cleaned_data[]17:57
mhall119|workDjango form fields also contain widgets that are used to create the HTML necessary to build the form17:58
mhall119|workso you don't even have to worry about that17:58
mhall119|worka full listing of Django's form fields can be seen here: http://docs.djangoproject.com/en/1.1/ref/forms/fields/#ref-forms-fields17:59
mhall119|workhowever, you won't actually have to explicitly use them all the time17:59
=== ChanServ changed the topic of #ubuntu-classroom to: Welcome to the Ubuntu Classroom - http://wiki.ubuntu.com/Classroom || Support in #ubuntu || Upcoming Schedule: http://is.gd/8rtIi || Event: Intro to Django - Current Session: Learning Django - Part 4 - Instructor: mhall119|work || Questions in #ubuntu-classroom-chat
mhall119|workDjango provides a helpful ModelForm type, that will create a Form class with all the fields18:01
mhall119|workin your Model18:01
mhall119|workrun "bzr pull -r tag:day3.6"18:01
mhall119|workand "bzr diff -r tag:day3.4"18:02
mhall119|work(yes, day3.5 is missing)18:02
mhall119|worknow, you will see a new file: classroom/forms.py18:02
mhall119|workthis file contains 2 very small classes, SessionForm and CourseForm, both of which extend Django's ModelForm18:03
mhall119|workyou will also notice that, just like your Models, it contains an internal Meta class18:03
mhall119|workin this class, we specify which of our Model definitions we want this Form class to use18:03
mhall119|workand that's really all we need18:04
mhall119|workwe can now call form = SessionForm(request.POST)18:05
mhall119|workwe can also bind an instance of our model to the form: form = SessionForm(instance=mysession, data=request.POST)18:06
mhall119|workif we have a bound instance, we can call form.save() to apply all of the HTTP values to the instance, and save the instance to the database18:06
mhall119|workthis really saves a lot of boiler plate code you would need to write in other frameworks18:06
mhall119|workwe can also pass the bound form instance to a template for display18:07
mhall119|workrun "bzr pull -r tag:day3.7"18:07
mhall119|worknow you will have 2 new files, classroom/templates/session_view.html and classroom/templates/course_view.html18:08
mhall119|workthey are largely the same, so we'll just look at classroom/templates/session_view.html for now18:09
mhall119|workby default, forms will render themselves as a series of table rows and cells18:09
mhall119|workyou can also use {{form.as_p}} or {{form.as_ul}} to have it render as a series of <p> or <ul><li> tags18:10
mhall119|worknotice that it does not create the <form> or <table> tags itself, this makes it easy to add thing before or after the form fields18:11
mhall119|worksuch as submit and reset buttons18:11
mhall119|worknow if you look at classroom/views.py you will see 2 new view functions18:11
mhall119|worksession_view and course_view18:12
mhall119|workboth take an additional id argument18:12
mhall119|workagain, the view functionality is similar between them, so we'll only look at session_view18:12
mhall119|workfirst we determine if the session_id is 0, this lets us know if we are creating a new session, or modifying an existing one18:13
mhall119|workif it's 0, we just create an empty Session() instance18:13
mhall119|workotherwise, we use the helper method get_object_or_404 to see if a session by that id exists in the database18:14
mhall119|workif it doesn't exist, this method will raise an exception, and Django will forward the request to an error page saying that the Session for that id can't be found18:14
mhall119|worknext, we check to see if this is an HTTP POST request.18:14
mhall119|workif it is a POST, then we need to process the submitted values from our form18:15
mhall119|workwe create a new SessionForm, bound to both the Session instance we created and the POST data that was submitted18:15
mhall119|workcalling is_valid() will return true if all of the form's fields contain good data18:16
mhall119|workif it's all good, we call save() to apply the data to the record in the database18:16
mhall119|workif it's not a POST request, we are just going to display the form to the user18:16
mhall119|workwe create a SessionForm that is only bound to the session instance18:17
mhall119|workand add that to a Context object for our template18:17
mhall119|workand then call render_to_response again18:17
mhall119|workfinally, let's look at urls.py18:18
mhall119|workwe added 2 new entries there, for session_view and course_view18:18
mhall119|workthese use a slightly more complex url pattern than we've previously used, so lets take a closer look at them18:19
mhall119|workr'^session/(?P<session_id>\d+)'18:19
mhall119|workthis will match /session/#, where # can be any digit18:19
mhall119|workor multiple digists18:19
mhall119|workas long as it's a number18:19
mhall119|work123 works18:19
mhall119|work12abc doesn't18:19
mhall119|workit then assigns the matching value to session_id, which is passed to the view function18:20
mhall119|workso, to view session #1, use the url /session/118:20
mhall119|workto view session #2, use /session/218:20
mhall119|workand to get a form for creating a new session, use /session/018:20
mhall119|workthat is because our view is treating session_id==0 as a special case18:20
ClassBotryanprior45 asked: where do I type /session/1 ?18:21
mhall119|worksorry, that would be at the end of your URL, like http://127.0.0.1:8000/session/118:21
ClassBothemanth asked: does dw+ match words and digit, is it the same logic?18:22
mhall119|workany valid regular expression will work18:22
mhall119|work\d\w+ would work18:23
mhall119|workto match 1abc18:23
mhall119|workfor example18:23
mhall119|workwe also added links to the schedule view to take you to the correct URL18:24
mhall119|workit should look something like this: http://www.growingupfree.org:8001/schedule/18:24
mhall119|workif you look at classroom/templates/schedule_view.html you will see how we're doing this18:25
mhall119|worknow, since views are mapped to url patterns in urls.py, you won't necessarily know what the URL pattern will look like when you're writing your templates and views18:26
mhall119|workto accomodate this, Django has a powerful reverse-lookup ability that when given the name of a view, can give you a URL that it is mapped to18:27
mhall119|workso we use {% url session_view session.id %} to lookup a URL pattern named "session_view" that takes a single argument18:28
mhall119|workDjango then locates the URL pattern, and inlines the argument value you passed18:28
mhall119|workso {% url session_view session.id %} will return /session/1 if session.id==118:28
mhall119|workif we wanted to change you URL pattern to '^classroom/session/(?P<session_id>\d+)'18:29
mhall119|workthen {% url %} would return /classroom/session/118:29
mhall119|workthis makes Django applications very portable, as you can write them without knowing (or caring) how the urls will ultimately be mapped in a given project18:30
mhall119|workany other questions on what we just covered?18:30
mhall119|workalright18:31
mhall119|worknow, while Django is smart enough to validate the format of data, it's doesn't know enough to determine if the value makes logical sense18:32
mhall119|workfor example, when adding a new Session, it wouldn't make sense to create one with an end_time in the past18:32
mhall119|workyou can do this in your view, but if the validation is something that should always exist, it's best to add it to the Form18:33
mhall119|workthat way, is_valid() will run your custom validations, and return false if any one of them raises an exception18:33
mhall119|workrun "bzr pull -r tag:day3.8.1"18:34
mhall119|worknow if you look at classroom/forms.py you will see that I've added a method to our Form classes18:34
mhall119|workDjango looks for methods named "clean_$fieldname" for each $fieldname in the form18:35
mhall119|worksince we are using ModelForms, that means for every field name in the Model itself18:35
mhall119|workso when it is validating the format of the data in 'end_time', it will look for a method called 'clean_end_time', and call it for the final cleaned value18:36
mhall119|workin there, I retrieve the current clean value for the field, and if the Session is new, check that the 'end_time' value exists sometime in the future18:37
mhall119|workif it doesn't, an exception will be raised.  is_valid will return false, and the user will be directed back to the form page, only now the text of the exception will be displayed above the 'end_time' field18:38
mhall119|worknow, that's an easy way for validating an field's value by itself18:38
mhall119|workbut often times you need to validate a field's value when compared to another field's value18:39
mhall119|workfor example, it wouldn't make sense for a session's end_time to come before it's start_time18:39
mhall119|workto do that, we need to implement a 'clean()' method on the form, that will be called after all the 'clean_$fieldname' methods are called18:40
mhall119|workrun "bzr pull -r tag:day3.8.2"18:40
mhall119|workand "bzr diff -r tag:day3.8.1"18:41
mhall119|worknow you will see the clean() method on each of our Form classes18:41
mhall119|workthe first thing I do is get the values for start_time and end_time18:41
mhall119|worknotice that I'm using self.cleaned_data.get('start_time'), rather than self.cleaned_data['start_time']18:42
mhall119|workthat's because of 'start_time' failed validation, it won't be added to self.cleaned_data, but Django will continue to call all clean and clean_fieldname methods anyway18:42
mhall119|workso we need to account for that field not existing in cleaned_data18:43
mhall119|workcalling cleaned_data.get('start_time') will return None if it doesn't exist18:43
mhall119|workcalling cleaned_data['start_time'] will raise a KeyError18:43
mhall119|worknext I check that both 'start_time' and 'end_time' are not None, and then if 'end_time' comes before 'start_time', raise an exception18:44
mhall119|workdon't forget to return self.cleaned_data, otherwise you won't be able to use it in your view, or when calling form.save18:45
mhall119|workany questions so far on forms validation?18:46
mhall119|workalright18:47
mhall119|workin tag:day3.9 I just added an extra table to the schedule view for listing courses, there isn't really anything in it that we haven't already discussed18:47
mhall119|workby now, we can see our data, we can add data, and we can modify data18:48
mhall119|workbut, we can't delete it!18:48
mhall119|workit's time to implement that18:48
mhall119|workrun "bzr pull -r tag:day3.10"18:48
mhall119|workyou will get the new files classroom/templates/session_delete.html and classroom/templates/course_delete.html18:49
mhall119|workyou will also get 2 new view fuctions in classroom/views.py18:49
mhall119|worklet's look at those first18:49
mhall119|worksince we don't need to think about new (unsaved) records when deleting, we just call get_object_or_404 to retrieve the instance of the record we want to delete18:50
mhall119|worknow, it's polite to double check that the user wanted to actually delete something18:51
mhall119|workit's also good policy to not delete things on a GET request18:51
mhall119|workso, if it is a GET request, we first show them a page (course_delete.html or session_delete.html) to warn them about what they are about to do18:52
mhall119|workthis page builds a <form> that will POST back to the view if the user confirms the deleting by clicking the submit button18:52
mhall119|workwhen the view sees a POST method, it will then delete the instance from the database, and redirect the user back to the schedule view18:53
mhall119|workif you look at the view templates for Session and Course, you will see the link added to the bottom to delete that instance18:53
mhall119|workby now your application should look like this: http://www.growingupfree.org:8001/schedule/18:54
mhall119|workyou can add, edit and delete your sessions and courses to your heart's content18:54
mhall119|workand in only 4 hours time too!18:54
mhall119|worknow, there is still much to implement, like access control, a better looking template, etc18:55
mhall119|workand I plan to offer more classes in this series to cover those topics after Ubuntu Opportunistic Developer Week (all of next week)18:56
mhall119|workthis is also a live project: https://launchpad.net/classroom-scheduler18:56
mhall119|workso development will certainly continue on it, even after these classes are over18:56
mhall119|workwell, my time is almost over, are there any questions on today's classes, or any previous ones?18:57
mhall119|workany suggestions or wants for future classes?18:59
mhall119|workokay, well the IRC logs are linked on the launchpad page now18:59
mhall119|workand as always, you can email me if you have any other questions; mhall119@ubuntu.com19:00
ClassBothemanth asked: pre preparation list for the class? {suggestion}19:00
mhall119|workI only had a basic syllabus outline this time19:00
=== ChanServ changed the topic of #ubuntu-classroom to: Welcome to the Ubuntu Classroom - http://wiki.ubuntu.com/Classroom || Support in #ubuntu || Upcoming Schedule: http://is.gd/8rtIi
mhall119|workI will try to prepare a list of required apps to have installed before future classes19:01
mhall119|workis that what you were asking for?19:01
malevmhall119|work: I'm sorry, where do you say are the logs?19:01
mhall119|workhttps://launchpad.net/classroom-scheduler has links to all 4 hours19:01
mhall119|workhemanth: I will make sure I have better setup material next time19:01
malevmhall119|work: and.. is there a wiki?19:02
hemanthmhall119|work, ok :)19:02
mhall119|worknow you guys have a working, useful Django application, start hacking on your own now!19:02
mhall119|workmalev: only a syllabus outline: https://wiki.ubuntu.com/mhall119/classes/LearningDjango19:02
malevmhall119|work: cool!! thanks!19:03

Generated by irclog2html.py 2.7 by Marius Gedminas - find it at mg.pov.lt!