2008-12-31 21 views
44

Potrzebuję przechowywać niektóre dane w modelu Django. Te dane nie są równe wszystkim instancjom modelu.Jak przechowywać słownik w modelu Django?

Początkowo myślałem o podklasowaniu modelu, ale staram się zachować elastyczność aplikacji. Jeśli używam podklas, będę musiał stworzyć całą klasę za każdym razem, gdy potrzebuję nowego rodzaju obiektu, a to nie jest dobre. Będę też miał wiele podklas tylko do przechowywania pary dodatkowych pól.

Naprawdę uważam, że najlepszym podejściem byłby słownik, ale w dokumentacji Django nie ma nic o przechowywaniu słownika w modelu Django (lub nie mogę go znaleźć).

Jakieś wskazówki?

+6

"niektóre dane" - źle zdefiniowane. Bez jakiegoś modelu danych lub innej wskazówki, nie ma odpowiedzi. –

Odpowiedz

32

Jeśli to naprawdę słownik, na przykład dowolne dane, prawdopodobnie można użyć konfiguracji dwupoziomowej z jednym modelem, który jest kontenerem i innym modelem, który jest parą klucz-wartość. Można utworzyć instancję kontenera, utworzyć każdą z instancji typu klucz-wartość i powiązać zestaw instancji klucz-wartość z instancją kontenera. Coś jak:

class Dicty(models.Model): 
    name  = models.CharField(max_length=50) 

class KeyVal(models.Model): 
    container = models.ForeignKey(Dicty, db_index=True) 
    key  = models.CharField(max_length=240, db_index=True) 
    value  = models.CharField(max_length=240, db_index=True) 

To nie jest ładna, ale to umożliwiają dostęp/szukaj wnętrzności słownika przy użyciu DB natomiast zalewie/serializacji rozwiązanie nie będzie.

+4

Jedyną wadą jest to, że pojawi się dodatkowe zapytanie DB. –

+2

Kolejną wadą jest to, że masz dokładnie jeden "poziom" danych, nie możesz utworzyć wielopoziomowych, złożonych danych w stylu JSON. (ale mimo to dobry pomysł) –

+6

Znaleziono ładne rozszerzenie tego rozwiązania: https://djangosnippets.org/snippets/2451/ ten facet rozszerzył słownik do wszystkich funkcji słownika pythonic –

14

Jeśli nie potrzebujesz żadnych dodatkowych danych, możesz zapisać je w postaci serializowanego słownika. Użyj repr, aby przekształcić słownik w ciąg znaków, a eval, aby zamienić ciąg znaków w słowniku. Uważaj na eval, że nie ma danych użytkownika w słowniku lub użyj implementacji safe_eval.

2

Przemyśl to i znajdź podobieństwo każdego zestawu danych ... a następnie określ model. Może wymagać użycia podklas lub nie. Nie należy unikać kluczy obcych reprezentujących podobieństwa, ale zachęcać, gdy mają sens.

Wprowadzanie losowych danych do tabeli SQL nie jest inteligentne, chyba że jest to naprawdę nierelacyjne dane. W takim przypadku zdefiniuj swój problem i być może pomożemy.

+1

+1: nie wciskaj obiektów Pythona w stół przypadkowo. –

4

Nie jestem pewien co do natury problemu, który próbujesz rozwiązać, ale brzmi to dziwnie podobnie do Google App Engine's BigTable Expando.

Funkcja Rozwiń umożliwia określenie i zapisanie dodatkowych pól w instancji obiektu opartego na bazie danych w środowisku wykonawczym. Aby zacytować dokumentację:

import datetime 
from google.appengine.ext import db 

class Song(db.Expando): 
    title = db.StringProperty() 

crazy = Song(title='Crazy like a diamond', 
      author='Lucy Sky', 
      publish_date='yesterday', 
      rating=5.0) 

crazy.last_minute_note=db.Text('Get a train to the station.') 

Google App Engine obsługuje obecnie zarówno Python, jak i framework Django. Może warto się zastanowić, czy jest to najlepszy sposób na wyrażenie swoich modeli.

Tradycyjne modele relacyjnej bazy danych nie mają tego rodzaju elastyczności dodawania kolumn. Jeśli twoje typy danych są wystarczająco proste, możesz oderwać się od tradycyjnej filozofii RDBMS i zhakować wartości w jedną kolumnę poprzez serializację, jak proponuje @Ned Batchelder; jednak jeśli masz mieć do korzystania z RDBMS, dziedziczenie modelu Django jest prawdopodobnie drogą do zrobienia. W szczególności, stworzy on relację a one-to-one foreign key dla każdego poziomu wyprowadzenia.

7

Jak odpowiedział Ned, nie będzie można wyszukiwać "niektórych danych", jeśli używasz metody słownikowej.

Jeśli nadal potrzebujesz przechowywać słowniki, najlepszą metodą jest zdecydowanie klasa PickleField udokumentowana w nowej książce Marty Alchin: Pro Django. W tej metodzie właściwości klasy Python są używane do pikowania/rozpłaszczania obiektu Pythona tylko na żądanie, który jest przechowywany w polu modelu.

Podstawą tego podejścia jest zastosowanie metody django do automatycznego dodawania nowego pola do modelu i użycie metody getattr/setattr do serializacji na żądanie.

Jednym z niewielu przykładów online, które można znaleźć jest podobna jest ta definicja JSONField.

3

Bycie "nie równym wszystkim instancjom modelu" brzmi dla mnie jak dobre dopasowanie do "bazy danych wolnej od schematów". CouchDB jest dzieckiem z plakatu dla tego podejścia i możesz to rozważyć.

W projekcie przeniosłem kilka stołów, które nigdy nie grały zbyt dobrze z Django ORM do CouchDB i jestem z tego całkiem zadowolony. Używam couchdb-python bez żadnego z modułów Douchgo CouchDB. Opis modelu danych można znaleźć here. Ruch z pięciu "modeli" w Django do modeli 3 "w Django i jednej bazie danych" CouchDB "faktycznie nieznacznie zredukował całkowite linie kodu w mojej aplikacji.

3

Zgadzam się, że należy powstrzymać wypychanie w inny sposób danych strukturalnych do pojedynczej kolumny. Ale jeśli musisz to zrobić, Django ma wbudowaną wersję XMLField.

Istnieje również JSONField w saszetkach Django.

10

doszedłem do tego wpisu przez 4rth wyniku google na „sklep django obiekt”

Trochę późno, ale django-picklefield wygląda dobrym rozwiązaniem dla mnie.

Przykład z Doc:

w obsłudze, wystarczy zdefiniować pole w modelu:

>>> from picklefield.fields import PickledObjectField 
>>> class SomeObject(models.Model): 
>>>  args = PickledObjectField() 

i przypisać cokolwiek chcesz (tak długo, jak to picklable) do pola:

>>> obj = SomeObject() 
>>> obj.args = ['fancy', {'objects': 'inside'}] 
>>> obj.save() 
6

Kolejne czyste i szybkie rozwiązanie można znaleźć tutaj: https://github.com/bradjasper/django-jsonfield

Dla wygody skopiowałem proste instrukcje.

Install

pip install jsonfield 

Wykorzystanie

from django.db import models 
from jsonfield import JSONField 

class MyModel(models.Model): 
    json = JSONField()