programing

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

batch 2023. 6. 5. 23:45
반응형

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

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

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?

목록이 파이썬에서 매우 일반적인 데이터 구조이기 때문에, 저는 그것을 위한 장고 모델 필드가 있을 것이라고 예상했습니다.다대다 또는 1대다 관계를 사용할 수 있다는 것을 알고 있지만 코드에서 추가적인 지시를 피하고 싶었습니다.

편집:

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

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

그것을 확실히 염두에 두고, 이것을 해봅시다!앱이 특정 지점에 도달하면 데이터를 정규화하지 않는 것이 매우 일반적입니다.올바르게 수행하면 더 많은 하우스키핑 비용으로 수많은 값비싼 데이터베이스 검색을 절약할 수 있습니다.

list친구 이름의 경우 액세스 시 목록을 반환하는 사용자 지정 장고 필드 클래스를 만들어야 합니다.

David Cramer는 자신의 블로그에 분리된 가치 필드를 만드는 가이드를 게시했습니다.코드는 다음과 같습니다.

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)

이 코드의 논리는 데이터베이스에서 Python으로, 또는 그 반대로 값을 직렬화 및 역직렬화하는 것을 다룹니다.이제 모델 클래스에서 사용자 지정 필드를 쉽게 가져와서 사용할 수 있습니다.

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

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

이 관계가 1대 다의 외국인 키 관계로 더 잘 표현되지 않을까요?Friends요? 나는 이해합니다.myFriends그냥 문자열이지만 저는 더 나은 디자인이 그것을 만드는 것이라고 생각합니다.Friend모델을 하고 가지고 있습니다.MyClass결과 테이블에 대한 외부 키 관계를 포함합니다.

장고에 목록을 저장하는 간단한 방법은 목록을 JSON 문자열로 변환한 다음 모델에서 텍스트로 저장하는 것입니다.그런 다음 (JSON) 문자열을 다시 파이썬 목록으로 변환하여 목록을 검색할 수 있습니다.방법:

"리스트"는 다음과 같이 장고 모델에 저장됩니다.

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

Postgres와 함께 Django >= 1.9를 사용하는 경우 ArrayField의 장점을 활용할 수 있습니다.

데이터 목록을 저장하는 필드입니다.대부분의 필드 유형을 사용할 수 있습니다. 다른 필드 인스턴스를 base_field로 전달하기만 하면 됩니다.크기를 지정할 수도 있습니다.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이 언급했듯이 요소를 직접 쿼리할 수도 있습니다.문서 참조

이 질문은 오래된 질문이며, 그 이후로 장고 기술이 크게 변경되었을 것이므로 이 답변은 장고 버전 1.4를 반영하며 v 1.5에 적용될 가능성이 높습니다.

장고는 기본적으로 관계형 데이터베이스를 사용하므로 사용해야 합니다.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

그러나 이러한 관계는 대칭적입니다. 조셉이 밥의 친구라면 밥은 조셉의 친구입니다.

2021년에는 이 게시물이 구글 결과에서 1위를 차지하기 때문입니다.요즘은 멋지고 우아한 해결책이 존재합니다.

MySql 문서

PostgreSQl

from django.db.models import CharField, Model
from django_mysql.models import ListCharField

class Person(Model):
    name = CharField()
    post_nominals = ListCharField(
        base_field=CharField(max_length=10),
        size=6,
        max_length=(6 * 11)  # 6 * 10 character nominals, plus commas
    )

형태

from django.db.models import IntegerField, Model
from django_mysql.models import ListTextField

class Widget(Model):
    widget_group_ids = ListTextField(
        base_field=IntegerField(),
        size=100,  # Maximum of 100 ids in list
    )

쿼리

>>> Person.objects.create(name='Horatio', post_nominals=['PhD', 'Esq.', 'III'])
>>> Person.objects.create(name='Severus', post_nominals=['PhD', 'DPhil'])
>>> Person.objects.create(name='Paulus', post_nominals=[])

>>> Person.objects.filter(post_nominals__contains='PhD')
[<Person: Horatio>, <Person: Severus>]

>>> Person.objects.filter(post_nominals__contains='Esq.')
[<Person: Horatio>]

>>> Person.objects.filter(post_nominals__contains='DPhil')
[<Person: Severus>]

>>> Person.objects.filter(Q(post_nominals__contains='PhD') & Q(post_nominals__contains='III'))
[<Person: Horatio>]

이것은 결국 관계형 데이터베이스에 포함되어야 합니다.관계를 활용하는 것이 이 문제를 해결하는 일반적인 방법입니다.목록을 개체 자체에 저장해야 하는 경우 쉼표로 구분하여 문자열에 저장한 다음 문자열을 목록으로 분할하는 액세스 도구 함수를 제공할 수 있습니다.이렇게 하면 최대 문자열 수가 제한되고 효율적인 쿼리가 손실됩니다.

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

