2008-12-16 7 views
7

Digamos que quería tener un proyecto, uno a muchos con elementos para hacer y quería reordenar arbitrariamente los elementos de tareas pendientes.en SQL, o Django ORM, ¿cuál es la forma convencional de tener un pedido uno a muchos?

En el pasado, he agregado un campo de pedido numerado, y cuando alguien quiere cambiar el orden, tenía que actualizar todos los artículos con sus nuevos números de pedido. Este es probablemente el peor enfoque, ya que no es atómico & requirió varias actualizaciones.

Me di cuenta de que Django tiene un CommaSeparatedIntegerField de múltiples valores que podría contener el orden al almacenar las claves ordenadas en los ítems de la tabla de tareas pendientes en un campo de la tabla del proyecto.

He considerado un sistema decimal dewey donde si quisiera tomar el elemento 3 y ponerlo entre 1 y 2, cambiaría su número de orden a 1.5.

Algo me dice que hay una opción más fácil que me falta ... aunque

¿Cómo darle fin a una relación de uno a muchos?

Respuesta

5

Odio este problema ... y me encuentro con él todo el tiempo.

Para mi sitio más reciente de Django, teníamos un boletín que contenía N artículos y, por supuesto, el orden era importante. Asigné la orden predeterminada como Article.id ascendente, pero esto falló si los Artículos se ingresaron en un orden diferente al "correcto".

En la página del boletín change_form.html agregué un poco de magia jQuery usando el plugin de interfaz (http://interface.eyecon.ro/). Muestro los títulos de los Artículos asociados y el usuario puede arrastrarlos a su gusto. Hay un controlador onChange que vuelve a calcular Article.id's en el campo article_order.

Enjoy,
Peter

para App = contenido, modelo = Newsletter, el siguiente está en plantillas/admin/content/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 %} 
1

Me he encontrado con esto tantas veces que me he decidido a gestionar estos dinámicamente en el BL o UI, y luego simplemente persistir el pedido a una columna especialmente diseñada una vez que el usuario esté satisfecho. SQL está diseñado de forma intempestiva para no gestionar pedidos, y siempre responde.

2

"añadido una orden/newslettter numerada campo "- bien.

"actualizar todos los artículos con sus nuevos números de pedido" - evitable.

Usa números con espacios.

  • Punto flotante. De esa forma, alguien puede insertar "1.1" entre 1 y 2. Encuentro que esto funciona bien, ya que la mayoría de las personas puede entender cómo funciona la secuencia. Y no tiene que preocuparse demasiado por la cantidad de espacio para salir, hay mucho espacio entre cada número.

  • En la carga inicial, numere los artículos por 100 o 1000 o algo con espacio entre cada uno. En este caso, debe adivinar cuántos dígitos debe dejar para reordenar.

  • Una posición separada por comas. Inicialmente, son todos (1,0), (2,0), (3,0), etc. Pero cuando quiera reorganizar las cosas, es posible que tenga que introducir (2,1) y (2,2) que van después (2,0) pero antes (3.0).

    Esto parece un poco complicado, pero a algunas personas les gusta este tipo de complejidad. Es esencialmente lo mismo que punto flotante, excepto que el número único se reemplaza por una tupla (número entero, fracción implícita). Y esto se extiende para manejar jerarquías.

+0

Nice. Me recuerda los números de línea en BASIC. :-) –

0

Ésta es una respuesta tardía a la pregunta, pero yo sólo quería meter su cuchara y señalan que los árboles B son una gran estructura de datos para este tipo de cosas, sobre todo si sus patrones de acceso no requieren usted para recuperar la lista completa a la vez.

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

2

he tenido este problema con dos proyectos que he trabajado en el último momento. Para mi solución de ejemplo, tengo un "Formulario" que tiene muchas "Variables" asignadas y el orden de las variables en el formulario debe ser ordenable. Así que han puesto en práctica lo siguiente:

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 

La clave de lo alto es el VariableOrder CommaSeparatedIntegerField es donde vamos a guardar el orden de las variables de la hoja, y vamos a utilícelo como una lista de Python, por lo que el valor predeterminado es [].

Para la plantilla, renderizo mis Variables en un archivo que vamos a hacer arrastrar y soltar (los elementos de lista que realmente uso tienen mucho más estilo relacionado con CSS e información sobre la variable).

<ul id="sortable"> 

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

</ul> 

Ahora vamos a hacer que la lista se arrastre y suelte para cambiar el orden. para que esto funcione es necesario tener el fragmento de AJAX CSRF de Django sitio en la cabeza

$(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(); 
}); 

La parte importante anterior es que "actualizar" llama a la función cada vez que hay un cambio de posición de cualquiera de los variables, que envía el AJAX. toArray on sortable junto con el stringify de JSON nos permite enviar los id de arriba a abajo de cada variable, que la vista utiliza de la siguiente manera. Nota: Guardo el objeto Form activo como una variable de sesión, pero en otro caso solo necesitaría llamar al objeto Form que deseaba cambiar el orden de.

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 

La clave de todo esto es que se puede utilizar este CommaSeparatedIntegerField como una lista mediante la evaluación de la cadena.Por ejemplo:

Adición de una variable:

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

Extracción de una variable:

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

Rendering las variables para:

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

Este es un primer borrador aproximado de lo que voy a usar, pero me está funcionando bien. La primera mejora obvia es la evaluación de que la lista de Python es un método en la clase. p.ej.

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

y luego a llamarlo Form.getVarOrder() cuando se quiere manipular la lista. En cualquier caso, con suerte esto ayuda.

JD

Cuestiones relacionadas