Django मॉडल में एक सूची को स्टोर करने का सबसे कुशल तरीका क्या है?


146

वर्तमान में मेरे पास अपने कोड में बहुत सारे अजगर वस्तुओं के समान है:

class MyClass():
  def __init__(self, name, friends):
      self.myName = name
      self.myFriends = [str(x) for x in friends]

अब मैं इसे एक Django मॉडल में बदलना चाहता हूं, जहां self.myName एक स्ट्रिंग फ़ील्ड है, और self.myFriends तार की एक सूची है।

from django.db import models

class myDjangoModelClass():
    myName = models.CharField(max_length=64)
    myFriends = ??? # what goes here?

चूंकि सूची अजगर में इस तरह की एक सामान्य डेटा संरचना है, इसलिए मुझे उम्मीद है कि इसके लिए एक Django मॉडल फ़ील्ड होने की उम्मीद है। मुझे पता है कि मैं एक ManyToMany या OneToMany संबंध का उपयोग कर सकता हूं, लेकिन मैं कोड में उस अतिरिक्त अप्रत्यक्षता से बचने की उम्मीद कर रहा था।

संपादित करें:

मैंने इस संबंधित प्रश्न को जोड़ा , जो लोगों को उपयोगी लग सकता है।


1
@ डॉरज़ी: वैसे मैं शायद एक अलग वाक्यांश का उपयोग कर सकता था, लेकिन मूल रूप से मेरा मतलब था, क्या मैं तार की सूची में पास होना चाहता था और तार की एक सूची वापस प्राप्त करना चाहता था। मैं उनमें से प्रत्येक के लिए Friend ऑब्जेक्ट्स का एक समूह बनाना नहीं चाहता, और inst.myFriends.add (friendObj) को कॉल करना चाहता हूं। नहीं यह सब है कि कठिन है, लेकिन ... हो सकता है कि
शोक

जवाबों:


77

क्या यह संबंध एक Friendsटेबल के लिए एक से कई विदेशी कुंजी संबंधों के रूप में बेहतर रूप से व्यक्त नहीं किया जाएगा ? मैं समझता हूं कि myFriendsयह केवल तार हैं लेकिन मुझे लगता है कि एक बेहतर डिज़ाइन एक Friendमॉडल बनाने के लिए होगा और MyClassपरिणामस्वरूप तालिका में एक विदेशी कुंजी realtionship शामिल होगी।


15
यह शायद मैं क्या कर रहा हूं, लेकिन मैं वास्तव में उम्मीद कर रहा था कि इसके लिए अंतर्निहित संरचना का निर्माण किया गया होगा। मुझे लगता है कि मैं ओ आलसी हूं।
16:10 पर

सुरुचिपूर्ण और सबसे खूबसूरती से विस्फोट।
Tessaracter


129

"सभी बुराईयो की जड़ समयपूर्व इष्टतमीकरण है।"

उस दृढ़ता के साथ मन में, चलो यह करते हैं! एक बार जब आपके ऐप्स एक निश्चित बिंदु पर पहुंच जाते हैं, तो डेटा को निरूपित करना बहुत आम है। सही ढंग से किया, यह थोड़ा महंगा हाउसकीपिंग की कीमत पर कई महंगे डेटाबेस लुक को बचा सकता है।

listदोस्त के नाम वापस करने के लिए हमें एक कस्टम Django फ़ील्ड क्लास बनाने की आवश्यकता होगी जो एक्सेस किए जाने पर एक सूची वापस करेगी।

डेविड Cramer ने अपने ब्लॉग पर एक SeperatedValueField बनाने के लिए एक गाइड पोस्ट किया। यहाँ कोड है:

from django.db import models

class SeparatedValuesField(models.TextField):
    __metaclass__ = models.SubfieldBase

    def __init__(self, *args, **kwargs):
        self.token = kwargs.pop('token', ',')
        super(SeparatedValuesField, self).__init__(*args, **kwargs)

    def to_python(self, value):
        if not value: return
        if isinstance(value, list):
            return value
        return value.split(self.token)

    def get_db_prep_value(self, value):
        if not value: return
        assert(isinstance(value, list) or isinstance(value, tuple))
        return self.token.join([unicode(s) for s in value])

    def value_to_string(self, obj):
        value = self._get_val_from_obj(obj)
        return self.get_db_prep_value(value)

