Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Django V Rails

Django V Rails

A talk I gave to pybelfast on the 26th October 2016

Stephen McCullough

November 05, 2016
Tweet

More Decks by Stephen McCullough

Other Decks in Programming

Transcript

  1. who am i • Stephen McCullough • @swmcc on the

    interwebs • Senior Software Engineer @ ShopKeep • We are hiring - python/ruby - talk to me after
  2. Translation • models • template • views • URL •

    models • views • controllers • routes django rails
  3. Tools • pypi • pip • pdb • virtualenv •

    rubygems • bundler • debugger • rvm/rbenv django rails
  4. Comparison • generic templates • models • admin interface •

    authentication • south • scaffolding • active record • active admin • devise • migrations django rails
  5. models To create a model in rails you run a

    command rails generate model SomeModel 
 somerow:string class SomeModel < ActiveRecord::Base
 
 end create_table “some_model”, force => true do |t| t.string “somerow” end
  6. models To create a model in django you run a

    command class SomeModel(models.Model):
 somerow = models.CharField() created_at = models.DateTimeField(auto_now_add=True) upcated_at = models.DateTimeField(auto_now=True)
  7. migrations To create a migration in rails you run a

    command rails generate migration AddAnotherThingToSomeModel something_else:string
  8. migrations To create a migration in django you edit model.py

    class SomeModel(models.Model):
 somerow = models.CharField() something_else = models.CharField() created_at = models.DateTimeField(auto_now_add=True) upcated_at = models.DateTimeField(auto_now=True) end python manage.py schemamigration somemodel —auto python manage.py migrate somemodel
  9. queries In rails you can be quite expressive with your

    queries. Client.where(created_at: (Time.now.midnight - 1.day)..Time.now.midnight) Model.where('field >= ?', value) Model.objects.filter(field__gt=value)
  10. controllers In rails the controllers look nice. class OrdersController <

    ApplicationController def index @orders = Order.where(active: true) end def show @order = Order.find(params[:id]) end def new @order = Order.new end def create @order = Order.new(params[:order]) if @order.save redirect_to @order else render 'new' end end end
  11. controllers In django the controllers don’t look so nice. #

    django usually calls the 'show' method 'detail' # the product_id parameter comes from the routing def detail(request, product_id): p = Product.objects.get(pk=product_id) # pk = primary key # renders detail.html with the third parameter passed as context return render(request, 'products/detail.html', {'product': p}) def create(request): # check if form was submitted if request.method == 'POST': # similar to RoR' 'create' action form = ProductForm(request.POST) # A form bound to the POST data if form.is_valid(): # All validation rules pass new_product = form.save() return HttpResponseRedirect(new_product.get_absolute_url()) else: # similar to RoR' 'new' action form = ProductForm() # An empty form return render(request, 'products/create.html', { 'form': form })
  12. controllers In django controllers don’t look so nice. # Supposes

    the routing passed in a parameter called 'pk' # containing the object id and uses it for fetching the object. # Automatically renders the view /products/product_detail.html # and passes product as a context variable to the view. class ProductDetail(DetailView): model = Product # Generates a form for the given model. If data is POSTed, # automatically validates the form and creates the resource. # Automatically renders the view /products/product_create.html # and passes the form as a context variable to the view. class ProductCreate(CreateView): model = Product
  13. views Forms <%= form_tag("/contact", method: "post") do %> <%= label_tag(:subject,

    "Subject:") %> <%= text_field_tag(:subject) %> <%= label_tag(:message, "Message:") %> <%= text_field_tag(:message) %> <%= label_tag(:subject, "Sender:") %> <%= text_field_tag(:sender) %> <%= label_tag(:subject, "CC myself:") %> <%= check_box_tag(:sender) %> <%= submit_tag("Search") %> <% end %>
  14. views Forms class ContactForm(forms.Form): subject = forms.CharField(max_length=100) message = forms.CharField()

    sender = forms.EmailField() cc_myself = forms.BooleanField(required=False) def contact(request): if request.method == 'POST': form = ContactForm(request.POST) if form.is_valid(): return HttpResponseRedirect('/thanks/') # Redirect after POST else: form = ContactForm() # An unbound form return render(request, 'contact.html', { 'form': form }
  15. views Forms class ContactForm(forms.Form): subject = forms.CharField(max_length=100) message = forms.CharField()

    sender = forms.EmailField() cc_myself = forms.BooleanField(required=False) def contact(request): if request.method == 'POST': form = ContactForm(request.POST) if form.is_valid(): return HttpResponseRedirect('/thanks/') # Redirect after POST else: form = ContactForm() # An unbound form return render(request, 'contact.html', { 'form': form }
  16. views Forms <form action="/contact/" method="post"> {{ form.as_p }} <!-- generates

    a form very similar to rails' --> <input type="submit" value="Submit" /> </form>
  17. routing # automatically maps GET /products/:id to products#show # GET

    /products to products#index # POST /products to products#create # DELETE /products/:id to products#destroy # etc. resources :products urlpatterns = patterns('', # matches the detail method in the products controller url(r'^products/(?P\d+)/$', products.views.DetailView.as_view(), name='detail'), # matches the index method, you get the gist url(r'^products/$', products.views.IndexView.as_view(), name='index'), url(r'^products/create/$', products.views.CreateView.as_view(), name='create'), url(r'^products/(?P\d+)/delete/$', products.views.DeleteView.as_view(), name='delete'), )
  18. testing class UsersControllerTest < ActionController::TestCase test "should get index" do

    get :index # GET request to the index action assert_response :success # request returned 200 # assigns is a hash containing all instance variables assert_not_nil assigns(:users) end end class UsersTest(unittest.TestCase): def setUp(self): self.client = Client() def test_index(self): """ should get index """ response = self.client.get(reverse('users:index')) self.assertEqual(response.status_code, 200) self.assertIsNotNone(response.context['users'])
  19. Conclusion • Both are outstanding frameworks • You can’t go

    wrong my picking either one. • I prefer django, marginally • It's not hard to switch from one to another