2017-11-13 91 views
5

Mam dwa modele Kategoria i produkty.Dostosowywanie widżetu dla pola ManyToMany do modelu z okrągłym kluczem obcym dla siebie

  • produkt może mieć wiele kategorii
  • do kategorii może mieć wiele produktów.
  • Kategorie mają okrągły klucz obcy, sam w sobie.
  • nie wszystkie kategorie mają ten sam poziom Głębokość

Przykład:

  • Kategoria A
    • Kategoria a_1
    • kategoria A_2
      • Kategoria A_2_1
  • Kategoria B
  • Kategoria C
    • Kategoria 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) 

jako forma Używam ModelForm:

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

Co chcę osiągnąć:

Chcę zaimplementować warunkowego wybrać (wąskie Opcje) na tworzeniu postaci produktu:

  1. Dostępne są tylko górne kategorie nadrzędne (poziom 0 A, B, C).
  2. Użytkownik wybiera kategorię nadrzędną. Jeśli rodzic ma dzieci, pojawia się nowe pole wyboru ze swoimi dziećmi (poziom kategorii 1 A1, C1)
  3. Użytkownik wybiera kategorię poziomu 1 (A1, C1).Jeśli rodzic ma dzieci nowy Zaznacz pole pojawia się ze swoimi dziećmi (poziom 2 A2)

    • Proces jest powtarzany, dopóki dzieci nie są availavable (rekurencyjne), użytkownik wybierz kategorię „najmniejszy” w drzewie
    • Nowy przycisk jest dostępny dla użytkownika, aby dodać więcej kategorii i ponownie rozpocząć proces od nowa
    • Chcę zrobić zaznaczenie, dodać nowy wybór przy użyciu JavaScriptu
    • W formularzu Prześlij Chcę wysłać tylko ostatnie dzieci kategorie

Opcje pomyślałem:

  1. Zmiany te ManyToMany coresponding domyślne Fields - wygląda nie ma dobrych haki i/lub dziedziczenie
  2. użycie non-default pole niestandardowe instean z ManytoMany (jak Charfield) - bardziej złożone na czystym, oszczędnym formularzu
  3. Zmień/Odziedzicz widżet. Moje problemy to jak wysyłać dane do standardowego pola po złożyć i uzyskać/pokazać go edytować

Praktyczne, powiedzmy mam 7 Wybierz Skrzynki, z wartościami dla każdego:

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

Jak mogę powiedzieć Django w przeglądarce przesłać (wraz z innymi danymi), aby wysłać do ManyToany to ostatnie Dziecko we wszystkich trzech z nich

Mogę je zbierać z Javascript, ale muszę powiedzieć Django, żeby dostał te dane, to jest to, czego potrzebujesz.

Potrzebuję pomocy jako kodu i wskazania, jak to zrobić.

enter image description here

+0

Jak wygląda szablon HTML? czy podałeś jakąś logikę, na przykład wyciągi? Myślę, że to może być miejsce, w którym znajduje się twoje rozwiązanie. – johnashu

+0

Szablon HTML nie ma znaczenia, problemem jest to, że potrzebuję informacji dotyczących relacji między rodzicem a dziećmi i poziomu głębi kategorii, do której nie jest wysyłany szablon . Muszę nadpisać domyślne pole przydzielone przez ManyToMany. Mam na myśli "wewnętrzny" Field ModelSelectMultiple – user3541631

Odpowiedz

2

Django pozwala na zdefiniowanie modelu masz odniesienie w ForeignKey lub ManyToManyField jako '<app_name>.<model_name>' ciąg zamiast importować model i przypisywanie go bezpośrednio. Rozwiązuje to wiele problemów, w szczególności importowanie okrężne.


Zakładając, że aplikacje categories z Category modelu i products z Product modelu to:

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) 

można bezpośrednio przełożyć na to, czego potrzebujesz:

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) 

z tym, można mieć wiele kategorii, jak chcesz:

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)


Należy również zauważyć, że w przypadku każdej klasy Pythona self nie jest samą klasą - jest to instancja. Więc nie można odwoływać się do niego poza metodą instancji, istnieje dobre wyjaśnienie, dlaczego here. Jedyny powód, dla którego ciąg 'self' działa tutaj, ponieważ Django tłumaczy to na klasę, w której się znajduje, categories.Category - więc może być dobrym pomysłem zastąpienie 'self' z categories.Category, aby było jawne.

+0

Rozumiem, co robi Django, to nie jest problem, muszę nadpisać domyślne "wewnętrzne" Pole wybrane przez Django dla ManytoMany, a także utworzyć niestandardowy widget – user3541631