इस कोड का तर्क डेटाबेस से पायथन और इसके विपरीत मूल्यों को क्रमबद्ध और deserializing मूल्यों से संबंधित है। अब आप मॉडल वर्ग में हमारे कस्टम फ़ील्ड को आसानी से आयात और उपयोग कर सकते हैं:

from django.db import models
from custom.fields import SeparatedValuesField 

class Person(models.Model):
    name = models.CharField(max_length=64)
    friends = SeparatedValuesField()

8
एक महान जवाब के लिए +1, लेकिन हम पहले से ही ऐसा कुछ कर रहे हैं। यह वास्तव में सभी मूल्यों को एक तार में विभाजित करता है और फिर उन्हें विभाजित करता है। मुझे लगता है कि मैं एक ListofStringsField की तरह कुछ के लिए उम्मीद कर रहा था, जो वास्तव में अलग तालिका बनाता है और स्वचालित रूप से विदेशी कुंजी बनाता है। मुझे यकीन नहीं है कि अगर Django में यह संभव है। यदि यह है, और मुझे एक उत्तर मिलता है, तो मैं इसे स्टैकओवरफ़्लो पर पोस्ट करूँगा।
१३:३५ पर

2
अगर ऐसा है तो आप initcrash के django-denorm की तलाश कर रहे हैं। आप इसे github: github.com/initcrash/django-denorm/tree/master
jb

3
+1। लेकिन तार में अल्पविराम के साथ संभव मुद्दों। क्या धारावाहिक और जॉन से deserializing के बारे में?
sbeliakov

मौजूदा मॉडल के साथ इसे जोड़ने की कोशिश कर रहा है, my_vals = SeparatedValuesField(blank=True, default="")लेकिन NULLs की वजह से इंटीग्रिटीइर्रर्ट प्राप्त कर रहा है। क्या डिफ़ॉल्ट तर्क सही तरीके से नहीं हो रहा है?
जॉन लेहमैन

1
ध्यान दें कि Django 2.1 to_pythonमें अब पढ़ने के लिए कॉल नहीं किया जाता है। इस प्रकार इस काम को करने के लिए आपको जोड़ना होगा: def from_db_value(self, value, expression, connection, context): return self.to_python(value)
theadriangreen

46

Django में एक सूची को स्टोर करने का एक सरल तरीका यह है कि इसे केवल JSON स्ट्रिंग में परिवर्तित किया जाए, और फिर मॉडल में टेक्स्ट के रूप में सहेजें। फिर आप (JSON) स्ट्रिंग को अजगर सूची में परिवर्तित करके सूची पुनः प्राप्त कर सकते हैं। ऐसे:

"सूची" को आपके Django मॉडल में संग्रहीत किया जाएगा:

class MyModel(models.Model):
    myList = models.TextField(null=True) # JSON-serialized (text) version of your list

आपके विचार / नियंत्रक कोड में:

डेटाबेस में सूची संग्रहीत करना:

import simplejson as json # this would be just 'import json' in Python 2.7 and later
...
...

myModel = MyModel()
listIWantToStore = [1,2,3,4,5,'hello']
myModel.myList = json.dumps(listIWantToStore)
myModel.save()

डेटाबेस से सूची प्राप्त करना:

jsonDec = json.decoder.JSONDecoder()
myPythonList = jsonDec.decode(myModel.myList)

वैचारिक रूप से, यहाँ क्या हो रहा है:

>>> myList = [1,2,3,4,5,'hello']
>>> import simplejson as json
>>> myJsonList = json.dumps(myList)
>>> myJsonList
'[1, 2, 3, 4, 5, "hello"]'
>>> myJsonList.__class__
<type 'str'>
>>> jsonDec = json.decoder.JSONDecoder()
>>> myPythonList = jsonDec.decode(myJsonList)
>>> myPythonList
[1, 2, 3, 4, 5, u'hello']
>>> myPythonList.__class__
<type 'list'>

8
दुर्भाग्य से यह आपको django व्यवस्थापक का उपयोग करके सूची प्रबंधित करने में मदद नहीं करता है
GreenAsJade

