Django mixin可以继承另一个mixin吗?

时间:2013-08-10 12:12:42

标签: ajax django json django-class-based-views

我很确定这个问题的答案显然是“不”,因为Django mixins应该是<

继承“对象”,但我无法找到解决问题的替代方案:(

为了使问题尽可能简单,,,

views.py

class JSONResponseMixin(object):
    def render_to_response(self, context):
        "Returns a JSON response containing 'context' as payload"
        return self.get_json_response(self.convert_context_to_json(context))

    def get_json_response(self, content, **httpresponse_kwargs):
        "Construct an `HttpResponse` object."
        return http.HttpResponse(content,
                                 content_type='application/json',
                                 **httpresponse_kwargs)

    def convert_context_to_json(self, context):
        "Convert the context dictionary into a JSON object"
        # Note: This is *EXTREMELY* naive; in reality, you'll need
        # to do much more complex handling to ensure that arbitrary
        # objects -- such as Django model instances or querysets
        # -- can be serialized as JSON.
        return json.dumps(context)


class HandlingAJAXPostMixin(JSONResponseMixin):
    def post(self, request, *args, **kwargs):
        .....
        data = {'somedata': somedata}

        return JSONResponseMixin.render_json_response(data)


class UserDetailView(HandlingAJAXPostMixin, DetailView):
    model = MyUser
    .....



所以我遇到的问题是,对于多个视图,我想用相同的方式响应他们的“post”请求

JSON回复。这就是为什么我定义了HandlingAJAXPostMixin以便我可以重复使用它为

其他观点。由于HandlingAJAXPostMixin返回JSON响应,
它需要一个render_json_response方法,该方法在JSONResponseMixin中定义。

这就是为什么我让我的HandlingAJAXPostMixin继承了旧的JSONResponseMixin,但这显然是错误的:( ..

有任何建议......?

感谢!!!

1 个答案:

答案 0 :(得分:4)

mixin从另一个mixin继承是完全有效的 - 事实上,这就是大多数Django更先进的mixin的制作方式。

然而,mixins的想法是它们是可重用的部分,与其他类一起构建一个完整的,可用的类。现在,您的JSONResponseMixin也可能是一个您没有继承的单独类,或者这些方法可能只是模块范围的方法。它确实有效,它没有任何问题,但这不是mixin的想法。

如果您查看Django的BaseDetailView,您会看到以下get()方法:

def get(self, request, *args, **kwargs):
    self.object = self.get_object()
    context = self.get_context_data(object=self.object)
    return self.render_to_response(context)

get_object()get_context_data()BaseDetailView的子类中定义,但render_to_response()不是。 mixin可以依赖于它的超类没有定义的方法,这允许从BaseDetailView继承的不同类提供它们自己的render_to_response()实现。现在,在Django中,只有一个子类。

然而,逻辑被尽可能地委托给mixins提供的那些小的,可重用的方法。这就是你想要的目标。如果尽可能避免/ else逻辑 - Django默认视图中最先进的逻辑是:

if form.is_valid(): 
    return self.form_valid(form) 
else: 
    return self.form_invalid(form)

这就是为什么非常相似的视图,例如CreateViewUpdateView实际上是两个独立的视图,而它们可以很容易地成为具有一些额外的if / else逻辑的单个视图。唯一的区别是CreateView执行self.object = None,而UpdateView执行self.object = self.get_object()

现在您正在使用DetailView定义get()方法,该方法返回self.render_to_response()的结果。但是,您重写render_to_response()以返回JSON响应而不是基于模板的HTML响应。你正在使用一个你不使用的mixin(SingleObjectTemplateResponseMixin),然后覆盖它的行为来做你不想做的事情,只是为了让视图做你想要的做。更好的想法是为DetailView编写替代方案,他的唯一工作就是根据单个对象提供JSON响应。为此,我将创建一个SingleObjectJSONResponseMixin,类似于SingleObjectTemplateResponseMixin,并创建一个类JSONDetailView,将所有需要的mixin组合到一个对象中:

class SingleObjectJSONResponseMixin(object):
    def to_json(context):
        return json.dumps(context)

    def render_to_response(context, **httpresponse_kwargs):
        return HttpResponse(self.to_json(context),
                            context_type='application/json',
                            **httpresponse_kwargs)

class BaseJSONDetailView(SingleObjectMixin, View):
    # if you want to do the same for get, inherit just from BaseDetailView
    def post(self, request, *args, **kwargs):
        self.object = self.get_object()
        context = self.get_context_data(object=self.object)
        return render_to_response(context)

class JSONDetailView(SingleObjectJSONResponseMixin, BaseJSONDetailView):
    """ 
    Return JSON detail data of a single object.
    """

请注意,这几乎与Django提供的BaseDetailViewSingleObjectTemplateResponseMixin完全相同。不同之处在于您定义了一个post()方法,并且只需转换为上下文数据的JSON而不是完整的模板呈现,渲染就更加简单了。但是,逻辑尽可能地保持简单,并且尽可能地分离彼此不相关的方法。这样,SingleObjectJSONResponseMixin可以例如BaseUpdateView。与UpdateView混合以轻松创建基于AJAX / JSON的to_json()。子类可以轻松覆盖mixin的不同部分,例如覆盖render_to_response()以提供特定的数据结构。渲染逻辑就是它所属的位置(在JSONDetailView中)。

现在,您只需创建特定的class UserJSONDetailView(JSONDetailView): model = MyUser 即可创建子类并定义要使用的模型:

{{1}}