Джанго: пользовательское представление многих ко многим - PullRequest
0 голосов
/ 06 июня 2011

У меня есть модель, скажем, MyModel, у которой есть внешний ключ к другой модели, скажем, Tag.

class MyModel(models.Model):
    id=models.AutoField(primary_key=True)
    name=models.CharField(max_length=200)
    tag = models.ManyToMany(Tag)

У меня приблизительно 50 000 экземпляров MyModel, и у каждого MyModel может быть 100 тегов.

Если я использую описанную выше модель, я получу 5 000 000 записей в таблице, mymodel_tag, но я могу использоватьвсе функции ORM.

Однако, если я напишу пользовательские методы и обработаю указанное выше поле как массив целых чисел и напишу собственный код для извлечения / сохранения идентификаторов тегов, связанных с MyModel, у меня будет только 50 тыс. записей, но янужно будет написать собственный код для извлечения и т. д.

a) Я хочу знать плюсы и минусы обоих подходов!

b) Если мне придется использовать подход с использованием пользовательских массивовкак я могу сделать это эффективно.

Ответы [ 2 ]

1 голос
/ 06 июня 2011

Умм ..

tag = models.ManyToManyField(Tag)

?

С внешним ключом MyModel может быть связан только с одним и только одним Tag.Я, честно говоря, даже не уверен, как вы смогли дать каждому 100 Tags без дублирования каждого MyModel 100 раз.Если вы это делаете, неудивительно, что вам не нравятся результаты.

ManyToManyField создает таблицу соединения, которая будет состоять только из ссылки id (целое число) на MyModel и id (целое число)ссылка на Tag.Это самый компактный тип отношений, который вы когда-либо получите, и в любом случае это лучшая практика.

0 голосов
/ 08 июня 2011

Хотя я полностью согласен с тем, что говорит Крисдратт, но, к сожалению, я был вынужден сделать это иначе.Вот один из способов сделать это на http://djangosnippets.org/snippets/1200/:

from django.db import models
from django import forms

class MultiSelectFormField(forms.MultipleChoiceField):
    widget = forms.CheckboxSelectMultiple

    def __init__(self, *args, **kwargs):
        self.max_choices = kwargs.pop('max_choices', 0)
        super(MultiSelectFormField, self).__init__(*args, **kwargs)

    def clean(self, value):
        if not value and self.required:
            raise forms.ValidationError(self.error_messages['required'])
        if value and self.max_choices and len(value) > self.max_choices:
            raise forms.ValidationError('You must select a maximum of %s choice%s.'
                    % (apnumber(self.max_choices), pluralize(self.max_choices)))
        return value

class MultiSelectField(models.Field):
    __metaclass__ = models.SubfieldBase

    def get_internal_type(self):
        return "CharField"

    def get_choices_default(self):
        return self.get_choices(include_blank=False)

    def _get_FIELD_display(self, field):
        value = getattr(self, field.attname)
        choicedict = dict(field.choices)

    def formfield(self, **kwargs):
        # don't call super, as that overrides default widget if it has choices
        defaults = {'required': not self.blank, 'label': capfirst(self.verbose_name), 
                    'help_text': self.help_text, 'choices':self.choices}
        if self.has_default():
            defaults['initial'] = self.get_default()
        defaults.update(kwargs)
        return MultiSelectFormField(**defaults)

    def get_db_prep_value(self, value):
        if isinstance(value, basestring):
            return value
        elif isinstance(value, list):
            return ",".join(value)

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

    def contribute_to_class(self, cls, name):
        super(MultiSelectField, self).contribute_to_class(cls, name)
        if self.choices:
            func = lambda self, fieldname = name, choicedict = dict(self.choices):",".join([choicedict.get(value,value) for value in getattr(self,fieldname)])
            setattr(cls, 'get_%s_display' % self.name, func)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...