设为首页收藏本站

LUPA开源社区

 找回密码
 注册
文章 帖子 博客
LUPA开源社区 首页 业界资讯 技术文摘 查看内容

Rails和Django的深度技术对比

2015-1-19 14:51| 发布者: joejoe0332| 查看: 6699| 评论: 0|原作者: Ev4n, LeoXu, chxm1990, BruceLinxu, edwardlu_|来自: oschina

摘要: 6个月以前我在大学用Ruby on Rails做 了一个项目而且一直做到现在。我做地第一件事就是仔细地学习了这两个框架并对它们进行了比较,但是我记得当时我很泄气的。当我寻找这些问题(比如说:”对 于这两者来说,数据库 ...


  Django使用两种不同的方式实现控制器。你可以使用一个方法来实现每个动作,与Rails做法非常相似,或者你可以为每个控制器动作创建一个类。 Django没有区分new和create方法,资源的创建和空资源的创建发生在同一个控制器中。也没有便捷的方法命名你的视图。视图变量需要从控制器显式的传递,而使用的模板文件也需要显式的设置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# django通常称 'show' 方法为'detail'
# product_id 参数由route传递过来
def detail(request, product_id):
    = 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传递该对象等工作也会被自动完成。上面相同的例子使用这种方式只有四行代码。

1
2
3
4
5
6
7
8
9
10
11
12
# 假设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,也要把类似的产品传递给我们的视图,代码就有可能像这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
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)。

1
2
3
4
5
6
7
8
9
10
11
<%= 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 %>

像subject,message这样的输入字段可以在控制器中通过ruby哈希 (类似字典的结构)params来读取,比如params[:subject]和params[:message]。Django通过另一种方式抽象了表单概念。表单封装了字段并包含验证规则。它们看起来像是模型。

1
2
3
4
5
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的表单会在控制器中实例化。

1
2
3
4
5
6
7
8
9
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)。使用上面的代码片段,如果表单验证失败,带有错误信息的表单会自动重新显示,已经输入的内容也会显示。下面的代码在视图中显示显示了一个表单。

1
2
3
4
<form action="/contact/" method="post"
{{ form.as_p }} <!-- 生成类似于rails的表单 -->
<input type="submit" value="Submit" />
</form>

URL 和 Route

Route 是将特定的URL匹配到指定控制器的工作。Rails建立REST网络服务非常轻松,而route以HTTP的行为(verbs)来表达。

1
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)命名了控制器的方法时这会很方便。

1
2
3
4
5
6
# 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和对应的控制器。

1
2
3
4
5
6
7
8
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规则。



酷毙

雷人

鲜花

鸡蛋

漂亮
  • 快毕业了,没工作经验,
    找份工作好难啊?
    赶紧去人才芯片公司磨练吧!!

最新评论

关于LUPA|人才芯片工程|人才招聘|LUPA认证|LUPA教育|LUPA开源社区 ( 浙B2-20090187 浙公网安备 33010602006705号   

返回顶部