25

यदि आप Django> = 1.9 का उपयोग कर रहे हैं तो Postgres के साथ आप ArrayField लाभ का उपयोग कर सकते हैं

डेटा की सूची संग्रहीत करने के लिए एक फ़ील्ड। अधिकांश फ़ील्ड प्रकारों का उपयोग किया जा सकता है, आप बस आधार_फील्ड के रूप में एक और फ़ील्ड उदाहरण पास करते हैं। आप एक आकार भी निर्दिष्ट कर सकते हैं। ArrayField को बहुआयामी सरणियों को संग्रहीत करने के लिए नेस्टेड किया जा सकता है।

यह सरणी फ़ील्ड्स को घोंसला करने के लिए भी संभव है:

from django.contrib.postgres.fields import ArrayField
from django.db import models

class ChessBoard(models.Model):
    board = ArrayField(
        ArrayField(
            models.CharField(max_length=10, blank=True),
            size=8,
        ),
        size=8,
    )

जैसा कि @ thane-brimhall ने उल्लेख किया है कि सीधे तत्वों को क्वेरी करना भी संभव है। प्रलेखन संदर्भ


2
इसका बड़ा फायदा यह है कि आप एरे फ़ील्ड से सीधे एलिमेंट्स को क्वेरी कर सकते हैं।
ठाणे ब्रिमहल

@ThaneBrimhall आप सही हैं। शायद मुझे इस जानकारी के साथ जवाब अपडेट करना चाहिए। धन्यवाद
wolendranh

अफसोस की बात है, mysql के लिए कोई समाधान नहीं
जोएल जी मैथ्यू

यह उल्लेख किया जाना चाहिए कि यह केवल PostGres के साथ काम करता है।
theadriangreen

1
Django 1.8 में ArrayField भी है: docs.djangoproject.com/en/1.8/ref/contrib/postgres/fields
kontextify

15

जैसा कि यह एक पुराना सवाल है, और Django तकनीकें काफी बदल गई हैं, क्योंकि यह उत्तर Django संस्करण 1.4 को दर्शाता है, और यह संभवतः v 1.5 पर लागू होता है।

डिफ़ॉल्ट रूप से Django संबंधपरक डेटाबेस का उपयोग करता है; आपको उन्हें इस्तेमाल करना चाहिए। ManyToManyField के उपयोग के साथ डेटाबेस संबंधों (विदेशी प्रमुख बाधाओं) के लिए मानचित्र दोस्ती। ऐसा करने से आप मित्रविदों के लिए संबंधित प्रबंधक का उपयोग कर सकते हैं, जो स्मार्ट क्वेरी का उपयोग करते हैं। आप सभी उपलब्ध तरीकों का उपयोग कर सकते हैं जैसे filterया values_list

ManyToManyFieldसंबंधों और गुणों का उपयोग करना :

class MyDjangoClass(models.Model):
    name = models.CharField(...)
    friends = models.ManyToManyField("self")

    @property
    def friendlist(self):
        # Watch for large querysets: it loads everything in memory
        return list(self.friends.all())

आप किसी उपयोगकर्ता की मित्र सूची इस तरह से एक्सेस कर सकते हैं:

joseph = MyDjangoClass.objects.get(name="Joseph")
friends_of_joseph = joseph.friendlist

ध्यान दें कि ये संबंध सममित हैं: यदि यूसुफ बॉब का मित्र है, तो बॉब यूसुफ का मित्र है।


9
class Course(models.Model):
   name = models.CharField(max_length=256)
   students = models.ManyToManyField(Student)

class Student(models.Model):
   first_name = models.CharField(max_length=256)
   student_number = models.CharField(max_length=128)
   # other fields, etc...

   friends = models.ManyToManyField('self')

8

