в SQL или Django ORM, каков обычный способ упорядочить один-ко-многим? - PullRequest
7 голосов
/ 16 декабря 2008

Скажем, я хотел иметь проект, и один-ко-многим с делами, и хотел произвольно переупорядочить товары?

Раньше я добавлял пронумерованное поле заказа, и когда кто-то хотел изменить заказ, приходилось обновлять все позиции новыми номерами заказов. Вероятно, это худший подход, поскольку он не атомарный и требует нескольких обновлений.

Я заметил, что у Django есть многозначное поле CommaSeparatedIntegerField, которое может содержать порядок, храня упорядоченные ключи к элементам в таблице элементов списка дел прямо в одном поле таблицы проекта.

Я обдумал десятичную систему Дьюи, где, если бы я хотел взять пункт 3 и поставить его между 1 и 2, я бы изменил его номер заказа на 1,5.

Что-то говорит мне, что есть более простой вариант, который я упускаю, хотя ...

Как бы вы отдали приказ отношениям «один ко многим»?

Ответы [ 5 ]

5 голосов
/ 17 декабря 2008

Я ненавижу эту проблему ... и постоянно сталкиваюсь с ней.

Для моего самого последнего сайта Django у нас был информационный бюллетень, который содержал N статей, и, конечно, порядок был важен. Я назначил порядок по умолчанию как восходящий Article.id, но это не удалось, если статьи были введены не в «правильном» порядке.

