Django-eav (gói ban đầu không còn được bảo dưỡng nữa nhưng có một số nhánh phát triển mạnh )
Giải pháp này dựa trên mô hình dữ liệu Giá trị thuộc tính thực thể , về cơ bản, nó sử dụng một số bảng để lưu trữ các thuộc tính động của các đối tượng. Phần lớn về giải pháp này là nó:
- sử dụng một số mô hình Django thuần túy và đơn giản để biểu diễn các trường động, giúp cho việc hiểu và cơ sở dữ liệu trở nên đơn giản;
cho phép bạn gắn / tách hiệu quả lưu trữ thuộc tính động vào mô hình Django bằng các lệnh đơn giản như:
eav.unregister(Encounter)
eav.register(Patient)
Tích hợp độc đáo với quản trị viên Django ;
Đồng thời là thực sự mạnh mẽ.
Nhược điểm:
- Không hiệu quả lắm. Đây là một sự chỉ trích nhiều hơn về chính mẫu EAV, đòi hỏi phải hợp nhất thủ công dữ liệu từ định dạng cột thành một tập hợp các cặp khóa-giá trị trong mô hình.
- Khó bảo trì hơn. Việc duy trì tính toàn vẹn dữ liệu đòi hỏi một ràng buộc khóa duy nhất nhiều cột, có thể không hiệu quả trên một số cơ sở dữ liệu.
- Bạn sẽ cần phải chọn một trong các dĩa , vì gói chính thức không còn được duy trì và không có nhà lãnh đạo rõ ràng.
Việc sử dụng khá đơn giản:
import eav
from app.models import Patient, Encounter
eav.register(Encounter)
eav.register(Patient)
Attribute.objects.create(name='age', datatype=Attribute.TYPE_INT)
Attribute.objects.create(name='height', datatype=Attribute.TYPE_FLOAT)
Attribute.objects.create(name='weight', datatype=Attribute.TYPE_FLOAT)
Attribute.objects.create(name='city', datatype=Attribute.TYPE_TEXT)
Attribute.objects.create(name='country', datatype=Attribute.TYPE_TEXT)
self.yes = EnumValue.objects.create(value='yes')
self.no = EnumValue.objects.create(value='no')
self.unkown = EnumValue.objects.create(value='unkown')
ynu = EnumGroup.objects.create(name='Yes / No / Unknown')
ynu.enums.add(self.yes)
ynu.enums.add(self.no)
ynu.enums.add(self.unkown)
Attribute.objects.create(name='fever', datatype=Attribute.TYPE_ENUM,\
enum_group=ynu)
# When you register a model within EAV,
# you can access all of EAV attributes:
Patient.objects.create(name='Bob', eav__age=12,
eav__fever=no, eav__city='New York',
eav__country='USA')
# You can filter queries based on their EAV fields:
query1 = Patient.objects.filter(Q(eav__city__contains='Y'))
query2 = Q(eav__city__contains='Y') | Q(eav__fever=no)
Các trường Hstore, JSON hoặc JSONB trong PostgreSQL
PostgreSQL hỗ trợ một số loại dữ liệu phức tạp hơn. Hầu hết được hỗ trợ thông qua các gói của bên thứ ba, nhưng trong những năm gần đây Django đã áp dụng chúng vào django.contrib.postgres.fields.
HStoreField :
Django-hstore ban đầu là gói của bên thứ ba, nhưng Django 1.8 đã thêm HStoreField dưới dạng tích hợp, cùng với một số loại trường khác được PostgreQuery hỗ trợ.
Cách tiếp cận này tốt theo nghĩa là nó cho phép bạn có cả hai thế giới tốt nhất: trường động và cơ sở dữ liệu quan hệ. Tuy nhiên, hstore không phải là hiệu suất lý tưởng , đặc biệt nếu bạn cuối cùng sẽ lưu trữ hàng ngàn mặt hàng trong một lĩnh vực. Nó cũng chỉ hỗ trợ chuỗi cho các giá trị.
#app/models.py
from django.contrib.postgres.fields import HStoreField
class Something(models.Model):
name = models.CharField(max_length=32)
data = models.HStoreField(db_index=True)
Trong shell của Django, bạn có thể sử dụng nó như thế này:
>>> instance = Something.objects.create(
name='something',
data={'a': '1', 'b': '2'}
)
>>> instance.data['a']
'1'
>>> empty = Something.objects.create(name='empty')
>>> empty.data
{}
>>> empty.data['a'] = '1'
>>> empty.save()
>>> Something.objects.get(name='something').data['a']
'1'
Bạn có thể đưa ra các truy vấn được lập chỉ mục đối với các trường hstore:
# equivalence
Something.objects.filter(data={'a': '1', 'b': '2'})
# subset by key/value mapping
Something.objects.filter(data__a='1')
# subset by list of keys
Something.objects.filter(data__has_keys=['a', 'b'])
# subset by single key
Something.objects.filter(data__has_key='a')
Năng suất JSON :
Các trường JSON / JSONB hỗ trợ bất kỳ loại dữ liệu có thể mã hóa JSON nào, không chỉ các cặp khóa / giá trị, mà còn có xu hướng nhanh hơn và (đối với JSONB) nhỏ gọn hơn Hstore. Một số gói triển khai các trường JSON / JSONB bao gồm django-pgfields , nhưng kể từ Django 1.9, JSONField là một tích hợp sử dụng JSONB để lưu trữ.
JSONField tương tự như HStoreField và có thể hoạt động tốt hơn với các từ điển lớn. Nó cũng hỗ trợ các loại khác ngoài chuỗi, chẳng hạn như số nguyên, booleans và từ điển lồng nhau.
#app/models.py
from django.contrib.postgres.fields import JSONField
class Something(models.Model):
name = models.CharField(max_length=32)
data = JSONField(db_index=True)
Tạo trong trình bao:
>>> instance = Something.objects.create(
name='something',
data={'a': 1, 'b': 2, 'nested': {'c':3}}
)
Các truy vấn được lập chỉ mục gần giống với HStoreField, ngoại trừ việc lồng nhau là có thể. Các chỉ mục phức tạp có thể yêu cầu tạo thủ công (hoặc di chuyển theo kịch bản).
>>> Something.objects.filter(data__a=1)
>>> Something.objects.filter(data__nested__c=3)
>>> Something.objects.filter(data__has_key='a')
Django MongoDB
Hoặc các điều chỉnh khác của NoQuery Django - với chúng, bạn có thể có các mô hình hoàn toàn năng động.
Các thư viện Django của NoQuery rất tuyệt, nhưng hãy nhớ rằng chúng không tương thích 100% với Django, ví dụ, để di chuyển sang Django-nonrel từ Django tiêu chuẩn, bạn sẽ cần thay thế ManyToMany bằng ListField trong số những thứ khác.
Kiểm tra ví dụ Django MongoDB này:
from djangotoolbox.fields import DictField
class Image(models.Model):
exif = DictField()
...
>>> image = Image.objects.create(exif=get_exif_data(...))
>>> image.exif
{u'camera_model' : 'Spamcams 4242', 'exposure_time' : 0.3, ...}
Bạn thậm chí có thể tạo danh sách nhúng của bất kỳ mô hình Django nào:
class Container(models.Model):
stuff = ListField(EmbeddedModelField())
class FooModel(models.Model):
foo = models.IntegerField()
class BarModel(models.Model):
bar = models.CharField()
...
>>> Container.objects.create(
stuff=[FooModel(foo=42), BarModel(bar='spam')]
)
Django-mutant: Các mô hình động dựa trên syncdb và South-hook
Django-mutant thực hiện các trường Foreign Key và m2m hoàn toàn năng động. Và được lấy cảm hứng từ các giải pháp đáng kinh ngạc nhưng hơi khó tin của Will Hardy và Michael Hall.
Tất cả những thứ này đều dựa trên móc Django South, mà theo Will Hardy tại DjangoCon 2011 (xem nó!) Tuy nhiên vẫn mạnh mẽ và được thử nghiệm trong sản xuất ( mã nguồn có liên quan ).
Đầu tiên để thực hiện điều này là Michael Hall .
Vâng, đây là điều kỳ diệu, với những cách tiếp cận này, bạn có thể đạt được các ứng dụng, mô hình và trường Django hoàn toàn năng động với bất kỳ phụ trợ cơ sở dữ liệu quan hệ nào. Nhưng với chi phí nào? Sự ổn định của ứng dụng sẽ bị ảnh hưởng khi sử dụng nặng? Đây là những câu hỏi được xem xét. Bạn cần chắc chắn duy trì một khóa thích hợp để cho phép các yêu cầu thay đổi cơ sở dữ liệu đồng thời.
Nếu bạn đang sử dụng lib Michael Halls, mã của bạn sẽ như thế này:
from dynamo import models
test_app, created = models.DynamicApp.objects.get_or_create(
name='dynamo'
)
test, created = models.DynamicModel.objects.get_or_create(
name='Test',
verbose_name='Test Model',
app=test_app
)
foo, created = models.DynamicModelField.objects.get_or_create(
name = 'foo',
verbose_name = 'Foo Field',
model = test,
field_type = 'dynamiccharfield',
null = True,
blank = True,
unique = False,
help_text = 'Test field for Foo',
)
bar, created = models.DynamicModelField.objects.get_or_create(
name = 'bar',
verbose_name = 'Bar Field',
model = test,
field_type = 'dynamicintegerfield',
null = True,
blank = True,
unique = False,
help_text = 'Test field for Bar',
)