【问题标题】:Django: How to include a view from within a templateDjango:如何在模板中包含视图
【发布时间】:2013-06-15 05:41:25
【问题描述】:

我是 django 新手,我想知道从模板中包含视图(具有特定逻辑及其生成的 HTML)的最佳/推荐方法是什么。

我的具体例子如下: 我有一个模型:

class City(models.Model):    
    name = models.CharField(max_length=200)        

class Place(models.Model):    
    city = models.ForeignKey(City)
    name = models.CharField(max_length=200)
    state = models.IntegerField()

所以我需要一个视图来显示每个城市及其地点。每个地方都应该根据其状态以不同的方式呈现。每种不同的方式都非常不同,可能需要相当多的业务逻辑。

根据我对其他框架的经验,我设想如下。从城市模板调用将呈现位置的视图,该视图将具有所有必要的逻辑,并会选择使用哪个模板来呈现位置: 示例伪代码:

城市.html

{% for place in places %}    
   {% include_view 'show_place' place %}    
{% endfor %}

include_view 标签将调用视图的位置,该视图将决定给定位置使用哪个模板:

def show_place(request, place):    
    # Here I will probably use more logic to prepare the template.
    template_name = "places/default.html"
    if place.state == 1 :
        template_name = 'places/active.html'
    if place.state == 2 :
        template_name = 'places/started.html'
    if place.state == 3 :
        template_name = 'places/completed.html'
    # etc

    return render(request, template_name, { 'place': place } )

这种方法在 django 中可行吗?

我已经看到了使用包含标签的可能性,例如:Include a view in a templateTemplate includes and django views/urls. How (do/should) they work?

但这会强制使用固定模板注册自定义模板函数: register.inclusion_tag('results.html')(show_results) #这里我需要逻辑,并让'results.html'动态化。

我还希望将 show_place 作为普通视图,以便能够直接访问它。

我也可以执行 IF 来询问模板内的状态并使用 {% include %} 标记,但这将允许我在视图中的其他方法中拥有额外的业务逻辑:

{% for place in places %}    
    {% if place.state = 1 %}    
        {% include 'places/active.html' %}    
    {% if ... }    
                {% include ... }    
{% endfor %}

最好的方法是什么?

谢谢!

【问题讨论】:

    标签: django python-2.7 django-templates django-views


    【解决方案1】:

    您需要使用的是Django Custom Template Tag。你可以简单地在你的模板中传递一个变量给它,然后让它决定在你当前的模板中插入哪个视图和模板。

    一个例子:

    您的自定义模板标签 (rend_item.py)

    def return_template(item):
        template = 'null'
    
        context = {
                #Dictionary of things to pass back
    
        }
        #if statements that choose what 'template' should be
        if item == 5:
            template = 'item5.html'
        else:
            template = 'default.html'
    
        #render the template
        return render_to_string(template, context)
    

    模板

     {# Make sure you load the py file where your template tag is located at the top #}
     {% load rend_item %}
    
          {% for item in cart %}
    
             {{ item|return_template }}         
    
          {% endfor %}
    

    【讨论】:

    • 谢谢!这就是我一直在寻找的。您知道是否有办法将该过滤器作为实际视图?例如,如果我想将生成的 HTML 呈现为 AJAX。在过滤器中也有数据库查询听起来不太好。我试过了,但是 {% load %} 标签在 templatetags 文件夹中查找标签,所以无法在 views.py 文件中进行注册。再次感谢!
    • django 不提供“模板中的视图”。自定义标签尽可能接近。
    【解决方案2】:

    尽管这个问题被问到 相当 不久前,我一直在寻找同样的功能。

    我相信我找到了 JcKelly 帖子的初始问题和后续问题的答案 ->“过滤器作为实际视图”(我假设过滤器意味着渲染)。

    我在网上找到了这个 sn-p(一个自定义模板标签,有关自定义模板标签的信息,请参阅 JcKelley 帖子):

    https://djangosnippets.org/snippets/1568/
    

    对我来说已经过时了。因此,我遵循了它的方法并想出了:

    您的 TemplateTag.py 文件

    from django.template import Library, Node, Variable, TemplateSyntaxError
    from django.conf import settings
    from django.urls import reverse, resolve, NoReverseMatch
    register = Library()
    
    
    class ViewNode(Node):
        def __init__(self, url_or_view, args, kwargs):
            self.url_or_view = url_or_view
            self.args = args
            self.kwargs = kwargs
    
        def render(self, context):
            if 'request' not in context:
                raise TemplateSyntaxError("No request has been made.")
    
            url_or_view = Variable(self.url_or_view).resolve(context)
            try:
                view, args, kwargs = resolve(reverse(url_or_view))
            except NoReverseMatch:
                view, args, kwargs = resolve(url_or_view)
    
            try:
                if callable(view):
                    self.args += args
                    self.kwargs.update(**kwargs)
                    return (view(context['request'], *self.args, **self.kwargs)
                            .rendered_content)
                raise "%r is not callable" % view
            except:
                if settings.DEBUG:
                    raise
            return None
    
    
    @register.tag(name='view')
    def do_view(parser, token):
        args, kwargs, tokens = [], {}, token.split_contents()
        if len(tokens) < 2:
            raise TemplateSyntaxError(
                f"{token.contents.split()[0]} tag requires one or more arguments")
    
        for t in tokens[2:]:
            kw = t.find("=")
            args.append(t) if kw == -1 else kwargs.update({str(t[:kw]): t[kw+1:]})
        return ViewNode(tokens[1], args, kwargs)
    

    您的 Template-file.html -> 使用示例

    使用视图的路径名, (有关路径名的信息,请参阅 https://docs.djangoproject.com/en/2.2/topics/http/urls/#naming-url-patterns):

         {% view "mymodule:inner" %}
         {% view "mymodule:inner" "value" %}
         {% view "mymodule:inner" keyword="value" %}
         {% view "mymodule:inner" arg_expr %}
         {% view "mymodule:inner" keyword=arg_expr %}
    

    使用 URL(或评估为 URL 的东西):

         {% view "/inner" %}
         {% view url_expr %}
    

    希望它可以帮助某人!

    【讨论】:

    • 谢谢 - 这正是我所需要的。不知道为什么,但我无法获得需要参数来解析的基于类的视图。将解析后的 url 传递给视图虽然有效: {% url "app:update_thing" pk=object.id as this_url %} {% view this_url %}
    猜你喜欢
    • 2013-02-17
    • 2017-10-30
    • 2011-08-18
    • 2014-03-12
    • 2010-10-28
    • 2015-07-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多