장고 모델에서 목록을 저장하는 가장 효율적인 방법은 무엇입니까?
현재 코드에 다음과 유사한 파이썬 객체가 많이 있습니다.
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위를 차지하기 때문입니다.요즘은 멋지고 우아한 해결책이 존재합니다.
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 확장자 사용).
그것은 보다 유리합니다.ArrayField
PostgreSQL보다 더 많은 데이터베이스에서 지원된다는 점에서 (장고 3.1 이후).
또한, 그것은 더 좋습니다.TextField
이것은 JSON을 저장하기 위해 의도적으로 만들어졌기 때문에 읽기와 같은 작업에 더 적은 단계가 필요합니다.
또한 이미 장고(추가 작업/유지보수 필요 없음)가 포함되어 있다는 점에서 사용자 지정 필드보다 더 좋습니다.
2023년 답변: 장고와 함께 사용하는 데이터베이스에 따라 다릅니다.
이 답변은 Postgre에 적용됩니다.SQL, MySQL 및 SQLite가 있습니다.
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
'programing' 카테고리의 다른 글
UITextView에서 클릭 링크를 가로채는 방법은 무엇입니까? (0) | 2023.06.05 |
---|---|
소수 자릿수 형식 지정(R) (0) | 2023.06.05 |
이미지가 작아도 UITableViewCell의 이미지 보기를 고정 크기로 만드는 방법 (0) | 2023.06.05 |
미학 및 gem_text를 사용할 때 범례에서 'a' 제거 (0) | 2023.06.05 |
R을 사용하여 압축된 데이터 파일 다운로드, 압축 풀기 및 데이터 가져오기 (0) | 2023.06.05 |