Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Django e Backbone.js  Uma parceria de sucesso       Thiago Garcia
Quem?
thiagogds14 thiagogds thiagogds thiagogds
Disclaimer
Por que Backbone?
Model
Collection
ViewText
Testes!!• Jasmine.js: http://pivotal.github.com/jasmine/• Jasmine-Jquery: https://github.com/velesin/jasmine-jquery• Sinon...
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"  "http://www.w3.org/TR/html4/loose.dtd"><html><head>  <titl...
describe("Absenteeism", function() {    beforeEach(function() {        this.initial_data = {           atested_begin: "03/...
describe("AbsenteeismModel", function() {    beforeEach(function() {        this.eventSpy = sinon.spy();    });    describ...
describe("AbsenteeismReport View", function() {        beforeEach(function() {            loadFixtures("absenteeism.html")...
Handlebars                               http://handlebarsjs.com/                   var abs_template_html = $(#absenteeism...
var strdt = function(str) {}    return moment(str, "DD/MM/YYYY").toDate();         http://momentjs.com/window.Absenteeism ...
save: function() {    var self = this;    var post_data = {};    var absenteeism = {};    var values = [];    this.collect...
window.Absenteeism = Backbone.Model.extend({        validate: function(attributes) {            var data_inicio_atestado =...
window.AbsenteeismView = Backbone.View.extend({        events: {            click .remove: remove,            blur input[n...
window.AbsenteeismReport = Backbone.View.extend({        events: {            click .add: add_entry,            click .con...
window.AbsenteeismCollection = Backbone.Collection.extend({    model: Absenteeism});
Tá, e o Django?
def save(request):    absenteeism_data = json.loads(request.POST[data])    absenteeism = absenteeism_data[absenteeism]    ...
class AbsenteeismEntryForm(forms.ModelForm):    class Meta:        model = AbsenteeismEntry        exclude = (absenteeism,...
return HttpResponse(json.dumps(dict(url="/success/")),                    mimetype="application/json")
def save(request):    absenteeism_data = json.loads(request.POST[data])    absenteeism = absenteeism_data[absenteeism]    ...
https://github.com/thiagogds/backbone-PyBR-8
Palestra PythonBrasil[8]
Upcoming SlideShare
Loading in …5
×

Palestra PythonBrasil[8]

459 views

Published on

Minha palestra sobre Django e Backbone na PythonBrasil 8

Published in: Technology
  • Be the first to comment

  • Be the first to like this

Palestra PythonBrasil[8]

  1. 1. Django e Backbone.js Uma parceria de sucesso Thiago Garcia
  2. 2. Quem?
  3. 3. thiagogds14 thiagogds thiagogds thiagogds
  4. 4. Disclaimer
  5. 5. Por que Backbone?
  6. 6. Model
  7. 7. Collection
  8. 8. ViewText
  9. 9. Testes!!• Jasmine.js: http://pivotal.github.com/jasmine/• Jasmine-Jquery: https://github.com/velesin/jasmine-jquery• Sinon.js: http://sinonjs.org/• Jasmine-Sinon: https://github.com/froots/jasmine-sinon
  10. 10. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head> <title>Jasmine Spec Runner</title> <link rel="shortcut icon" type="image/png" href="lib/jasmine-1.2.0/jasmine_favicon.png"> <link rel="stylesheet" type="text/css" href="lib/jasmine-1.2.0/jasmine.css"> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script> <script type="text/javascript" src="../underscore-min.js"></script> <script type="text/javascript" src="../handlebars-1.0.0.beta.6.js"></script> <script type="text/javascript" src="../backbone-min.js"></script> <script src="../bootstrap-datepicker.js"></script> <script src="../bootstrap-datepicker.pt-BR.js"></script> <script src="../rrule.js"></script> <script src="../moment.min.js"></script>1 <script type="text/javascript" src="lib/jasmine-1.2.0/jasmine.js"></script> <script type="text/javascript" src="lib/jasmine-1.2.0/jasmine-html.js"></script> <script type="text/javascript" src="lib/sinon-1.5.0.js"></script> <script type="text/javascript" src="lib/jasmine-sinon.js"></script> <script type="text/javascript" src="lib/jasmine-jquery.js"></script> <!-- include source files here... --> <script type="text/javascript" src="../absenteeism.js"></script> <!-- include spec files here... --> <script type="text/javascript" src="spec/AbsenteeismSpec.js"></script> <script type="text/javascript"> (function() { var jasmineEnv = jasmine.getEnv(); jasmineEnv.updateInterval = 1000; var htmlReporter = new jasmine.HtmlReporter(); jasmineEnv.addReporter(htmlReporter); jasmineEnv.specFilter = function(spec) {
  11. 11. describe("Absenteeism", function() { beforeEach(function() { this.initial_data = { atested_begin: "03/01/2012", atested_end: "04/01/2012", revised_begin: "03/01/2012", revised_end: "04/01/2012", }; this.absenteeism = new Absenteeism(this.initial_data); this.absenteeismCollection = new AbsenteeismCollection([this.absenteeism]) this.absenteeismReportView = new AbsenteeismReport({collection: this.absenteeismCollection}) });
  12. 12. describe("AbsenteeismModel", function() { beforeEach(function() { this.eventSpy = sinon.spy(); }); describe("When validating", function() { it("should check that first atested date is lower then second date", function() { this.absenteeism.bind("error", this.eventSpy); this.initial_data["atested_end"] = "01/01/2012"; this.absenteeism.set(this.initial_data); expect(this.eventSpy).toHaveBeenCalledOnce(); expect(this.eventSpy).toHaveBeenCalledWith( this.absenteeism, "Data Final Atestadada não pode ser menor que a Data Inicial Atestada" ); });
  13. 13. describe("AbsenteeismReport View", function() { beforeEach(function() { loadFixtures("absenteeism.html"); }); describe("When rendering", function() { it("should show the correct components", function() { this.absenteeismReportView.render(); var atested_begin = $("input[name=atested_begin]"); var atested_end = $("input[name=atested_end]"); var revised_begin = $("input[name=revised_begin]"); var revised_end = $("input[name=revised_end]"); var dias_negados = $("span.difference"); expect(atested_begin).toHaveValue("03/01/2012"); expect(atested_end).toHaveValue("04/01/2012"); expect(revised_begin).toHaveValue("03/01/2012"); expect(revised_end).toHaveValue("04/01/2012"); }); });
  14. 14. Handlebars http://handlebarsjs.com/ var abs_template_html = $(#absenteeism_form).html(); var abs_template = Handlebars.compile(abs_template_html); $(this.el).html(abs_template(this.model.toJSON()));{% verbatim %}<script id="absenteeism_form" type="text/x-handlebars-template"> <td><button class="close remove">&times;</button></td> <td> <input type="text" name="atested_begin" class="input-small" value="{{ atested_begin }}"><br> <input type="text" name="atested_end" class="input-small" value="{{ atested_end }}"> </td> <td> <input type="text" name="revised_begin" class="input-small" value="{{ revised_begin }}"><br> <input type="text" name="revised_end" class="input-small" value="{{ revised_end }}"> </td></script>{% endverbatim %}
  15. 15. var strdt = function(str) {} return moment(str, "DD/MM/YYYY").toDate(); http://momentjs.com/window.Absenteeism = Backbone.Model.extend({ validate: function(attributes) { var data_inicio_atestado = strdt(attributes.atested_begin); var data_fim_atestado = strdt(attributes.atested_end); var data_inicio_revisado = strdt(attributes.revised_begin); var data_fim_revisado = strdt(attributes.revised_end); if(data_inicio_atestado.getYear() < 0 || data_fim_atestado.getYear() < 0 || data_inicio_revisado.getYear() < 0 || data_fim_revisado.getYear() < 0 ) { return "Data inv̇lida"; } if (data_fim_atestado < data_inicio_atestado) { return "Data Final Atestadada ṇo pode ser menor que a Data Inicial Atestada"; } if (data_fim_revisado < data_inicio_revisado) { return "Data Final Abonada ṇo pode ser menor que a Data Inicial Abonada"; } if (data_inicio_revisado < data_inicio_atestado) { return "Data Incial Abonada ṇo pode ser menor que a Data Inicial Atestada"; } if (data_fim_revisado > data_fim_atestado){ return "Data Final Abonada ṇo pode ser maior que a Data Final Atestada"; } }});
  16. 16. save: function() { var self = this; var post_data = {}; var absenteeism = {}; var values = []; this.collection.each(function(model) { values.push(model.toJSON()); }); absenteeism[adm_obs] = $(this.el).find(textarea[name="adm_obs"]).val(); absenteeism[medical_obs] = $(this.el).find(textarea[name="medical_obs"]).val(); absenteeism[entries] = values; post_data[absenteeism] = absenteeism; $.ajax({ type: POST, url: window.post_url, data: {data: JSON.stringify(post_data)}, success: function(data) { self.process_success(data); }, error: function(data) { self.process_error(data); }, dataType: json });},
  17. 17. window.Absenteeism = Backbone.Model.extend({ validate: function(attributes) { var data_inicio_atestado = strdt(attributes.atested_begin); var data_fim_atestado = strdt(attributes.atested_end); var data_inicio_revisado = strdt(attributes.revised_begin); var data_fim_revisado = strdt(attributes.revised_end); if(data_inicio_atestado.getYear() < 0 || data_fim_atestado.getYear() < 0 || data_inicio_revisado.getYear() < 0 || data_fim_revisado.getYear() < 0 ) { return "Data inv̇lida"; } if (data_fim_atestado < data_inicio_atestado) { return "Data Final Atestadada ṇo pode ser menor que a Data Inicial Atestada"; } if (data_fim_revisado < data_inicio_revisado) { return "Data Final Abonada ṇo pode ser menor que a Data Inicial Abonada"; } if (data_inicio_revisado < data_inicio_atestado) { return "Data Incial Abonada ṇo pode ser menor que a Data Inicial Atestada"; } if (data_fim_revisado > data_fim_atestado){ return "Data Final Abonada ṇo pode ser maior que a Data Final Atestada"; } } });
  18. 18. window.AbsenteeismView = Backbone.View.extend({ events: { click .remove: remove, blur input[name=atested_begin]: update_value, blur input[name=atested_end]: update_value, blur input[name=revised_begin]: update_value, blur input[name=revised_end]: update_value }, tagName: tr, initialize: function() { _.bindAll(this, render); _.bindAll(this, remove); _.bindAll(this, update_value); _.bindAll(this, restore_view); this.model.on(error, this.restore_view); }, render: function() { var abs_template_html = $(#absenteeism_form).html(); var abs_template = Handlebars.compile(abs_template_html); $(this.el).html(abs_template(this.model.toJSON())); var self = this; $(this.el).find(input[type=text]).datepicker({ format: dd/mm/yyyy, autoclose: true, language: pt-BR, }).on(changeDate, function(ev) { self.update_value(ev); }); return this; }, remove: function() { $(this.el).remove(); this.model.collection.remove(this.model); }, update_value: function(event) { var data_inicio_atestado = $(this.el).find(input[name=atested_begin]).val(); var data_fim_atestado = $(this.el).find(input[name=atested_end]).val(); var data_inicio_revisado = $(this.el).find(input[name=revised_begin]).val(); var data_fim_revisado = $(this.el).find(input[name=revised_end]).val(); this.model.set({ atested_begin: data_inicio_atestado, atested_end: data_fim_atestado, revised_begin: data_inicio_revisado, revised_end: data_fim_revisado, }); }, restore_view: function(model, message) { $(this.el).find(input[name=atested_begin]).val(this.model.get(atested_begin)); $(this.el).find(input[name=atested_end]).val(this.model.get(atested_end)); $(this.el).find(input[name=revised_begin]).val(this.model.get(revised_begin)); $(this.el).find(input[name=revised_end]).val(this.model.get(revised_end)); $(#myModal .modal-body p).html(message); $(#myModal).modal(toggle); }, });
  19. 19. window.AbsenteeismReport = Backbone.View.extend({ events: { click .add: add_entry, click .confirm: save, }, el: function () { return $(#main); }, initialize: function() { _.bindAll(this, render); _.bindAll(this, add); _.bindAll(this, add_entry); _.bindAll(this, save); _.bindAll(this, process_success); _.bindAll(this, process_error); this.collection.on(add, this.add); }, render: function() { var view = $(this.el).find(#table_body); this.collection.each(function(model) { var model_view = new AbsenteeismView({model: model}); view.append(model_view.render().el); }); return this; }, add: function(item) { var entry = new AbsenteeismView({model:item}); $(this.el).find(#table_body).append(entry.render().el); }, add_entry: function() { this.collection.add(new_absenteeism()); }, process_success: function (data) { alert(data.message); }, process_error: function (data) { alert(data.responseText); }, save: function() { var self = this; var post_data = {}; var absenteeism = {}; var values = []; this.collection.each(function(model) { values.push(model.toJSON()); }); absenteeism[adm_obs] = $(this.el).find(textarea[name="adm_obs"]).val(); absenteeism[medical_obs] = $(this.el).find(textarea[name="medical_obs"]).val(); absenteeism[entries] = values; post_data[absenteeism] = absenteeism; $.ajax({ type: POST, url: window.post_url, data: {data: JSON.stringify(post_data)}, success: function(data) { self.process_success(data); }, error: function(data) { self.process_error(data); }, dataType: json }); }, });
  20. 20. window.AbsenteeismCollection = Backbone.Collection.extend({ model: Absenteeism});
  21. 21. Tá, e o Django?
  22. 22. def save(request): absenteeism_data = json.loads(request.POST[data]) absenteeism = absenteeism_data[absenteeism] absenteeism_entries = absenteeism[entries] absenteeism.pop(entries)
  23. 23. class AbsenteeismEntryForm(forms.ModelForm): class Meta: model = AbsenteeismEntry exclude = (absenteeism,) def clean(self): super(AbsenteeismEntryForm, self).clean() if self.cleaned_data.get(atested_begin) > self.cleaned_data.get(atested_end): raise forms.ValidationError( uData Final Atestadada não pode ser menor que a Data Inicial Atestada) if self.cleaned_data.get(revised_begin) > self.cleaned_data.get(revised_end): raise forms.ValidationError( uData Final Abonada não pode ser menor que a Data Inicial Abonada) if self.cleaned_data.get(atested_begin) > self.cleaned_data.get(revised_begin): raise forms.ValidationError( uData Incial Abonada não pode ser menor que a Data Inicial Atestada) if self.cleaned_data.get(revised_end) > self.cleaned_data.get(atested_end): raise forms.ValidationError( uData Final Abonada não pode ser maior que a Data Final Atestada) return self.cleaned_data
  24. 24. return HttpResponse(json.dumps(dict(url="/success/")), mimetype="application/json")
  25. 25. def save(request): absenteeism_data = json.loads(request.POST[data]) absenteeism = absenteeism_data[absenteeism] absenteeism_entries = absenteeism[entries] absenteeism.pop(entries) absenteeism_form = AbsenteeismForm(absenteeism) if absenteeism_form.is_valid(): entries_form = [] for entry in absenteeism_entries: entry_form = AbsenteeismEntryForm(entry) if entry_form.is_valid(): entries_form.append(entry_form.cleaned_data) else: return HttpResponseServerError(json.dumps(entry_form.errors), mimetype="application/json") else: return HttpResponseServerError(json.dumps(absenteeism_form.errors), mimetype="application/json") new_absenteeism = absenteeism_form.save() for entry in entries_form: new_absenteeism.absenteeismentry_set.create(**entry) return HttpResponse(json.dumps(dict(message="Salvou com sucesso!")), mimetype="application/json")
  26. 26. https://github.com/thiagogds/backbone-PyBR-8

×