5

Powiedzmy mamy aplikację o nazwie garderoba i ma kilka modeli:Django: CreateView z pre-zaludnionych i nieedytowalnych dziedzinach określonych przez ciąg kwerendy

# closet.models.py 
class Outfit(models.Model): 
    shirt = models.ForeignKey(Shirt) 
    pants = models.ForeignKey(Trouser) 

class Shirt(models.Model): 
    desc = models.TextField() 

class Trouser(models.Model): 
    desc = models.TextField() 

class Footwear(models.Model): 
    desc = models.TextField 

Używanie zwykłych widok szczegółowy, to łatwo zrobić conf URL Aby uzyskać szczegółowe informacje na temat każdego z nich:

#urls.py 
urlpatterns = patterns('', 
    url(r'^closet/outfit/(?P<pk>\d+)$',  DetailView(model=Outfit),  name='outfit_detail'), 
    url(r'^closet/shirt/(?P<pk>\d+)$',   DetailView(model=Shirt),  name='shirt_detail'), 
    url(r'^closet/trouser/(?P<pk>\d+)$',  DetailView(model=Trouser),  name='trouser_detail'), 
    url(r'^closet/footwear/(?P<pk>\d+)$',  DetailView(model=Footwear),  name='footwear_detail'), 
) 

Chciałbym teraz zdefiniować widoki, które utworzą nowy obiekt każdego typu. Chciałbym to zrobić z rozszerzoną wersją CreateView, która będzie w stanie obsłużyć dane na wstępnie wypełnionych polach.

szczególności chcę następujące zachowanie:

  1. Gdybym odwiedzić /closet/outfit/new Chcę dostać standardowego ModelForm dla modelu Outfit we wszystko puste i wszystko edytowalne.
  2. Jeśli odwiedzę /closet/outfit/new/?shirt=1, chcę zobaczyć wszystkie pola, które widziałem w przypadku 1), ale chcę, aby pole koszulki było wstępnie wypełnione koszulką z pk = 1. Dodatkowo chcę, aby pole koszulek było wyświetlane jako nierejestrowalne. Jeśli formularz zostanie przesłany i zostanie uznany za nieważny, przy ponownym wyświetlaniu formularza chcę, aby pole koszulek było nadal nie do edycji.
  3. Jeśli odwiedzę /closet/outfit/new/?shirt=1&trouser=2, chcę zobaczyć wszystkie pola, które widziałem w przypadku 1), ale teraz zarówno koszula, jak i spodnie powinny być wstępnie przygotowane i nie nadające się do edycji. (Tj. Tylko pole footwear powinno być edytowalne.)

Generalnie jest to możliwe? To znaczy. czy querystring może w ten sposób modyfikować strukturę wyświetlanego formularza? Chcę to osiągnąć w możliwie najdrobniejszy sposób. Moje jelito mówi mi, że to powinno być wykonalne z poglądami opartymi na klasach i być może wymagałoby to model_form_factory, ale nie mogę uzyskać logiki prosto w mojej głowie. W szczególności nie byłem pewien, czy możliwe było uzyskanie dostępu opartego na klasach do parametrów request.REQUEST (tj. request.POST lub request.GET) w czasie, gdy konstruowany jest ModelForm.

Być może jest to możliwe tylko wtedy, gdy dla zablokowanych pól używam różnych słów kluczowych z zapytaniami. To znaczy. być może adres URL musi być: /closet/outfit/new/?lock_shirt=1 i /closet/outfit/new?lock_shirt=1&lock_trouser=2. Być może, jeśli zrobi się to w ten sposób, handler POST otrzyma zarówno listę zablokowanych pól (dla celów wyświetlania formularza w przeglądarce), jak i regularną listę wszystkich pól modelu w celu rzeczywistego utworzenia obiektu.

Dlaczego chcę to: W szablonie dla footwear_detail chciałbym być w stanie dokonać takiego znacznika

<a href="{% url outfit_new %}?footwear={{object.pk}}>Click to create a new outfit with this footwear!</a> 

