django - tại sao đối tượng request.POST là bất biến?


109

Như tiêu đề đã hỏi, tại sao các anh chàng Django lại quyết định triển khai đối tượng request.POST với một câu truy vấn (tất nhiên, đến lượt nó, làm cho toàn bộ mọi thứ trở nên bất biến?)

Tôi biết bạn có thể xác minh nó bằng cách tạo một bản sao của dữ liệu bài đăng

post = request.POST.copy()

nhưng tại sao làm điều này? Chắc chắn nó sẽ đơn giản hơn nếu chỉ cho phép mọi thứ có thể thay đổi được? Hay nó đang được sử dụng vì một số lý do khác có thể gây ra sự cố?


1
Tại sao bạn muốn nó có thể thay đổi được? Bạn có thể lấy dữ liệu từ nó và sử dụng / sửa đổi nó trong chế độ xem của bạn. Bằng cách thêm dữ liệu vào nó, bạn có thể tạo ấn tượng request.POSTđã được gửi với nhiều dữ liệu hơn thực tế.
Simeon Visser

11
Không phải là tôi muốn nó có thể thay đổi được. Không hơn, nói rằng, tôi muốn kem lạnh. Tuy nhiên, trong trường hợp kem, nếu nó không lạnh, nó sẽ tan chảy và bạn sẽ bị mắng vì đã tạo ra một mớ hỗn độn lớn. Nhưng với đối tượng request.POST ... Ý tôi là, nếu tôi định sửa mã của mình, tôi sẽ làm hỏng nó. Tôi không biết rằng có một số lượng lớn các nhà phát triển thêm dữ liệu vào các đối tượng POST và Gây ra sự cố, vì vậy có vẻ như là một điều kỳ lạ khi nhắm mục tiêu để "sửa chữa".
bharal

Câu hỏi hay; không bao giờ nghĩ về nó thực sự.
Burhan Khalid

1
Điều này xảy ra với tôi không thường xuyên vì khách hàng của tôi đôi khi gửi dữ liệu JSON (có thể thay đổi) và đôi khi là các thông báo được Mã hóa Mẫu URL (không thể thay đổi).
owenfi

2
Đối với những người không nói tiếng Anh, "mutify" không phải là một từ - cụm từ chính xác là "bạn có thể biến đổi nó" hoặc "bạn có thể sửa đổi nó". Cũng không cần phân biệt giới tính của các nhà phát triển - bạn có thể sử dụng "Django team" hoặc "core devs" thay vì "guys".
alexmuller

Câu trả lời:


131

Nó có một chút bí ẩn, phải không? Một số giả thuyết hợp lý hời hợt hóa ra lại sai khi điều tra:

  1. Để POSTđối tượng không phải thực hiện các phương pháp gây đột biến? Số: các POSTđối tượng thuộc các django.http.QueryDictlớp , mà thực hiện một tập hợp đầy đủ các phương pháp đột biến bao gồm __setitem__, __delitem__, popclear. Nó thực hiện tính bất biến bằng cách kiểm tra một cờ khi bạn gọi một trong các phương pháp đột biến. Và khi bạn gọi copyphương thức, bạn sẽ nhận được một QueryDictphiên bản khác với cờ có thể thay đổi được bật.

  2. Để cải thiện hiệu suất? Không: QueryDictlớp không nhận được lợi ích về hiệu suất khi cờ có thể thay đổi bị tắt.

  3. Vì vậy, POSTđối tượng có thể được sử dụng như một khóa từ điển? Không: QueryDictcác đối tượng không thể băm được.

  4. Vì vậy, POSTdữ liệu có thể được xây dựng một cách lười biếng (mà không cần cam kết đọc toàn bộ phản hồi), như đã tuyên bố ở đây ? Tôi thấy không có bằng chứng về việc này trong các mã: như xa như tôi có thể nói, toàn bộ phản ứng luôn đọc, hoặc trực tiếp , hoặc thông qua MultiPartParsercho multipartcâu trả lời.

  5. Để bảo vệ bạn khỏi các lỗi lập trình? Tôi đã thấy điều này được tuyên bố, nhưng tôi chưa bao giờ thấy lời giải thích tốt về những lỗi này là gì và tính bất biến bảo vệ bạn chống lại chúng như thế nào.

