2

我是 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 中可行吗?

我已经看到了使用像这里这样的包含标签的可能性:在模板中包含视图模板包含和 django 视图/url。他们如何(做/应该)工作?

但这会强制使用固定模板注册自定义模板函数: 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 %}

实现这一目标的最佳方法是什么?

谢谢!

4

2 回答 2

6

尽管这个问题是很久以前提出的,但我一直在寻找同样的功能。

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

我在网上找到了这个片段(自定义模板标签,有关自定义模板标签的信息,请参阅 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 %}

希望它可以帮助某人!

于 2019-06-06T11:47:27.960 回答
4

您将需要使用的是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 %}
于 2013-06-18T21:01:18.420 回答