In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-23 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article will explain in detail how to make an in-depth technical comparison between Rails and Django. The content of the article is of high quality, so the editor will share it with you for reference. I hope you will have a certain understanding of the relevant knowledge after reading this article.
I would like to start with a disclaimer. I have been using Django to develop websites for three years, and as we all know, I like Django. I have written an open source application (app), and I have sent patches to Django. However, I wrote this article as fairly as possible, and this article has both praise and criticism of this framework.
I did a project with Ruby on Rails in college six months ago and have been doing it all the time. One of the things I did was carefully study the two frameworks and compare them, but I remember being very discouraged at that time. When I look for these questions (for example, "how does database migration work for both?" , "what's the difference in their grammar?" , "how is user authentication done"), I compared the two from a higher point of view and found that most of them were very superficial. The following comments will answer these questions and compare how each web framework operates models, controllers, views, and tests.
Brief introduction
Both frameworks are designed for faster development of web applications and better organization of code. They all follow the MVC principle, which means that domain (model layer) modeling, application presentation (view layer) and user interaction (control layer) are all separated from each other. Incidentally, Django actually only considers the framework to do the work of the control layer, so Django itself claims to be a model-template-view (model-template-view) framework. The template of Django can be understood as a view, and the view can be regarded as the control layer in a typical MVC scenario. I will use standard MVC terminology in this article.
Ruby on Rails
Ruby on Rails (RoR) is a web development framework written in Ruby, and Ruby "famous" is often attributed to it. Rails emphasizes that convention is bigger than configuration and testing. Rails's convention greater than configuration (CoC) means that there are almost no configuration files, only implementing agreed directory structure and naming conventions. It hides a lot of magic everywhere: it automatically introduces, automatically passes controller entities to the view layer, and a lot of things such as template names can be automatically inferred by the framework. This means that developers only need to specify unagreed parts of the application, and the result is clean and short code.
Django
Django is a web development framework written in Python and named after guitarist Django Reinhardt. The motivation for Django's emergence lies in "the intensive deadlines of the product department and the strict requirements of the experienced Web developers who developed it." Django follows a rule that makes it clear that it is better than obscure metaphors (a core Python principle), and the result is that even for those who are not familiar with the framework, the code is very readable. The Django in the project is organized around app. Each app has its own model, controller, view, and test settings, thus acting like a small project. The Django project is basically a collection of small app, each app responsible for a specific subsystem.
Model (Model)
Let's start by looking at how each framework handles the MVC principle. The model describes what the data looks like and contains business logic.
Create a model
Rails creates the model by running a command in the terminal.
Rails generate model Product name:string quantity_in_stock:integer category:references
This command automatically generates a migration and an empty model file, which looks like this:
Class Product
< ActiveRecord::Base end 由于我有Django的技术背景, 令我很生气的一个事实就是我不能只通过模型文件就了解到一个模型有哪些字段. 我了解到Rails基本上只是将模型文件用于业务逻辑,而把模型长什么样存到了一个叫做 schemas.rb 的文件中. 这个文件会在每次有迁移运行时被自动更新. 如果我们看看该文件,我们可以看到我们的 Product 模型长什么样子. create_table "products", :force =>True do | t | t.string "name", t.integer "quantity_in_stock", t.integer "category_id", t.datetime "created_at",: null = > false t.datetime "updated_at",: null = > false end
You can see two additional properties in this model. Created_at and updated_at are two attributes that are automatically added to each model in Rails.
In Django, the model is defined in a file called models.py. The same Product model might look like this
Class Product (models.Model): name = models.CharField () quantity_in_stock = models.IntegerField () category = models.ForeignKey ('Category') created_at = models.DateTimeField (auto_now_add=True) # set when it's created updated_at = models.DateTimeField (auto_now=True) # set every time it's updated
Note that we must explicitly (that is, manually) add created_at and updated_at attributes in Django. We also tell Django how the behavior of these properties is defined through the parameters auto_now_add and auto_now.
Model (Model) field default values and foreign keys
Rails will allow the field to be empty by default. As you can see in the example above, all three fields we created are allowed to be empty. The reference field category will also create neither an index nor a foreign key constraint. This means that referential integrity cannot be guaranteed. The field default value for Django is exactly the opposite. No field is allowed to be empty unless explicitly set. Django's ForeignKey automatically creates a foreign key constraint and index. Although the development of Rails here may be out of performance concerns, I will be on the side of Django, which I believe can avoid (unexpected) bad design and unexpected situations. For example, there was a student in our project who did not realize that all the fields he created were allowed to be null as default values. After a while, we found that some of our tables contained data that was meaningless, such as a poll using null as the title. Since Rails does not add foreign keys, in our example, we can delete a category that continuously references other products that will have invalid references. One option is to use a third-party application to add support for automatic creation of foreign keys.
Migration (Migrations)
Migration allows the schema of the database (schema) to be changed again after creation (in fact, everything in Rails uses migration, even if it is created). I have to admire Rails's support for this feature for a long time. The work is done by using Rails's generator (generator).
$rails generate migration AddPartNumberToProducts part_number:string
This adds a new field called part_number (field) to the Product model (model).
However, Django can only support migration through a third-party library called South. I feel that South's approach is more concise and practical. The corresponding migration work above can directly edit the definition of the Product model and add new fields.
Class Product (models.Model):... # Old field part_number = models.CharField ()
And then call
$python manage.py schemamigration products-auto
South automatically recognizes a new field to add to the Product model and creates a migration file. The following command is then called to complete the synchronization (synced)
$python manage.py migrate products
Django eventually integrated South and supported migration in its version 1.7.
Execute query
Thanks to object-relational mapping (object-relation mapping), you don't need to write a single line of SQL statements in any framework. Thanks to Ruby expressions, you can write range search queries (range query) gracefully. .
Client.where (created_at: (Time.now.midnight-1.day).. Time.now.midnight)
This will query the Clients that was created yesterday. Python does not support extremely readable and concise syntax like 1.day, nor does it support.. Range operator. However, sometimes I feel like I'm writing a pre-statement (prepared statement) when I write Rails. For example, in order to select all the rows where a field is greater than a certain value, you have to do something like this
Model.where ('field > =?', value)
The way Django is done is not very good, but from my point of view, it is more brief. The corresponding code in Django is as follows:
Model.objects.filter (field__gt=value) Controller (Controller)
The job of the controller is to use the request to return an accurate response. The typical job of web applications is to support the addition, editing, deletion and display of specific resources, while the convenience of RoR is to make the work of developing controllers simple and intimate. The controller is split into several methods (method), each representing a specified action (action) (show for requesting a resource, new for displaying the form for creating the resource, and create for receiving POST data from the new and actually creating the resource). The controller's instance variable (prefixed with @) is automatically passed to the view (view), and the Rails identifies which template (template) should be used as the view from the method name.
Class ProductsController
< ApplicationController # 自动渲染views/products/show.html.erb def show # params是包含请求变量的ruby hash # 实例变量会自动被传递给视图 @product = Product.find(params[:id]) end # 返回空的product,渲染views/products/new.html.erb def new @product = Product.new end # 接收用户提交的POST数据。多数来至于在'new'视图中表单 def create @product = Product.new(params[:product]) if @product.save redirect_to @product else # 重写渲染create.html.erb的默认行为 render "new" end end end Django使用两种不同的方式实现控制器。你可以使用一个方法来实现每个动作,与Rails做法非常相似,或者你可以为每个控制器动作创建一个类。 Django没有区分new和create方法,资源的创建和空资源的创建发生在同一个控制器中。也没有便捷的方法命名你的视图。视图变量需要从控制器显式的传递,而使用的模板文件也需要显式的设置。 # django通常称 'show' 方法为'detail' # product_id 参数由route传递过来 def detail(request, product_id): p = Product.objects.get(pk=product_id) # pk 表示主键 # 使用传递的第三个参数作为内容渲染detail.html return render(request, 'products/detail.html', {'product': p}) def create(request): # 检查表单是否提交 if request.method == 'POST': # 类似于RoR的 'create' 动作 form = ProductForm(request.POST) # 绑定于POST数据的表单 if form.is_valid(): # 所有的验证通过 new_product = form.save() return HttpResponseRedirect(new_product.get_absolute_url()) else: # 类似于RoR的 'new' 动作 form = ProductForm() # 空的表单 return render(request, 'products/create.html', { 'form': form }) 在以上Django的例子中代码数量与RoR相比很明显。Django似乎也注意到这个问题,于是利用继承和mixin开发出了第二种实现控制器的方法。第二种方法称为基于类的视图(class-based views) (注意, Django称这个控制器为view),并且在Django 1.5中引入以提高代码重用。很多常用的动作都存在可被用来继承的类,比如对资源的显示,列表,创建和更新等,这大大简化了代码开发。重复的工作比如指定将被使用的视图文件名称,获取对象并向view传递该对象等工作也会被自动完成。上面相同的例子使用这种方式只有四行代码。 # 假设route传递了名为 'pk' 的参数,包含对象的 id 并使用该id获得对象。 # 自动渲染视图 /products/product_detail.html # 并将product作为上下文(context)变量传递给该视图 class ProductDetail(DetailView): model = Product # 为给定的模型生成表单。如果得到POST数据 # 自动验证表单并创建资源。 # 自动渲染视图 /products/product_create.html # 并将表单作为上下文变量传递给视图 class ProductCreate(CreateView): model = Product 当控制器比较简单时,使用基于类的视图(class-based views)通常是***的选择,因为代码会变得紧密,具有可读性。但是,取决于你的控制器的不标准(non-standard)程度,可能会需要重写很多函数来得到想要的功能。常遇到的情况就是程序员想向视图传递更多的变量,这时可以重写get_context_data函数来完成。你是不是想按照当前对象(模型实例)的特定的字段来渲染不同的模板?你只好重写render_to_response函数。你想不想改变获得对象的方式(默认是使用主键字段pk)?你只好重写get_object。例如,如果我们想要通过产品名称选择产品而不是id,也要把类似的产品传递给我们的视图,代码就有可能像这样: class ProductDetail(DetailView): model = Product def get_object(self, queryset=None): return get_object_or_404(Product, key=self.kwargs.get('name')) def get_context_data(self, **kwargs): # 先调用基类函数获取上下文 context = super(ProductDetail, self).get_context_data(**kwargs) # 在相关产品(product)中添加 context['related_products'] = self.get_object().related_products return context视图 Rails 视图使用 内置的Ruby 模板系统,它可以让你在你的模板里面编写任意的Ruby代码. 这就意味着它非常强大和快速, 而非常强大的同时就意味着非常大的责任. 你不得不非常小心的不去把表现层同任何其它类型的逻辑混在一起. 这里我需要再次提到涉及一位学生的例子. 一位新同学加入了我们的RoR项目,并且在学习一项新特性. 代码审查的时间到了. 我们首先从控制器开始,***件令我吃惊的事情是他写的控制器里面代码非常少. 我转而很快去看看他写的视图,看到了大块混着HTML的ruby代码. 诚然,Rails并不会嫌弃缺乏经验的程序员,但我的观点是框架可以帮助开发者避免一些坏的实践. 例如 Django 就有一个非常简洁的 模板语言. 你可以进行if判断以及通过for循环进行迭代,但是没有方法选择没有从控制器传入的对象,因为它并不会执行任意的Python表达式. 这是一个我认为可以敦促开发者方向正确的设计决定. 这能让我们项目中的新手找到组织他们代码的正确方式. 资源: CSS, Javascript 以及 图片 Rails 有一个很不错的内置 资源管道. Rails 的资源管道具有对JavaScript和CSS文件进行串联、最小化和压缩的能力. 不仅仅如此,它也还支持诸如 Coffeescript, Sass 和 ERB 等其它语言. Django 对资源的支持同Rails相比就显得相形见绌了,它把要麻烦都丢给了开发者去处理. Django 唯一提供的就是所谓的 静态文件, 这基本上就只是从每个应用程序那里将所有的静态文件集合到一个位置. 有一个叫做 django_compressor 的第三方app提供了一种类似于Rails的资源管道的解决方案. 单(Forms) 网络应用中的表单是用户输入(input)的界面。在Rails中的表单包含在视图中直接使用的帮助方法(method)。 像subject,message这样的输入字段可以在控制器中通过ruby哈希 (类似字典的结构)params来读取,比如params[:subject]和params[:message]。Django通过另一种方式抽象了表单概念。表单封装了字段并包含验证规则。它们看起来像是模型。 class ContactForm(forms.Form): subject = forms.CharField(max_length=100) message = forms.CharField() sender = forms.EmailField() cc_myself = forms.BooleanField(required=False) Django会将CharField解析为对应HTML元素的文本输入框,将BooleanField解析为单选框。你可以按照自己的意愿使用 widget 字段更换为其他输入元素。Django的表单会在控制器中实例化。 def contact(request): if request.method == 'POST': form = ContactForm(request.POST) if form.is_valid(): return HttpResponseRedirect('/thanks/') # POST之后重定向 else: form = ContactForm() # An unbound form return render(request, 'contact.html', { 'form': form }) Django会自动添加验证信息。默认情况下所有的字段都是必须的,除非特意定义(比如cc_myself)。使用上面的代码片段,如果表单验证失败,带有错误信息的表单会自动重新显示,已经输入的内容也会显示。下面的代码在视图中显示显示了一个表单。 {{ form.as_p }} URL 和 Route Route 是将特定的URL匹配到指定控制器的工作。Rails建立REST网络服务非常轻松,而route以HTTP的行为(verbs)来表达。 get '/products/:id', to: 'products#show' 以上的例子显示,向/products/any_id发起的GET请求会自动route到products控制器和show动作(action)。感谢惯例优先原则(convention-over-configuration),对于建立包含所有动作(create,show,index等等)的控制器的这种常见任务,RoR建立了一种快速声明所有常用route的方法,叫做resources。如果你依照Rails的惯例(convention)命名了控制器的方法时这会很方便。 # 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 Django不是通过HTTP的行为来决定route。而是使用更复杂的使用正则表达式来匹配URL和对应的控制器。 urlpatterns = patterns('', # 在products控制器中匹配具体方法 url(r'^products/(?P\d+)/$', products.views.DetailView.as_view(), name='detail'), # 匹配index方法就获得了主页 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'), ) 由于使用了正则表达式,框架会自动使用单纯的验证。请求/products/test/会因匹配不到任何route而返回404,因为test不是正确的数字。不同的哲学思想在这里又一次出现。Django在命名控制器动作方面确实方便一些,以至于Django就没有像Rails的resource那样方便的助手,而且每个route必须显式的定义。这将导致每个控制器需要若干个route规则。 测试 在Rails中测试很轻松,与Django比较起来更需要着重强调。 Fixture 两个框架以相似的方式都支持fixture(示例数据)。我却给Rails更高的评价,因为它更实用,能从文件的名称得知你在使用哪个模板。Rails使用YAML格式的fixture,这是人类可读的数据序列化格式。 # users.yml (Rails当前知道我们在使用user的fixtures) john: name: John Smith birthday: 1989-04-17 profession: Blacksmith bob: name: Bob Costa birthday: 1973-08-10 profession: Surfer 所有的fixture会自动加载而且在测试中可以作为本地变量来访问。 users(:john).name # John Smith Django也支持YAML格式的fixture但是开发人员更倾向于使用JSON格式。 [ { "model": "auth.user", "fields": { "name": "John Smith", "birthday": "1989-04-17", "profession": "Blacksmith", } }, { "model": "auth.user", "fields": { "name": "Bob Costa", "birthday": "1973-08-10", "profession": "Surfer", } } ] 这没什么吸引力,注意它有多啰嗦,因为你必须显式的定义它属于哪个模板,然后在 fields下面列出每个字段。 测试模板 在单元测试模板时两种框架的方式基本一致。使用一组不同类型的断言来进行确定,比如assert_equal,assert_not_equal,assert_nil,assert_raises等等。 class AnimalTest < ActiveSupport::TestCase test "Animals that can speak are correctly identified" do assert_equal animals(:lion).speak(), 'The lion says "roar"' assert_equal animals(:cat).speak(), 'The cat says "meow"' end end 类似功能的代码在Django非常相似。 class AnimalTestCase(TestCase): def test_animals_can_speak(self): """Animals that can speak are correctly identified""" # no way of directly accessing the fixtures, so we have to # manually select the objects lion = Animal.objects.get(name="lion") cat = Animal.objects.get(name="cat") self.assertEqual(lion.speak(), 'The lion says "roar"') self.assertEqual(cat.speak(), 'The cat says "meow"')测试控制器(controller) Rails又因为它魅力而更胜一筹。Rails 使用类名称来决定哪个控制器正在被测试,而测试某个特定动作(action)就像调用http_verb :action_name一样简单。我们看一下例子。 class UsersControllerTest < ActionController::TestCase test "should get index" do get :index # 向index 动作发起GET请求 assert_response :success # 请求返回200 # assigns是包含所有实例变量的hash assert_not_nil assigns(:users) end end 上面的代码很容易理解正在发生什么。***行测试模拟了向 User控制器的 index动作发起一个请求。第二行随后检查请求是否成功(返回代码200-299)。 assigns是一个hash,包含了传递到视图(view)的实例变量。所以第三行检查是否存在名为 users的实例变量并且值不是 nil。 也有一些类似于assert_difference 这样方便的断言帮助方法。 # assert_difference检查被测试的数字在开始和结束之间是否更改 assert_difference('Post.count') do # 创建post post :create, post: {title: 'Some title'} end 在Django中测试控制器可以通过使用一个叫 Client类来完成,它扮演着虚拟浏览器(dummy web browser)的角色。下面是Django中对应的代码。 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']) 首先我们必须在测试设置时初始化 Client。 test_index的***行模拟了向 Users控制器的 index动作申请了一个 GET请求。 reverse查找对应index动作的URL。注意代码是如此冗余并且没有类似于 assert_response :success的帮助方法。 response.context包含我们传递给视图的变量。 很显然Rails的magic是相当有帮助的。Rails/Ruby同时也拥有很多第三方app,比如factory_girl,RSpec,Mocha,Cucumber,这使得编写测试是一种乐趣。 工具和其他特征依赖性管理(Dependency management) 两种框架都有出色的依赖性管理工具。Rails使用 Bundler 来读取Gemfile文件并跟踪文件中对应ruby应用程序运行所依赖的gem。 gem 'nokogiri' gem 'rails', '3.0.0.beta3' gem 'rack', '>= 1.0 'gem' thin','~ > 1.1'
Simply add a new line to the Gemfile file to add the dependency (Dependency). You can install all the required gem by simply calling the following command:
Bundle install
Django strongly recommends using virtualenv to isolate the Python environment. Pip is used to manage python packages. The installation of a separate python package can be done with the following command:
Pip install django-debug-toolbar
Project dependency files can be grouped together by:
Pip freeze > requirements.txt administrative commands
Basically every project has the same management work to do when it is completed, such as precompiled files (precompiling assets), clean records (log), and so on. Rails uses Rake to manage these tasks. Rake is very flexible and makes development tasks simple, especially those that depend on other tasks.
Desc "eat the food. You need to cook (Cooks) and set a form (table) before eating." Task eat: [: cook,: set_the_table] do # before eating delicious food,: cook and: set_the_table need to finish # which part of the code to eat can be written here end
Rake tasks can have prerequisites (prerequisite). For tasks called eat above, you must run task cook and task set_the_table before execution. Rake also supports namespaces (namespace), which can combine the same tasks into group. To execute a task, simply call the name of the task:
Rake eat
Django management commands are less flexible and do not support prerequisites and namespaces. Although the task will be completed eventually, it is not very good.
Class Command (BaseCommand): help = 'eat the food' def handle (self, * args, * * options): call_command ('cook') # here is how to call the management command set_the_table () in the code # but the subtasks need to be regular python functions # here are the eating codes
If we save the above to eat.py, we can call it as follows:
Python manage.py eat internationalization and localization
The internationalization of China is a little weak in Rails. In the folder config/locales, the translation string is defined as a ruby hash in the file.
# config/locales/en.yml en: # the language identifier greet_username: "Hello,% {user}!" # translation_key: "value" # config/locales/pt.yml pt: greet_username: "Ol á,% {user}!"
It is translated by the function t. The function * variables are the key (such as greet_username) that determines which string needs to be used. Rails automatically chooses the correct language.
T ('greet_username', user: "Bill") # Hi, Bill or Ol á, Bill
I find it cumbersome to deal with key names and manual registration in local language files. Django packages it into a very convenient gettext. Translation is also done through a helper function (ugettext), but this time the key is the string itself that does not need to be translated.
Ugettext ('Hi,% (user) s.')% {'user':' Bill'} # Hi, Bill or Ol á, Bill
Django examines all the source code and calls the following command to automatically collect the strings to be translated:
Django-admin.py makemessages-a
The above command will generate a file for each language you want to translate. The contents of the file might look like this:
# locale/pt_BR/LC_MESSAGES/django.po msgid "Hi,% (user) s." # key msgstr "Ol á,% (user) s" # value (translation)
Notice that I have populated the translation in msgstr (those are originally empty). Once the translations are complete, they must be compiled.
Django-admin.py compilemessages
This approach to localizing projects is actually more practical because you don't need to consider the name of key and you don't need to look it up when you need it.
That is, there is no need to customize the key,django will replace the whole sentence as a key value.
User authorization
I have to say that I was somewhat shocked when I learned that RoR (Ruby on Rails) did not package any form of user license. I can't think of any projects that don't require authorization and user management. The gem in this respect is devise, and there is no doubt that it is also on Rails, which has half the score of Rails on Github.
Although Django packaged the authorization framework from the beginning, the flexibility of this authorization method did not improve until a year ago, when version 1.5 was released with a configurable user model (user model). Previously, you were forced to use Django to define users, rather than arbitrarily changing fields or adding fields (field). Now that this is no longer a problem, you can replace the original model with a user model defined by yourself.
Third-party library
There's nothing to say here. Many third-party libraries available to both have been mentioned in this article, and both have too much app. Django Packages is a very good website that can be used to search Django's App. However, no similar website has been found on Rails.
Community
Although I don't have more specific data to prove it, I'm pretty sure that Rails has a larger community. RoR scored twice as much as Django on Github. There are also twice as many problems marked as Rails on Stackoverflow. And it seems that RoR has more jobs than Django (241 versus 58 in the Stackoverflow profession). Rails is huge and has many fascinating resources to learn, such as Rails Casts and Rails for Zombies. Django has Getting Started with Django but no comparability. I know Django uses The Django Book, but it's years behind. Don't think I'm wrong, although there are many Django groups and if you have a problem, you can easily find the answer through google, but Django is not as big as Rails.
Conclusion
Both Ruby on Rails and Django are excellent frameworks for web development. In the development of modular and concise code, in reducing development time. I can't do without ORM framework, template engine and session management system. So the question is, how do I choose?
There is nothing wrong with choosing any one. My advice is usually to use both and choose the one that suits you best. The final decision will depend on which language or principle you prefer: convention first principle (convention-over-configuration,CoC) or explicit priority implicit principle (explicit is better than implicit). Using CoC, you can automatically load (import), and the controller instance is automatically passed to the view and easy to write tests. Using explicit precedence implicit gives you a clear idea of what the code is doing, even for those who are not familiar with the framework.
From my personal experience, I prefer Django. I like the explicitness of Python, the forms of Django, and the more defensive framework (limited template language, null is not available by default in the model field). But I also know that more people can't live without Rails's magic and its excellent test environment.
This is the end of the in-depth technical comparison between Rails and Django. I hope the above content can be helpful to you and learn more knowledge. If you think the article is good, you can share it for more people to see.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.