IT story

Django 모델에 목록을 저장하는 가장 효율적인 방법은 무엇입니까?

hot-time 2020. 7. 14. 07:58
반응형

Django 모델에 목록을 저장하는 가장 효율적인 방법은 무엇입니까?


현재 내 코드에는 다음과 유사한 많은 파이썬 객체가 있습니다.

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

이제 이것을 장고 모델로 바꾸고 싶습니다. 여기서 self.myName은 문자열 필드이고 self.myFriends는 문자열 목록입니다.

from django.db import models

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

목록은 파이썬에서 일반적인 데이터 구조이기 때문에 장고 모델 필드가있을 것으로 예상됩니다. 나는 ManyToMany 또는 OneToMany 관계를 사용할 수 있다는 것을 알고 있지만 코드에서 추가 간접적 인 것을 피하고 싶었습니다.

편집하다:

사람들이 유용하다고 생각하는 관련 질문을 추가했습니다 .


이 관계가 Friends테이블 에 대한 일대 다 외래 키 관계로 더 잘 표현되지 않습니까? 나는 myFriends단지 문자열 이라는 것을 이해 하지만 더 나은 디자인은 Friend모델 을 만들고 MyClass결과 테이블에 대한 외래 키 구현 포함하는 것이라고 생각 합니다.


"조기 최적화는 모든 악의 근원입니다."

이를 확실하게 염두에두고이 작업을 수행하십시오! 앱이 특정 지점에 도달하면 데이터의 비정규 화가 매우 일반적입니다. 올바르게 수행하면 약간의 하우스 키핑 비용으로 많은 고가의 데이터베이스 조회를 절약 할 수 있습니다.

list친구 이름 을 반환하려면 액세스 할 때 목록을 반환하는 사용자 지정 Django Field 클래스를 만들어야합니다.

David 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)

The logic of this code deals with serializing and deserializing values from the database to Python and vice versa. Now you can easily import and use our custom field in the model class:

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

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

A simple way to store a list in Django is to just convert it into a JSON string, and then save that as Text in the model. You can then retrieve the list by converting the (JSON) string back into a python list. Here's how:

The "list" would be stored in your Django model like so:

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

In your view/controller code:

Storing the list in the database:

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()

Retrieving the list from the database:

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

Conceptually, here's what's going on:

>>> 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'>

If you are using Django >= 1.9 with Postgres you can make use of ArrayField advantages

A field for storing lists of data. Most field types can be used, you simply pass another field instance as the base_field. You may also specify a size. ArrayField can be nested to store multi-dimensional arrays.

It is also possible to nest array fields:

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,
    )

As @thane-brimhall mentioned it is also possible to query elements directly. Documentation reference


As this is an old question, and Django techniques must have changed significantly since, this answer reflects Django version 1.4, and is most likely applicable for v 1.5.

Django by default uses relational databases; you should make use of 'em. Map friendships to database relations (foreign key constraints) with the use of ManyToManyField. Doing so allows you to use RelatedManagers for friendlists, which use smart querysets. You can use all available methods such as filter or values_list.

Using ManyToManyField relations and properties:

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())

You can access a user's friend list this way:

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

Note however that these relations are symmetrical: if Joseph is a friend of Bob, then Bob is a friend of Joseph.


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')

Remember that this eventually has to end up in a relational database. So using relations really is the common way to solve this problem. If you absolutely insist on storing a list in the object itself, you could make it for example comma-separated, and store it in a string, and then provide accessor functions that split the string into a list. With that, you will be limited to a maximum number of strings, and you will lose efficient queries.


In case you're using postgres, you can use something like this:

class ChessBoard(models.Model):

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

if you need more details you can read in the link below: https://docs.djangoproject.com/pt-br/1.9/ref/contrib/postgres/fields/


You can store virtually any object using a Django Pickle Field, ala this snippet:

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


Storing a list of strings in Django model:

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

and you can call it like this:

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."      

Using one-to-many relation (FK from Friend to parent class) will make your app more scalable (as you can trivially extend the Friend object with additional attributes beyond the simple name). And thus this is the best way


My solution, may be it helps someone:

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)

참고URL : https://stackoverflow.com/questions/1110153/what-is-the-most-efficient-way-to-store-a-list-in-the-django-models

반응형