2011-10-25 28 views
15

Tôi đang xây dựng một dự án cá nhân với Django, để tự rèn luyện bản thân (vì tôi yêu Django, nhưng tôi nhớ kỹ năng). Tôi có các yêu cầu cơ bản, tôi biết Python, tôi cẩn thận đọc cuốn sách Django hai lần nếu không ba lần.ForeignKey đến lớp trừu tượng (quan hệ chung)

Mục tiêu của tôi là tạo một dịch vụ giám sát đơn giản, với giao diện web dựa trên Django cho phép tôi kiểm tra trạng thái của "nút" (máy chủ) của tôi. Mỗi nút có nhiều "dịch vụ". Ứng dụng kiểm tra tính khả dụng của từng dịch vụ cho mỗi nút.

Vấn đề của tôi là tôi không biết cách thể hiện các loại dịch vụ khác nhau trong cơ sở dữ liệu của mình. Tôi nghĩ đến hai "giải pháp":

  • đơn mô hình dịch vụ, với một lĩnh vực "Loại Dịch vụ", và một mớ hỗn độn lớn với các lĩnh vực. (Tôi không có kinh nghiệm tuyệt vời trong mô hình hóa cơ sở dữ liệu, nhưng điều này có vẻ ... "xấu" với tôi)
  • nhiều mô hình dịch vụ. Tôi thích giải pháp này, nhưng sau đó tôi không có ý tưởng làm thế nào tôi có thể tham khảo các dịch vụ KHÁC BIỆT trong cùng một lĩnh vực.

Đây là một đoạn trích ngắn từ models.py tập tin của tôi: (Tôi đã gỡ bỏ tất cả những gì không liên quan đến vấn đề này)

from django.db import models 

# Create your models here.                               
class service(models.Model): 
    port = models.PositiveIntegerField() 
    class Meta: 
     abstract = True 

class sshService(service): 
    username = models.CharField(max_length=64) 
    pkey = models.TextField() 

class telnetService(service): 
    username = models.CharField(max_length=64) 
    password = models.CharField(max_length=64) 

class genericTcpService(service): 
    pass 

class genericUdpService(service): 
    pass 

class node(models.Model): 
    name = models.CharField(max_length=64) 
    # various fields                                 
    services = models.ManyToManyField(service) 

Tất nhiên, phù hợp với ManyToManyField là không có thật. Tôi không có ý tưởng gì để thay thế cho "* Dịch vụ". Tôi thành thật tìm kiếm các giải pháp về điều này, tôi nghe nói về "quan hệ chung chung", ba bàn tham gia, nhưng tôi đã không thực sự hiểu những điều này.

Hơn nữa, tiếng Anh không phải là ngôn ngữ mẹ đẻ của tôi, vì vậy đến cấu trúc cơ sở dữ liệu và ngữ nghĩa, kiến ​​thức và hiểu biết của tôi về những gì tôi đọc được giới hạn (nhưng đó là vấn đề của tôi)

Trả lời

13

Để bắt đầu, hãy sử dụng số multi-table inheritance của Django, chứ không phải là mô hình trừu tượng bạn hiện có.

Mã của bạn sau đó sẽ trở thành:

from django.db import models 

class Service(models.Model): 
    port = models.PositiveIntegerField() 

class SSHService(Service): 
    username = models.CharField(max_length=64) 
    pkey = models.TextField() 

class TelnetService(Service): 
    username = models.CharField(max_length=64) 
    password = models.CharField(max_length=64) 

class GenericTcpService(Service): 
    pass 

class GenericUDPService(Service): 
    pass 

class Node(models.Model): 
    name = models.CharField(max_length=64) 
    # various fields                                 
    services = models.ManyToManyField(Service) 

Ở cấp độ cơ sở dữ liệu, điều này sẽ tạo ra một bảng 'dịch vụ', các hàng trong số đó sẽ được liên kết qua 1-1 mối quan hệ với các bảng riêng biệt cho mỗi dịch vụ con .

Khó khăn duy nhất với phương pháp này là khi bạn làm điều gì đó như sau:

node = Node.objects.get(pk=node_id) 

for service in node.services.all(): 
    # Do something with the service 

