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

Avatar for Stephen McCullough

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