TL; DR - Hiện tại không có cách nào để làm như vậy, thiếu tạo một cặp tùy chỉnh Serializer
/Deserializer
.
Vấn đề với các mô hình có quan hệ chung là Django không thấy target
như một lĩnh vực nào cả, chỉ target_content_type
và target_object_id
, và nó cố gắng serialize và deserialize chúng riêng rẽ.
Các lớp chịu trách nhiệm tuần tự hóa và deserializing mô hình Django nằm trong các mô-đun django.core.serializers.base
và django.core.serializers.python
. Tất cả những người khác (xml
, json
và yaml
) mở rộng một trong hai (và python
kéo dài base
). Serialization lĩnh vực được thực hiện như thế này (đường không liên quan Bỏ qua phần):
for obj in queryset:
for field in concrete_model._meta.local_fields:
if field.rel is None:
self.handle_field(obj, field)
else:
self.handle_fk_field(obj, field)
Đây là biến chứng đầu tiên: chìa khóa nước ngoài ContentType
được xử lý ok, với các phím tự nhiên như chúng ta mong đợi. Nhưng PositiveIntegerField
được xử lý bởi handle_field
, đó là thực hiện như thế này:
def handle_field(self, obj, field):
value = field._get_val_from_obj(obj)
# Protected types (i.e., primitives like None, numbers, dates,
# and Decimals) are passed through as is. All other values are
# converted to string first.
if is_protected_type(value):
self._current[field.name] = value
else:
self._current[field.name] = field.value_to_string(obj)
ví dụ: khả năng duy nhất để tùy biến ở đây (subclassing PositiveIntegerField
và xác định một custom value_to_string
) sẽ không có hiệu lực, kể từ khi serializer sẽ không gọi nó. Thay đổi kiểu dữ liệu của target_object_id
thành một số khác không phải là một số nguyên có thể sẽ phá vỡ nhiều thứ khác, do đó, nó không phải là một tùy chọn.
Chúng tôi thể xác định tùy chỉnh của chúng tôi handle_field
để phát ra các phím tự nhiên trong trường hợp này, nhưng sau đó đến các biến chứng thứ hai: deserialization được thực hiện như thế này:
for (field_name, field_value) in six.iteritems(d["fields"]):
field = Model._meta.get_field(field_name)
...
data[field.name] = field.to_python(field_value)
Thậm chí nếu chúng ta tùy chỉnh phương pháp to_python
, nó chỉ hoạt động trên field_value
, ngoài ngữ cảnh của đối tượng. Nó không phải là một vấn đề khi sử dụng số nguyên, vì nó sẽ được hiểu là khóa chính của mô hình bất kể mô hình là gì. Nhưng để deserialize một khóa tự nhiên, đầu tiên chúng ta cần phải biết mô hình đó là chìa khóa, và thông tin đó không có sẵn trừ khi chúng tôi có một tham chiếu đến đối tượng (và trường target_content_type
đã được deserialized). Như bạn có thể thấy, nó không phải là một nhiệm vụ không thể - hỗ trợ các khóa tự nhiên trong quan hệ chung - nhưng để thực hiện điều đó, rất nhiều thứ sẽ cần phải được thay đổi trong mã tuần tự hóa và deserialization.Các bước cần thiết, sau đó (nếu có ai cảm thấy lên đến nhiệm vụ) là:
- Tạo một tùy chỉnh
Field
mở rộng PositiveIntegerField
, với các phương pháp mã hóa/giải mã một đối tượng - gọi các mô hình tham chiếu natural_key
và get_by_natural_key
;
- Ghi đè số nối tiếp
handle_field
để gọi bộ mã hóa nếu có;
- Triển khai trình giải mã tùy chỉnh mà: 1) áp đặt một số thứ tự trong các trường, đảm bảo loại nội dung được deserialized trước khóa tự nhiên; 2) gọi bộ giải mã, không chỉ qua số
field_value
mà còn tham chiếu đến mã được giải mã ContentType
.
Tôi tò mò, bạn đã tìm thấy bất kỳ giải pháp cho việc này? Tôi đã làm một số tìm kiếm nhưng không có gì hữu ích đã đưa ra. – shanyu
chưa nhưng tôi sẽ cập nhật điều này với một giải pháp nếu tôi tìm thấy một – Riz
Bạn có thể xây dựng câu hỏi của mình không? Một số ví dụ. – Rohan