Các 'dịch vụ' đối tượng bạn truy cập trong vòng lặp sẽ được loại cha mẹ. Nếu bạn biết những gì con gõ này sẽ có trước, bạn chỉ có thể truy cập vào các lớp con theo cách sau:

from django.core.exceptions import ObjectDoesNotExist 

try: 
    telnet_service = service.telnetservice 
except (AttributeError, ObjectDoesNotExist): 
    # You chose the wrong child type! 
    telnet_service = None 

Nếu bạn không biết loại con trước, nó được một chút phức tạp hơn. Có một vài giải pháp hacky/lộn xộn, bao gồm trường 'serviceType' trên mô hình gốc, nhưng cách tốt hơn, như Joe J đã đề cập, là sử dụng 'bộ truy vấn lớp con'. Lớp InheritanceManager từ django-model-utils có lẽ là dễ sử dụng nhất. Đọc tài liệu cho nó here, nó thực sự là một chút mã nhỏ.

+0

Cảm ơn bạn đã chi tiết, đầy đủ mã, câu trả lời. Với một trong những @ Joe J, tôi khá chắc chắn nó sẽ giúp tôi trong suốt việc mô hình hóa ứng dụng của tôi. Trang web này là tuyệt vời, người dùng của nó quá :) – pistache

+0

OK, đó là một giải pháp tuyệt vời mà bạn đã đưa ra ở đây, đặc biệt là thủ đoạn InheritanceManager, và toàn bộ gói django-model-utils. Cảm ơn một lần nữa – pistache

6

Tôi nghĩ một cách tiếp cận mà bạn có thể xem xét là "bộ truy vấn phân lớp con". Về cơ bản, nó cho phép bạn truy vấn mô hình cha và nó sẽ trả về các cá thể của các mô hình con trong bộ truy vấn kết quả. Nó sẽ cho phép bạn làm các truy vấn như:

models.service.objects.all() 

và có nó trở lại cho bạn kết quả như sau:

[ <sshServiceInstance>, <telnetServiceInstance>, <telnetServiceInstance>, ...] 

Đối với một số ví dụ về cách để làm điều này, hãy kiểm tra các liên kết trên các bài viết trên blog được liên kết bên dưới.

http://jazstudios.blogspot.com/2009/10/django-model-inheritance-with.html

Tuy nhiên, nếu bạn sử dụng phương pháp này, bạn không nên tuyên bố mô hình dịch vụ của bạn như là trừu tượng như bạn làm trong ví dụ. Cấp, bạn sẽ được giới thiệu một tham gia thêm, nhưng nói chung tôi đã tìm thấy các queryset subclassing để làm việc khá tốt cho trở về một tập hợp các đối tượng trong một queryset.

Dù sao, hy vọng điều này sẽ giúp, Joe

+1

Cảm ơn rất nhiều, câu trả lời của bạn, với một trong @Voightkampff đã giúp tôi hiểu mô hình kế thừa và đã cho tôi một cách mới để suy nghĩ về cấu trúc dữ liệu mô hình của tôi. Về một mặt không, đây là câu hỏi đầu tiên của tôi trong stackoverflow.com, và tôi thực sự hài lòng với trang web, giao diện, người dùng, câu trả lời và tôi rất vui khi chia sẻ kiến ​​thức của tôi nữa, bây giờ. :) – pistache

0

Nếu bạn đang tìm kiếm các mối quan hệ chính nước ngoài chung bạn nên kiểm tra Django contenttypes framework (được xây dựng vào Django). Các tài liệu khá nhiều giải thích làm thế nào để sử dụng nó và làm thế nào để làm việc với các mối quan hệ chung chung.

+1

Cảm ơn, nhưng như tôi đã nói, tôi đã kiểm tra nó, nhưng tôi đã không thực sự hiểu hay tôi có thể ánh xạ các ví dụ trên Internet cho trường hợp sử dụng của tôi. – pistache

0

Dịch vụ thực tế chỉ có thể ở trên một nút, phải không? Trong trường hợp đó khi không có trường

node = models.ForeignKey('node', related_name='services') 

trong lớp service?

Các vấn đề liên quan