Trong mọi trường hợp, POSTkhông phải lúc nào bất biến : khi phản ứng là multipart, sau đó POSTlà có thể thay đổi. Điều này dường như đặt kibosh vào hầu hết các lý thuyết mà bạn có thể nghĩ ra. (Trừ khi hành vi này là một sự giám sát.)

Tóm lại, tôi không thể thấy lý do rõ ràng nào trong Django cho việc POSTđối tượng là bất biến đối với các multipartyêu cầu không .


Tôi đã nhận thấy rất nhiều cạnh thô như thế này ở Django. Mặc dù vậy, hẳn là có ý nghĩa với ai đó ở một thời điểm nào đó.
Dan Passaro

2
Tôi tìm thấy điều này trong một câu trả lời khác của Stack: "Và nó phải là bất biến để có thể được tạo một cách lười biếng. Bản sao buộc lấy tất cả dữ liệu POST. Cho đến khi bản sao, nó có thể không được tìm nạp tất cả. Hơn nữa, đối với WSGI đa luồng máy chủ để làm việc khá tốt, nó rất hữu ích nếu điều này là không thay đổi"
Seaux

12
@Seaux, bạn không nên đọc câu trả lời SO một cách lười biếng khi bạn có ý định bình luận về chúng. ;-)
Chris Wesseling

3
@ChrisWesseling Tôi biết bạn đã làm gì ở đó
Seaux 15/10/14

2
Thậm chí tốt hơn, câu truy vấn có thể thay đổi khi tôi gửi yêu cầu khởi kiện ứng dụng khách thử nghiệm django.
user1158559 Ngày

82

Nếu yêu cầu là kết quả của formviệc gửi Django , thì điều hợp lý là POST immutablephải đảm bảo tính toàn vẹn của dữ liệu giữa quá trình gửi biểu mẫu và xác thực biểu mẫu . Tuy nhiên, nếu yêu cầu không được gửi qua formbản gửi Django , thì POST mutablelà không có xác thực biểu mẫu.

Bạn luôn có thể làm điều gì đó như sau: (theo nhận xét của @ leo-the-manic )

#  .....
mutable = request.POST._mutable
request.POST._mutable = True
request.POST['some_data'] = 'test data'
request.POST._mutable = mutable
# ......

3
@JoshK: Tôi đoán người bình luận muốn làm cho ĐĂNG có thể thay đổi và đoạn mã trong câu trả lời này đã giúp ích.
ShreevatsaR

Bạn có thể thêm khóa, giá trị mới nhưng không thể thay đổi dữ liệu hiện có.
Vamsidhar Muggulla

Đẹp. Và tôi chắc chắn rằng bất cứ ai sử dụng mã này đều biết họ đang làm gì.
John Pang

@VamsidharMuggulla Có thể thêm và thay đổi. Ngay cả việc xóa cũng được phép.
Antony Hatchkins

5

Cập nhật :

Gareth Rees đã đúng khi điểm 1 & 3 không hợp lệ trong trường hợp này. Mặc dù tôi nghĩ rằng điểm 2 và 4 vẫn còn giá trị, do đó tôi sẽ để lại luận văn ở đây.

(Tôi nhận thấy rằng request.POSTđối tượng của cả Kim tự tháp (Pylon) và Django đều là một dạng nào đó MultiDict. Vì vậy, có lẽ đó là một thực tế phổ biến hơn là làm cho request.POSTbất biến.)