W ogóle, to byłoby bardzo przydatne, aby móc tworzyć linki do formularzy których "struktura" (nie tylko wartości) zmienia się w zależności od przekazanego zapytania.


Odpowiadając na wielką sugestią BERISLAV Lopac:

Więc poszedł do przodu i tak:

class CreateViewWithPredefined(CreateView): 
    def get_initial(self): 
    return self.request.GET 

To dostaje mi 90% tego, co mi potrzeba. Ale pozwól mi nieco poprawić sytuację.Załóżmy, że dodaję dwa pola do modelu Strój: headgear = models.ManyToManyField('headgear') i awesomeness_rating = models.FloatField().

dwa problemy:

  1. Gdybym odwiedzić /closet/outfit/new/?awesomeness_rating=10 następnie moja forma wstępnie uzupełniane [u'10'] zamiast po prostu wypełnienie 10. Czy jest jakiś filtr, którego powinienem użyć w moim szablonie lub trochę przetwarzania mogę dodać do mojego widoku, aby formatowanie było bardziej odpowiednie?
  2. Jeśli chcę wstępnie określić kilka części nakrycia głowy, jaki jest odpowiedni format do przekazania czegoś, co wydaje się być listą pythonów w ciągu zapytania? To znaczy. powinienem zrobić /closet/outfit/new/?headgear=1,2,3? Jeśli tak, to czy Django poprawnie się zorientuje, że chciałbym wstępnie wybrać 3 części nakryć głowy z tymi identyfikatorami?

kontynuowania pracy na tym ...

class CreateViewWithPredefined(CreateView): 
    def get_initial(self): 
     initial = super(CreateView, self).get_initial() 
     for k, v in self.request.GET.iterlists(): 
      if len(v) > 1: 
       initial.update({ k : v }) 
      else: 
       initial.update({ k : v[0] }) 
     return initial 

Wydaje się zabić 2 pieczenie na jednym ogniu: Dane liczbowe zostaje zmuszony z Unicode do numerycznego i spłaszcza list, jeśli to możliwe (jak zamierzony). Musisz sprawdzić, czy to działa na polach wielowartościowych.

Odpowiedz

4

To jest self.request, gdziekolwiek w CBV. :-)

OK, pozwól mi udzielić bardziej wyczerpującej odpowiedzi. Zasadniczo, potrzebna jest metoda get_initial, która została wniesiona przez FormMixin. Zastąp go, aby zapełnić wartości początkowe dla twoich pól.

+0

To świetny pierwszy krok. Mam dwa pytania dotyczące sposobu wdrożenia tego. Zobacz zmiany w oryginalnym wpisie powyżej. Myślę, że dla moich celów, skończę tę drogę, ponieważ jest to najważniejsze. Ale w takim stopniu, w jakim inni mogą się przejmować pierwotnym problemem: czy ktoś ma rozwiązanie pierwotnego pytania ... zamiast po prostu wypełniać formularz danymi początkowymi, czy istnieje sposób, aby wstępnie wypełnione pola faktycznie wyświetlały się jako zamknięty? – 8one6

+0

Jednym ze sposobów jest dodanie atrybutu 'readonly' do elementu input, być może w metodzie' get_form' widoku. Możesz pobrać pola 'request.GET' (lub jeszcze lepiej użyć' get_initial' w celu uniknięcia duplikacji kodu) i zmodyfikować widget każdego pola, które ma tam wartość. –

+0

Dzięki. Jestem całkiem nowy w tym i nadal mam problemy z formatowaniem Unicode. Rozumiem, że wszystkie wpisy w QueryDict, które otrzymam z 'request.GET' będą sformatowane jako ciągi Unicode. Czy istnieje ogólny sposób konwertowania unicode na jego macierzysty typ danych python? Więc jeśli robię '/ closet/outfit/new /? Awesomeness_level = 10', chcę się upewnić, że pole wstępnie wypełni się 10 zamiast [u'10] ... – 8one6