5

Diciamo che abbiamo un app chiamato armadio e ha alcuni modelli:Django: CreateView con campi pre-popolati e non modificabili specificate dalla stringa di interrogazione

# 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 

Uso generico vista di dettaglio, è facile fare la conf URL per i dettagli su ciascuno di questi:

#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'), 
) 

quello che mi piacerebbe fare dopo è di definire i punti di vista che creeranno un nuovo oggetto di ogni tipo. Mi piacerebbe farlo con una versione estesa di CreateView che sarà in grado di gestire i dati su campi precompilati.

In particolare, voglio il seguente comportamento:

  1. Se visito /closet/outfit/new voglio ottenere uno standard ModelForm per il modello Outfit con tutto in bianco e tutto modificabile.
  2. Se visito lo /closet/outfit/new/?shirt=1 voglio vedere tutti i campi che ho visto nel caso 1) ma voglio che il campo della camicia sia prepopolato con la maglietta con pk = 1. Inoltre, voglio che il campo della maglietta sia visualizzato come non modificabile. Se il modulo viene inviato e ritenuto non valido, quando il modulo viene nuovamente visualizzato, desidero che il campo della maglieria continui a essere non modificabile.
  3. Se visito lo /closet/outfit/new/?shirt=1&trouser=2 voglio vedere tutti i campi che ho visto nel caso 1) ma ora entrambi i campi camicia e pantalone dovrebbero essere preopoulati e non modificabili. (Ad esempio, solo il campo footwear dovrebbe essere modificabile)

In generale, è possibile? Cioè la querystring può modificare la struttura della forma visualizzata in questo modo? Voglio realizzare questo nel modo più DRY possibile. Il mio istinto mi dice che questo dovrebbe essere fattibile con le viste basate sulla classe e forse comporterebbe model_form_factory ma non riesco a ottenere la logica direttamente nella mia mente. In particolare, non ero sicuro se fosse possibile avere la vista basata sulla classe per accedere allo request.REQUEST (ovvero i parametri request.POST o request.GET) nel momento in cui si sta costruendo lo ModelForm.

Forse è possibile solo se utilizzo parole chiave di querystring diverse per i campi bloccati. Cioè forse l'URL deve essere: /closet/outfit/new/?lock_shirt=1 e /closet/outfit/new?lock_shirt=1&lock_trouser=2. Forse se fosse fatto in questo modo il gestore POST sarebbe stato consegnato sia un elenco di campi bloccati (ai fini della visualizzazione del modulo nel browser) insieme a un elenco regolare di tutti i campi del modello allo scopo di creare effettivamente l'oggetto.

Perché voglio questo: Nel modello per il footwear_detail io vorrei essere in grado di fare un tag come

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

In generale, sarebbe davvero utile per essere in grado di fare collegamenti con le forme la cui "struttura" (non solo valori) cambia a seconda della querystring passata.


In risposta alla grande suggestione da Berislav Lopac:

Così sono andato avanti e ha fatto:

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

Questo mi ottiene il 90% di quello che mi serve. Ma lascia che apporti un po 'di più alla situazione.Suppongo di aggiungere due campi al modello Outfit: headgear = models.ManyToManyField('headgear') e awesomeness_rating = models.FloatField().

due problemi:

  1. Se visito /closet/outfit/new/?awesomeness_rating=10 poi il mio modulo di pre-riempie di [u'10'] invece di riempire con 10. C'è un filtro che dovrei usare nel mio modello o un po 'di elaborazione che posso aggiungere alla mia vista per rendere la formattazione più appropriata?
  2. Se voglio specificare alcuni pezzi di copricapo, qual è il formato giusto per passare quello che sembra un elenco python attraverso una stringa di query? Cioè dovrei fare /closet/outfit/new/?headgear=1,2,3? Se è così, Django capirà correttamente che mi piacerebbe preselezionare i 3 pezzi di copricapo con quegli ID?

continuare a lavorare su questo ...

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 

Questo sembra di uccidere 2 piccioni con una fava: dati numerici viene costretto da unicode a numerica e si appiattisce liste quando possibile (come inteso). È necessario verificare se questo funziona su campi multivalore.

risposta

4

È self.request, ovunque in un CBV. :-)

OK, lasciatemi rendere questa risposta più completa. Fondamentalmente, quello che vuoi è il metodo get_initial, che è fornito dallo FormMixin. Sovrascrivi per popolare i valori iniziali per i tuoi campi.

+0

Questo è un ottimo primo passo. Ho due domande su come implementarlo. Si prega di vedere le modifiche al post originale di cui sopra. Penso che per i miei scopi, finirò per percorrere questa strada dal momento che ottiene l'essenza. Ma nella misura in cui gli altri potrebbero preoccuparsi del problema originale: qualcuno ha una soluzione alla domanda originale ... invece di pre-compilare il modulo con i dati iniziali, c'è un modo per visualizzare effettivamente i campi pre-compilati come bloccato? – 8one6

+0

Un modo è quello di aggiungere l'attributo 'readonly' all'elemento di input, magari nel metodo' get_form' della vista. Puoi prendere i campi 'request.GET' (o anche meglio usare' get_initial' per evitare la duplicazione del codice) e modificare il widget di ogni campo che ha un valore lì. –

+0

Grazie. Sono abbastanza nuovo a questo e sto ancora avendo problemi con la formattazione Unicode. Capisco che tutte le voci in un QueryDict che ottengo da 'request.GET' saranno formattate come stringhe Unicode. Esiste un modo generale per convertire un unicode nel suo tipo di dati Python nativo? Quindi se faccio '/ closet/outfit/new /? Awesomeness_level = 10' voglio assicurarmi che il campo prepopuli con 10 invece di [u'10] ... – 8one6