Postgres를 사용하는 경우 다음과 같은 방법을 사용할 수 있습니다.

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/

Django 모델에서 문자열 목록 저장:

class Bar(models.Model):
  foo = models.TextField(blank=True)
    
  def set_list(self, element):
    self.foo += "," + element if self.foo else element
    
  def get_list(self):
    return self.foo.split(",") if self.foo else None

이렇게 부를 수 있습니다.

bars = Bar()
bars.set_list("str1")
bars.set_list("str2")
bar_list = bars.get_list()

for bar in bar_list:
   print bar    

장고 피클 필드를 사용하여 사실상 모든 개체를 저장할 수 있습니다.

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

일대일 관계(친구에서 부모 클래스로 FK)를 사용하면 앱의 확장성이 향상됩니다(단순한 이름 이외의 추가 속성으로 친구 개체를 확장할 수 있음).그래서 이것이 가장 좋은 방법입니다.

ListCharField는 CharField의 하위 클래스이므로 CharField 옵션도 설정할 수 있습니다.가장 중요한 것은 데이터베이스에서 예약할 문자 수를 결정하기 위해 max_length를 설정해야 한다는 것입니다.

인스턴스화 예제:

from django.db.models import CharField, Model
from django_mysql.models import ListCharField


class Person(Model):
    name = CharField()
    post_nominals = ListCharField(
        base_field=CharField(max_length=10),
        size=6,
        max_length=(6 * 11),  # 6 * 10 character nominals, plus commas
    )

Postgre를 사용하는 경우와 같이 잠재적 경로를 다루는 다양한 답변이 있습니다.SQL에서는 목록을 JSON 문자열로 변환하거나 사용자 지정 Django 모델 필드를 만들거나 새 모델을 만든 다음 여기서 Daniel Roseman이 언급처럼 ForeignKey를 사용합니다.

여전히, 이 사용 사례에 대한 제가 가장 좋아하는 (ForeignKey 옵션과 함께) 한 가지가 누락되었습니다.좀 더 구체적으로 말하자면, 저는 더 나은 옵션으로 참조하고 싶습니다.문서에 따르면,

JSON 인코딩 데이터를 저장하기 위한 필드입니다.Python에서 데이터는 사전, 목록, 문자열, 숫자, 부울 및 없음과 같은 Python 기본 형식으로 표시됩니다.

JSONField는 MariaDB, MySQL 5.7.8+, Oracle, Postgre에서 지원됩니다.SQL 및 SQLite(JSON1 확장자 사용).

그것은 보다 유리합니다.ArrayFieldPostgreSQL보다 더 많은 데이터베이스에서 지원된다는 점에서 (장고 3.1 이후).

또한, 그것은 더 좋습니다.TextField이것은 JSON을 저장하기 위해 의도적으로 만들어졌기 때문에 읽기와 같은 작업에 더 적은 단계가 필요합니다.

또한 이미 장고(추가 작업/유지보수 필요 없음)가 포함되어 있다는 점에서 사용자 지정 필드보다 더 좋습니다.

2023년 답변: 장고와 함께 사용하는 데이터베이스에 따라 다릅니다.

이 답변은 Postgre에 적용됩니다.SQL, MySQLSQLite있습니다.


PostgreSQL 요약: 예! PostgreSQL에ArrayField그리고 간단합니다.모델 코드:

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

class myDjangoModelClass(models.Model):
    myName = models.CharField(max_length=64)
    myFriends = ArrayField(models.CharField(max_length=64)

Postgre를 사용하는 Django의 배열 필드에 대한 설명서SQL 여기 있습니다.


MySQL 즉, 예! MySQL은 목록도 다룰 수 있고, 또한 간단합니다.모델 코드:

from django.db import models
from django_mysql.models import ListCharField

class myDjangoModelClass(models.Model):
    myName = models.CharField(max_length=64)
    myFriends = ListCharField(base_field=CharField(max_length=64))

여기 MySQL이 있는 장고의 문서 목록 필드.


SQLite 요약: 아니요.SQLite가 포함된 Django는 목록을 직접 지원하지 않습니다.다른 답변에 있는 해킹/해결 방법 중 하나를 사용하거나, 다른 답변에도 설명된 JSON 필드를 사용하거나, 현재 승인된 답변에 설명된 대로 외부 키를 사용하여 "적절한 방법"으로 수행할 수 있습니다.저는 아마도 여러 사람들이 같은 친구를 가질 수 있기 때문에 외국인 키보다는 ManyToMany가 여기에 가는 올바른 방법이라고 주장할 것입니다.모델 코드:

from django.db import models

class myDjangoModelClass(models.Model):
    myName = models.CharField(max_length=64)

class myFriend(models.model):
    friend_name = models.CharField(max_length=64)
    myName = models.ManyToManyField(myDjangoModelClass, related_name='myFriends')

SQLite를 사용한 장고의 ManyToMany 필드에 대한 문서입니다.

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

반응형