2017-11-13 4 views
5

Ich habe zwei Modelle Kategorie und Produkte.Anpassen eines Widgets für ManyToMany-Feld an ein Modell, die einen kreisförmigen ForeignKey zu sich haben

  • kann ein Produkt mehrere Kategorien
  • eine Kategorie haben mehrere Produkte haben kann.
  • Kategorien haben einen kreisförmigen Fremdschlüssel, für sich.
  • nicht alle Kategorien haben die gleiche Tiefe Ebene

Beispiel:

  • Kategorie A
    • Kategorie A_1
    • Kategorie A_2
      • Kategorie A_2_1
  • Kategorie B
  • Kategorie C
    • Kategorie C_1

models.py

class Product: 
    categories = models.ManyToManyField(Category) 
    name = models.CharField(max_length=255) 

class Category: 
    categories = models.ForeignKey(self) 
    name = models.CharField(max_length=255) 

As Form verwende ich eine Modelform:

class ProductForm(ModelForm): 
    class Meta: 
     model = Product 
     fields = ['categories', 'name', 'short_description', 'description'] 
     widgets = { 
      'categories': MyWidget, 
     } 

Was ich erreichen möchte:

Ich möchte eine bedingte wählen (narrow-Optionen) implementieren, auf Produktformularerstellung:

  1. Nur die obersten übergeordneten Kategorien (Ebene 0 A, B, C) sind verfügbar
  2. Der Benutzer wählt eine übergeordnete Kategorie aus. Wenn der Elternteil Kinder hat, erscheint ein neues Auswahlfeld mit seinen Kindern (Kategorie Stufe 1 A1, C1)
  3. Der Benutzer wählt eine Kategorie der Stufe 1 (A1, C1).Wenn die übergeordneten Kinder ein neues Auswahlfeld erscheint mit seinen Kindern (Stufe 2 A2)

    • Der Prozess wird wiederholt, bis keine Kinder sind availavable (rekursiv) hat ein Benutzer wählen Sie die „kleinste“ Kategorie in dem Baum
    • eine neue Schaltfläche ist verfügbar für den Benutzer mehr Kategorien hinzuzufügen, und starten Sie den 1-3 Prozess wieder
    • ich möchte die wählen tun, neue hinzufügen, wählen Sie mit Hilfe von JavaScript
    • On Form Submit ich nur die letzten Kinder schicken wollen Kategorien

Optionen Ich dachte:

  1. Ändern Sie die ManyToMany coresponding Standard Felder - sieht aus wie es keine guten Haken und/oder Erbschaft
  2. Verwenden Sie ein Nicht-Standard-benutzerdefinierten Feld instean von ManyToMany (wie Charfield) - komplexer auf sauberem, sparendem Form
  3. Änderung/vererbt das Widget. Meine Fragen ist, wie die Daten in das Standardfeld senden auf einreichen und erhalten/zeigen sie auf bearbeiten

Praktisch, lassen Sie uns sagen, ich habe 7 Wählen Sie Kästen, mit den Werten für jeden:

  1. Parent1-> Child11-> Child111
  2. Parent2-> Child21
  3. Parent3-> Child31-> Child311

Wie kann ich mich auf Browser (mit anderen Daten) einreichen Django sagen Sie zu schicken ManyToMany das letzte Kind in allen drei von ihnen

Ich kann sie mit Javascript sammeln, aber ich muss Django sagen, diese Daten zu bekommen, das ist, was Sie brauchen.

Ich brauche Hilfe als Code und Hinweis, wie dies zu tun ist.

enter image description here

+0

Wie sieht die HTML-Vorlage aus? Hast du irgendeine Logik wie if Statements zur Verfügung gestellt? Ich denke, das ist, wo Ihre Lösung liegt .. – johnashu

+0

die HTML-Vorlage ist es egal, das Problem ist, dass die Informationen, die ich brauche in Bezug auf die Beziehung zwischen Eltern und Kindern und Tiefe der Kategorie, die es nicht an die Vorlage gesendet wird . Ich muss das Standardfeld überschreiben, das von ManyToMany zugewiesen wird. Ich verweise auf das 'interne' Feld ModelSelectMultiple – user3541631

Antwort

2

Django ermöglicht es Ihnen, das Modell definieren Sie in einem ForeignKey oder ManyToManyField als '<app_name>.<model_name>' Zeichenfolge anstatt zu dem Modell zu importieren und die Zuordnung direkt verweisen. Dies löst viele Probleme, insbesondere zirkuläre Importe.


Vorausgesetzt, dass Sie die Apps categories mit einem Category Modell haben und products mit einem Product Modell, das:

products/models.py:

class Product: 
    categories = models.ManyToManyField(Category) 
    name = models.CharField(max_length=255) 

categories/models.py:

class Category: 
    categories = models.ManyToManyField(self) 
    name = models.CharField(max_length=255) 

direkt übersetzen können, was Sie brauchen:

products/models.py:

class Product: 
    categories = models.ManyToManyField('categories.Category') 
    name = models.CharField(max_length=255) 

categories/models.py:

class Category: 
    categories = models.ManyToManyField('self') 
    name = models.CharField(max_length=255) 

Mit diesem können Sie beliebig viele Kategorien, wie Sie wollen:

category_one = Category.create(name='Category one') 
category_two = Category.create(name='Category two') 
category_three = Category.create(name='Category three') 
category_three.categories.add(category_one, category_two) 
some_product = Product.create(name='Test Product') 
some_product.categories.add(category_three) 

(ManyToManyField docs)

Es ist auch wichtig zu beachten, dass bei jeder Python-Klasse self nicht die Klasse selbst ist - es ist die Instanz. Sie können es also nicht außerhalb einer Instanzmethode referenzieren, es gibt eine gute Erklärung dafür, warum here. Der einzige Grund dafür, dass die 'self' Zeichenkette hier funktioniert, ist, dass Django das in die Klasse übersetzt, in der sie sich befindet, categories.Category - es könnte also eine gute Idee sein, 'self' durch categories.Category zu ersetzen, um explizit zu sein.

+0

Ich verstehe, was Django macht, das ist nicht das Problem, ich muss das Standard 'interne' Feld von Django für ManytoMany überschreiben und auch ein benutzerdefiniertes Widget erstellen – user3541631

Verwandte Themen