याद रखें कि यह अंततः एक रिलेशनल डेटाबेस में समाप्त होना है। इसलिए वास्तव में संबंधों का उपयोग करना इस समस्या को हल करने का सामान्य तरीका है। यदि आप ऑब्जेक्ट में किसी सूची को संग्रहीत करने के लिए पूरी तरह से जोर देते हैं, तो आप इसे उदाहरण के लिए अल्पविराम से अलग कर सकते हैं, और इसे एक स्ट्रिंग में संग्रहीत कर सकते हैं, और फिर एक्सेसर फ़ंक्शन प्रदान कर सकते हैं जो स्ट्रिंग को एक सूची में विभाजित करते हैं। इसके साथ, आप अधिकतम संख्या में स्ट्रिंग्स तक सीमित रहेंगे, और आप कुशल क्वेरी खो देंगे।


3
मैं एक संबंध के रूप में इसे संग्रहीत करने वाले डेटाबेस के साथ ठीक हूं, मैं उम्मीद कर रहा था कि Django मॉडल मेरे लिए पहले से ही उस हिस्से को अलग कर देगा। ऐप की तरफ से मैं हमेशा इसे स्ट्रिंग्स की सूची के रूप में मानना ​​चाहता हूं।
शोक

7

यदि आप पोस्टग्रेज का उपयोग कर रहे हैं, तो आप कुछ इस तरह से उपयोग कर सकते हैं:

class ChessBoard(models.Model):

    board = ArrayField(
        ArrayField(
            models.CharField(max_length=10, blank=True),
            size=8,
        ),
        size=8,
    )

यदि आपको अधिक जानकारी चाहिए तो आप नीचे दिए गए लिंक में पढ़ सकते हैं: https://docs.djangoproject.com/pt-br/1.9/ref/contrib/postgres/fields/


4

आप वास्तव में किसी भी वस्तु को Django अचार फ़ील्ड का उपयोग करके स्टोर कर सकते हैं, इस स्निपेट को:

http://www.djangosnippets.org/snippets/513/


3
नहीं, यह नहीं है। स्निपेट का वर्णन पढ़ें।
हेरोल्ड

नया pypi.python.org/pypi/django-picklefield वही कार्य करता है (स्वतंत्र रूप से db)
Massagran

3

Django मॉडल में तार की एक सूची संग्रहीत करना:

class Bar(models.Model):
    foo = models.TextField(blank=True)

    def set_list(self, element):
        if self.foo:
            self.foo = self.foo + "," + element
        else:
            self.foo = element

    def get_list(self):
        if self.foo:
            return self.foo.split(",")
        else:
            None

और आप इसे इस तरह कह सकते हैं:

bars = Bar()
bars.set_list("str1")
bars.set_list("str2")
list = bars.get_list()
if list is not None:
    for bar in list:
        print bar
else:
    print "List is empty."      

2

मेरा समाधान, यह किसी की मदद कर सकता है:

import json
from django.db import models


class ExampleModel(models.Model):
    _list = models.TextField(default='[]')

    @property
    def list(self):
        return json.loads(self._list)

    @list.setter
    def list(self, value):
        self._list = json.dumps(self.list + value)

1

एक-से-कई संबंध (मित्र से माता-पिता वर्ग तक एफके) का उपयोग करना आपके ऐप को और अधिक स्केलेबल बना देगा (जैसा कि आप साधारण नाम से परे अतिरिक्त विशेषताओं के साथ मित्र वस्तु का तुच्छ विस्तार कर सकते हैं)। और इस तरह यह सबसे अच्छा तरीका है


3
यह स्केलेबिलिटी नहीं है, यह एक्स्टेंसिबिलिटी है। अक्सर एक दूसरे की कीमत पर होता है। इस स्थिति में, यदि आप जानते हैं कि आपको हमेशा स्ट्रिंग्स की एक सूची की आवश्यकता होगी, तो आप एक महंगी जॉइन से बच सकते हैं, इस प्रकार अपने कोड को और अधिक स्केलेबल बना सकते हैं (यानी अपभ्रंश से अधिक प्रदर्शनकारी)।
डस्टिन रासनेअर

ऊपर दो गुहाओं के साथ: 1) आप जानते हैं कि आप कभी भी उस डेटा और 2 के खिलाफ क्वेरी नहीं करना चाहते हैं। भंडारण अभी भी प्रसंस्करण शक्ति और मेमोरी (जो जानता है, शायद क्वांटम कंप्यूटिंग के साथ यह परिवर्तन) की तुलना में सस्ता है
डस्टिन रासनेर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.