Làm thế nào để nối chuỗi trong mẫu django?


189

Tôi muốn nối một chuỗi trong thẻ mẫu Django, như:

{% extend shop/shop_name/base.html %}

Đây shop_namelà biến của tôi và tôi muốn nối cái này với phần còn lại của đường dẫn.

Giả sử tôi có shop_name=example.comvà tôi muốn kết quả mở rộng shop/example.com/base.html.

Câu trả lời:


379

Dùng với:

{% with "shop/"|add:shop_name|add:"/base.html" as template %}
{% include template %}
{% endwith %}

2
Tôi hoàn toàn bối rối trước câu trả lời này vì nó sử dụng thẻ bao gồm thay vì thẻ mở rộng, nhưng rõ ràng nó chỉ hoạt động. Mặc dù tôi muốn giới thiệu câu trả lời của riêng Ahsan vì nó cũng hoạt động và (theo ý kiến ​​của tôi) đúng hơn về mặt ngữ nghĩa và làm tăng ít nhầm lẫn hơn.
gitaarik

15
Điều này có thể hoạt động nhưng không nên được coi là một câu trả lời chung để nối chuỗi trong các mẫu django. Xem stackoverflow.com/a/23783666/781695
người dùng

Như câu nói trong tài liệu Django, "Các chuỗi có thể được ép buộc với số nguyên sẽ được tóm tắt, không được nối" Vì vậy, ví dụ, nếu bạn muốn ghép các khóa chính của đối tượng mô hình (có thể hữu ích để tạo khóa bộ đệm duy nhất), thì không công việc.
zen11625

Tôi nghĩ rằng điều này không thoát ra được shop_name, vì vậy nó nguy hiểm.
Flimm

Hãy lưu ý, như đã đề cập, điều này chỉ hoạt động với các chuỗi! Nếu bạn dịch shop_nametrước khi chuyển nó sang ngữ cảnh trong một khung nhìn, get_context_datahãy chắc chắn rằng nó được dịch bằng cách sử dụng ugettextthay vì ugettext_lazy.
Kim

111

Không sử dụng addcho chuỗi, bạn nên xác định một thẻ tùy chỉnh như thế này:

Tạo một tệp: <appname>\templatetags\<appname>_extras.py

from django import template

register = template.Library()

@register.filter
def addstr(arg1, arg2):
    """concatenate arg1 & arg2"""
    return str(arg1) + str(arg2)

và sau đó sử dụng nó như @Steven nói

{% load <appname>_extras %}

{% with "shop/"|addstr:shop_name|addstr:"/base.html" as template %}
    {% include template %}
{% endwith %}

Lý do để tránh add:

Theo các tài liệu

Bộ lọc này trước tiên sẽ cố gắng ép buộc cả hai giá trị cho số nguyên ... Các chuỗi có thể được ép buộc thành số nguyên sẽ được tính tổng, không được nối ...

Nếu cả hai biến là số nguyên, kết quả sẽ không như mong đợi.


Không phải đó là @ register.filter (name = 'addstr')?
khóa

6
Điều này nên được đánh dấu là câu trả lời tốt nhất vì hoạt động chính xác với các giá trị có thể được Python ép buộc dưới dạng số nguyên.
zen11625

2
Tôi không biết lý do tại sao bạn không phải là một với hầu hết các "lên" vì nó là của bạn câu trả lời đó là đúng, " add" một mình chỉ không sử dụng str()ở vị trí đầu tiên và không làm việc ở tất cả đối với tôi trong khi giải pháp của bạn hoạt động hoàn hảo
Olivier Pons

1
Câu trả lời của bạn đã cứu tôi!
Ljubisa Livac

6
Hãy nhớ tải bộ lọc tùy chỉnh của bạn ở đầu tệp mẫu của bạn:{% load <appname>_extras %}
Susanne Peng

13

Tôi đã thay đổi hệ thống phân cấp thư mục

/shop/shop_name/base.html Tới /shop_name/shop/base.html

và sau đó dưới đây sẽ làm việc.

{% extends shop_name|add:"/shop/base.html"%} 

Bây giờ nó có thể mở rộng trang base.html.


7

Tham khảo Chuỗi liên kết trong Mẫu Django :

  1. Đối với các phiên bản trước của Django:

    {{ "Mary had a little"|stringformat:"s lamb." }}

"Mary có một con cừu nhỏ."

  1. Khác:

    {{ "Mary had a little"|add:" lamb." }}

"Mary có một con cừu nhỏ."


3

Có một cái nhìn vào addbộ lọc .

Chỉnh sửa: Bạn có thể xâu chuỗi các bộ lọc, vì vậy bạn có thể làm "shop/"|add:shop_name|add:"/base.html". Nhưng điều đó sẽ không hoạt động vì nó phụ thuộc vào thẻ mẫu để đánh giá các bộ lọc trong các đối số và mở rộng thì không.

Tôi đoán bạn không thể làm điều này trong các mẫu.


cái này không hiệu quả tôi muốn thêm biến của tôi ở giữa đường dẫn.
Ahsan

thêm bộ lọc chỉ tóm tắt không được nối theo tài liệu django
Ahsan

