5

Tôi cần lưu trữ cấu trúc dữ liệu cây trong cơ sở dữ liệu của mình, mà tôi dự định sử dụng django-treebeard hoặc có thể là django-mptt. Nguồn gây nhầm lẫn của tôi là mỗi nút có thể là một trong ba loại có thể khác nhau: nút gốc sẽ luôn là thực thể loại A, nút lá loại thực thể C và bất kỳ thứ gì ở giữa sẽ là thực thể loại B. Tôi muốn biết cách tốt nhất để mô hình hóa tình huống này.Django: Làm thế nào để mô hình hóa một loại dữ liệu không đồng nhất?

cập nhật: Lần đầu tiên tôi cố gắng kế thừa mô hình và tôi nghĩ rằng đây có thể là cách tốt nhất để thực hiện. Rất tiếc, API công khai của django-treebeard không thực sự được thiết kế để xử lý việc này. Tôi đã nhận được nó để làm việc với GenericForeignKey. Cảm ơn bạn rất nhiều vì câu trả lời.

Trả lời

3

Cách sử dụng generic relation từ mô hình sẽ giữ cấu trúc cây cho đối tượng nội dung cho nút mà nó đại diện?

from django.db import models 
from django.contrib.contenttypes.models import ContentType 
from django.contrib.contenttypes import generic 

class Node(models.Model): 
    content_type = models.ForeignKey(ContentType) 
    object_id = models.PositiveIntegerField() 
    object = generic.GenericForeignKey('content_type', 'object_id') 

này có khả năng có thể dẫn đến nhiều thắc mắc khi lấy đối tượng nội dung cho cây đầy đủ, nhưng có ways and means giảm số lượng các truy vấn yêu cầu.

# Assuming mptt, as I'm not familiar with treebeard's API 

# 1 query to retrieve the tree 
tree = list(Node.tree.all()) 

# 4 queries to retrieve and cache all ContentType, A, B and C instances, respectively 
populate_content_object_caches(tree) 
3

Ba loại của bạn có lẽ được xử lý dễ dàng nhất là các liên kết FK với cây cơ bản.

Cây có thể đồng nhất - lớp MyNode là một phân lớp trực tiếp của treebeard.Node. Nút của bạn có thể có một cờ (Root, Middle, Leaf) và FK cho A hoặc B hoặc C. Điều này cho phép bạn một số tính linh hoạt giống SQL trong truy vấn cá thể MyNode.

Điều này cho phép cây của bạn phát triển. Một nút có thể bắt đầu như một loại C (lá) và sau đó biến thành một loại B (trung gian). Bạn thay đổi trạng thái và thay đổi trạng thái của FK.

Cách thay thế phức tạp hơn một chút.

class MyA(treebeard.Node): 
    pass 

class MyB(treebeard.Node): 
    pass 

class MyC(treebeard.Node): 
    pass 

Trong trường hợp này, bạn không thể "biến hình" một nút. Khi nút bắt đầu dưới dạng MyC và nhận con, bạn phải xóa phiên bản MyC gốc và thay thế bằng phiên bản MyB có nút mới khi còn nhỏ. Điều này không phải là không thể, nhưng nó có thể gây đau đớn.

1

Vâng, rất nhiều đã được thực hiện cho bạn, bởi vì rễ, lá và những thứ khác đã được xác định bởi API cây. Bạn có thể gọi is_root() và is_leaf() trên các nút riêng lẻ để phân biệt chúng.

Lá và trong-betweens có thể là cùng một loại thực thể và giữ cùng một loại dữ liệu, với cách dữ liệu được diễn giải và sử dụng bởi ứng dụng tùy thuộc vào thử nghiệm is_leaf().

Rễ hơi đặc biệt ... chúng có thể muốn giữ thông tin phù hợp với toàn bộ cây và bạn có thể thích cách đơn giản để tìm kiếm các gốc cụ thể và giữ dữ liệu bổ sung. Bạn có thể làm điều này với một mô hình có mối quan hệ một-một với nút gốc (có lẽ với phương thức lưu đã được nạp chồng và kiểm tra để xác nhận rằng nút trỏ đến is_root() trước khi cho phép lưu).

Điểm chung của tôi là bạn có thể không cần phải làm rất thích làm những gì bạn muốn. Sự khác biệt mà bạn đang tạo ra đã được đóng gói trong khái niệm cây và API của nó và bạn có thể thực hiện hành vi khác nhau với cùng một dữ liệu cơ bản bằng cách kiểm tra ngữ cảnh của nút.

0

Nếu cấu trúc cây là một phần không thể thiếu trong ứng dụng của bạn, hãy xem xét sử dụng một thứ gì đó khác với cơ sở dữ liệu quan hệ. Có lẽ neo4j?