На странице новостного бюллетеня change_form.html я добавил немного магии jQuery с помощью плагина Interface (http://interface.eyecon.ro/).. Я показываю заголовки связанных статей, и пользователь может перетаскивать их по своему усмотрению. обработчик onChange, который заново вычисляет значения Article.id в поле article_order.

Наслаждайтесь
Питер

Для app = content, model = Newsletter, в шаблоны / администратора / содержание / newslettter / change_form.html

{% extends 'admin/change_form.html' %}

{% block form_top %}{% endblock %}
{% block extrahead %}{{ block.super }}
<script type="text/javascript" src="/media/js/jquery.js"></script>
<script type="text/javascript" src="/media/js/interface.js"></script>
<script>
$(document).ready(
    function () {
        $('ol.articles').Sortable(
            {
                accept :        'sortableitem',
                helperclass :   'sorthelper',
                activeclass :   'sortableactive',
                hoverclass :    'sortablehover',
                opacity:        0.8,
                fx:             200,
                axis:           'vertically',
                opacity:        0.4,
                revert:         true,
                trim:           'art_',
                onchange:
                    function(list){
                        var arts = list[0].o[list[0].id];
                        var vals = new Array();
                        var a;
                        for (a in arts) {
                            vals[a] = arts[a].replace(/article./, '');
                        }
                        $('#id_article_order').attr('value', vals.join(','));
                    }
            });
    }
);
</script>
{% endblock %}

{% block after_related_objects %}
{% if original.articles %}
<style>
.sortableitem {
    cursor:move;
    width: 300px;
    list-style-type: none;
    }
</style>

<h4>Associated Articles</h4>
<ol class="articles" id="article_list">
{% for art in original.articles %}
    <li id="article.{{art.id}}" class="sortableitem">{{art.title}}</li>

{% endfor %}
</ol>
{% endif %}
{% endblock %}
2 голосов
/ 17 октября 2012

У меня была эта проблема с двумя проектами, над которыми я работал в последнее время. Для моего примера решения у меня есть «Форма», которой назначено много «Переменных», и порядок переменных в форме должен быть сортируемым. Поэтому я реализовал следующее:

models.py

class Form(models.Model):
    FormName = models.CharField(verbose_name="Form Name:", max_length=40)
    VariableOrder = models.CommaSeparatedIntegerField(default="[]", editable=False)

    def __unicode__(self):
        return "%s" % (self.FormName)

class Variable(models.Model):
    FormID = models.ForeignKey(Form, default=0, editable=False, related_name="Variable")
    VarName = models.CharField(max_length=32, verbose_name="Name of variable in the database:") 

    def __unicode__(self):
        return "%s" % self.VarName

Ключ сверху - VariableOrder. CommaSeparatedIntegerField - это место, где мы собираемся хранить порядок переменных в форме, и мы собираемся использовать его в качестве списка Python, поэтому по умолчанию используется [].

Для шаблона я отображаю свои Переменные в виде, который мы собираемся сделать перетаскиваемым для сортировки (элементы списка, которые я на самом деле использую, имеют гораздо больше стилей, связанных с CSS и информацией о Переменной).

<ul id="sortable">

{% for Variable in VarList %}
    <li id="{{ Variable.id }}">{{ Variable }}</li>
{% endfor %}

</ul>

Теперь мы собираемся перетаскивать список для изменения порядка. Чтобы это работало, у вас должен быть фрагмент AJAX CSRF с сайта Django в голове

    $(function() {
    $("#sortable" ).sortable({
        placeholder: "ui-state-highlight",
        update: function(event, ui){
            $.ajax({
            type:"POST",
            url:"{% url builder.views.variableorder %}",
            data: {Order: JSON.stringify($('#sortable').sortable('toArray')) },
            success: function(data){
            // Do stuff here - I don't do anything.
            }
          });
        }
    });
    $( "#sortable" ).disableSelection();
});

Важной частью выше является то, что «update» вызывает функцию каждый раз, когда происходит изменение позиции любой из переменных, которые отправляет AJAX. Метод toArray для sorttable вместе с JSON stringify заставляет нас отправлять идентификаторы сверху вниз для каждой переменной, которая используется представлением следующим образом. Примечание. Я сохраняю активный объект Form как переменную сеанса, но в другом случае вам просто нужно вызвать объект Form, для которого вы хотите изменить порядок.

def variableorder(request):
    if request.is_ajax():
        Order = request.POST['Order']
        updateOrder = request.session['FormID']
        updateOrder.VariableOrder = newOrder
        updateOrder.save()
        request.session['FormID'] = Form.objects.get(id=updateOrder.id)
        return HttpResponse("Order changed.")
    else:
        pass

Ключом всего этого является то, что вы можете использовать этот CommaSeparatedIntegerField в виде списка, оценивая строку. Например:

Добавление переменной :

aForm = Form.objects.get(id=1)
currentOrder = aForm.VariableOrder
currentOrder = eval(currentOrder)
newVar = Variable(stuff in here)
newVar.save()
currentOrder.append(newVar.id)
aForm.VariableOrder = currentOrder
aForm.save()

Удаление переменной :

aForm = Form.objects.get(id=1)
currentOrder = aForm.VariableOrder
currentOrder = eval(currentOrder)
# Variable ID that we want to delete = 3
currentOrder.remove(3)
aForm.VariableOrder = currentOrder
aForm.save()

Отображение переменных в заказе :

aForm = Form.objects.get(id=1)
currentOrder = aForm.VariableOrder
currentOrder = eval(currentOrder)
VarList = []
for i in currentOrder:
    VarList.append(Variable.objects.get(id=i))

Это грубый первый набросок того, что я собираюсь использовать, но он хорошо работает для меня. Очевидным первым улучшением является оценка в списке Python, являющаяся методом в классе. например.

def getVarOrder(self):
    return eval(self.VariableOrder)

, а затем просто вызовите Form.getVarOrder (), когда хотите манипулировать списком. В любом случае, надеюсь, это поможет.

JD

2 голосов
/ 18 декабря 2008

«добавлено пронумерованное поле заказа» - хорошо.

"обновить все элементы с их новыми порядковыми номерами" - можно избежать.

Используйте числа с пробелами.

  • С плавающей точкой. Таким образом, кто-то может вставить «1.1» между 1 и 2. Я считаю, что это работает хорошо, так как большинство людей могут понять, как работает секвенирование. И вам не нужно слишком беспокоиться о том, сколько места осталось - между каждым числом много места.

  • При начальной загрузке нумеруйте статьи по 100 или 1000 или что-то с пробелом между каждым. В этом случае вам нужно угадать, сколько цифр оставить для переупорядочения.

  • Позиция, разделенная запятыми. Первоначально они все (1,0), (2,0), (3,0) и т. Д. Но когда вы хотите изменить порядок вещей, вам, возможно, придется ввести (2,1) и (2,2) после (2,0), но до (3,0).

    Это выглядит довольно сложно, но некоторым людям нравится такая сложность. По сути, это то же самое, что и число с плавающей точкой, за исключением того, что одно число заменяется на кортеж (целое число, неявная дробь). И это распространяется на иерархии.

1 голос
/ 16 декабря 2008

Я сталкивался с этим так много раз, что остановился на динамическом управлении ими в BL или пользовательском интерфейсе, а затем просто сохранил порядок в специальном столбце, как только пользователь будет доволен. SQL просто специально разработан, чтобы не обрабатывать заказы, и он всегда сопротивляется.

0 голосов
/ 29 октября 2009

Это поздний ответ на вопрос, но я просто хотел вмешаться и указать, что B-деревья - это отличная структура данных для такого рода вещей, особенно если ваши шаблоны доступа не требуют от вас весь список сразу.

http://en.wikipedia.org/wiki/B-tree

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...