Các tài liệu nói rằng "các chuỗi có thể được ép buộc thành số nguyên sẽ được tính tổng". Các chuỗi khác được nối. Nhưng dù sao điều đó cũng không thực sự quan trọng vì bạn không thể sử dụng bộ lọc :(
Daniel Hepper

2

Từ các tài liệu:

Thẻ này có thể được sử dụng theo hai cách:

  • {% extends "base.html" %} (có dấu ngoặc kép) sử dụng giá trị bằng chữ "base.html" làm tên của mẫu chính để mở rộng.
  • {% extends variable %}sử dụng giá trị của biến. Nếu biến ước tính thành một chuỗi, Django sẽ sử dụng chuỗi đó làm tên của mẫu mẹ. Nếu biến ước tính thành một đối tượng Mẫu, Django sẽ sử dụng đối tượng đó làm mẫu chính.

Vì vậy, có vẻ như bạn không thể sử dụng bộ lọc để thao tác đối số. Trong chế độ xem cuộc gọi, bạn phải khởi tạo mẫu tổ tiên hoặc tạo một biến chuỗi với đường dẫn chính xác và truyền nó với ngữ cảnh.


1

Câu trả lời của @ lỗi về cơ bản là đúng, bạn nên sử dụng thẻ mẫu cho việc này. Tuy nhiên, tôi thích một thẻ mẫu chung chung hơn một chút mà tôi có thể sử dụng để thực hiện bất kỳ loại hoạt động nào tương tự như sau:

from django import template
register = template.Library()


@register.tag(name='captureas')
def do_captureas(parser, token):
    """
    Capture content for re-use throughout a template.
    particularly handy for use within social meta fields 
    that are virtually identical. 
    """
    try:
        tag_name, args = token.contents.split(None, 1)
    except ValueError:
        raise template.TemplateSyntaxError("'captureas' node requires a variable name.")
    nodelist = parser.parse(('endcaptureas',))
    parser.delete_first_token()
    return CaptureasNode(nodelist, args)


class CaptureasNode(template.Node):
    def __init__(self, nodelist, varname):
        self.nodelist = nodelist
        self.varname = varname

    def render(self, context):
        output = self.nodelist.render(context)
        context[self.varname] = output
        return ''

và sau đó bạn có thể sử dụng nó như thế này trong mẫu của bạn:

{% captureas template %}shop/{{ shop_name }}/base.html{% endcaptureas %}
{% include template %}

Như nhận xét đề cập, thẻ mẫu này đặc biệt hữu ích cho thông tin có thể lặp lại trong toàn bộ mẫu nhưng yêu cầu logic và những thứ khác sẽ làm hỏng mẫu của bạn hoặc trong trường hợp bạn muốn sử dụng lại dữ liệu được truyền giữa các mẫu thông qua các khối:

{% captureas meta_title %}{% spaceless %}{% block meta_title %}
    {% if self.title %}{{ self.title }}{% endif %}
    {% endblock %}{% endspaceless %} - DEFAULT WEBSITE NAME
{% endcaptureas %}

và sau đó:

<title>{{ meta_title }}</title>
<meta property="og:title" content="{{ meta_title }}" />
<meta itemprop="name" content="{{ meta_title }}">
<meta name="twitter:title" content="{{ meta_title }}">

Tín dụng cho thẻ captureas là do tại đây: https://www.djangosnippets.org/snippets/545/


1

Tôi thấy làm việc với các {% with %}thẻ khá rắc rối. Thay vào đó tôi đã tạo thẻ mẫu sau, sẽ hoạt động trên chuỗi và số nguyên.

from django import template

register = template.Library()


@register.filter
def concat_string(value_1, value_2):
    return str(value_1) + str(value_2)

Sau đó tải thẻ mẫu trong mẫu của bạn ở đầu bằng cách sử dụng như sau:

{% load concat_string %}

Sau đó, bạn có thể sử dụng nó theo cách sau:

<a href="{{ SOME_DETAIL_URL|concat_string:object.pk }}" target="_blank">123</a>

Cá nhân tôi thấy điều này sẽ sạch hơn rất nhiều khi làm việc.


0

Bạn không thể thực hiện thao tác biến trong các mẫu django. Bạn có hai tùy chọn, hoặc viết thẻ mẫu của riêng bạn hoặc thực hiện điều này trong chế độ xem,


yêu cầu của tôi là chỉ làm điều đó trong các mẫu để tùy chọn lượt xem không hữu ích. tôi cũng đã thử qua thẻ mẫu tùy chỉnh nhưng {% load concat%} nên sau thẻ {% extend ....%}. vậy làm thế nào tôi có thể làm điều đó bây giờ?
Ahsan

Viết thẻ Extended_extends chấp nhận định dạng chuỗi và đối số.
Paulo Scardine

Bạn có thể vui lòng cho tôi một ví dụ về cách viết các thẻ tùy chỉnh cho các thẻ mặc định không?
Ahsan

0

extendskhông có cơ sở cho việc này. Hoặc đặt toàn bộ đường dẫn mẫu vào một biến bối cảnh và sử dụng nó hoặc sao chép thẻ mẫu tồn tại và sửa đổi nó một cách thích hợp.


thanx để trả lời! đối với biến bối cảnh tôi phải đặt trong view.py mà tôi không thể do yêu cầu dự án của tôi. và xin cho ví dụ về cái thứ hai.
Ahsan

0

Và nhiều kết nối:

from django import template
register = template.Library()


@register.simple_tag
def concat_all(*args):
    """concatenate all args"""
    return ''.join(map(str, args))

Và trong Mẫu:

{% concat_all 'x' 'y' another_var as string_result %}
concatenated string: {{ string_result }}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.