Tôi không thể nói thay cho các anh chàng Django, mặc dù đối với tôi, điều đó có thể xảy ra vì một số lý do sau:

  1. Performence . các đối tượng không thể thay đổi "nhanh hơn" so với các đối tượng có thể thay đổi ở chỗ chúng cho phép tối ưu hóa đáng kể. Một đối tượng là bất biến có nghĩa là chúng ta có thể phân bổ không gian cho nó tại thời điểm tạo và các yêu cầu về không gian không thay đổi. Nó cũng có những thứ như hiệu quả sao chép và hiệu quả so sánh vì nó. Chỉnh sửa : đây không phải là trường hợpQueryDictnhư Gareth Rees đã chỉ ra.
  2. Trong trường hợp của request.POST, có vẻ như không có hoạt động nào ở phía máy chủ cần phải thay đổi dữ liệu của yêu cầu . Và do đó, các đối tượng bất biến phù hợp hơn, chưa kể chúng có lợi thế về độ bền đáng kể.
  3. Các đối tượng bất biến có thể được sử dụng làm dictkhóa, mà tôi cho rằng có thể rất hữu ích ở đâu đó trong Django .. Chỉnh sửa : sai lầm của tôi, không thay đổi không trực tiếp ngụ ý có thể băm ; Tuy nhiên, các đối tượng có thể băm cũng thường là bất biến .
  4. Khi bạn chuyển qua request.POST(đặc biệt là các plugin của bên thứ ba trở ra), bạn có thể mong đợi rằng đối tượng yêu cầu này từ người dùng sẽ không thay đổi.

Theo một cách nào đó, những lý do này cũng là câu trả lời chung cho "không thể thay đổi và có thể thay đổi?" câu hỏi. Tôi chắc chắn rằng có nhiều cân nhắc về thiết kế hơn ở trên trong trường hợp Django.


1
Trường hợp cuối cùng thực sự quan trọng. Nó thực sự là về bảo mật. Đây là lý do tại sao Django cung cấp sessionsmột cách ngắn gọn để lấy và sửa đổi dữ liệu giữa các trạng thái.
CppLearner 27/09/12

2
Điểm (1) của bạn không thể là câu trả lời trong trường hợp này, vì POSTlà một QueryDictđối tượng , và những đối tượng này không nhận được lợi ích hiệu suất nào từ việc không thay đổi. Và điểm (3) của bạn không thể là câu trả lời, bởi vì QueryDictcác đối tượng không thể băm, và vì vậy không thể được sử dụng làm khóa từ điển.
Gareth Rees

@GarethRees Cảm ơn bạn đã chỉ ra những điều này. Quả thực tôi đã nhầm. Tôi đã cập nhật câu trả lời của mình để sửa những điều này. Tôi nên chú ý nhiều hơn QueryDicttrước khi trả lời.
KZ

7
@CppLearner Điểm bảo mật có vẻ tranh cãi, ví dụrequests.POST._mutable = True; requests.POST['foo'] = 'bar'; request.POST._mutable = False
Dan Passaro

4

Tôi thích nó là bất biến theo mặc định. Như đã chỉ ra, bạn có thể làm cho nó có thể thay đổi nếu bạn cần nhưng bạn phải rõ ràng về nó. Nó giống như 'Tôi biết rằng tôi có thể biến việc gỡ lỗi biểu mẫu của mình thành một cơn ác mộng nhưng tôi biết mình đang làm gì bây giờ.'


2

Tôi tìm thấy điều này trong một nhận xét trên Stack Answer https://stackoverflow.com/a/2339963

Và nó phải là bất biến để nó có thể được xây dựng một cách lười biếng. Bản sao buộc lấy tất cả dữ liệu POST. Cho đến khi sao chép, nó có thể không được tìm nạp tất cả. Hơn nữa, để một máy chủ WSGI đa luồng hoạt động tốt, sẽ rất hữu ích nếu điều này là bất biến


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.