2013-10-22 18 views
11

Vorrei che la mia applicazione django servisse un elenco di campi di qualsiasi modello (questo aiuterà la GUI a costruirsi).Django: elenca tutti i rapporti inversi di un modello

Immaginate le classi (ignorare il fatto che tutti i campi della Steps potrebbe essere in Item, ho le mie ragioni :-))

class Item(models.Model): 
    name = models.CharField(max_length=100) 
    description = models.TextField() 

class Steps(models.Model): 
    item = models.OneToOneField('Item', related_name='steps') 
    design = models.BooleanField(default=False) 
    prototype = models.BooleanField(default=False) 
    production = models.BooleanField(default=False) 

Ora, quando voglio elencare i campi di un modello:

def get_fields(model): 
    return model._meta.fields + model._meta.many_to_many 

Ma vorrei anche ottenere l'elenco delle chiavi esterne "correlate" one-to-one ai miei modelli. Nel mio caso Item.steps non sarebbe in quella lista.

Ho trovato che model._meta.get_all_field_names include tutti i campi correlati.

Ma quando chiamo Item._meta.get_field_by_name('steps') restituisce una tupla in possesso di un RelatedObject, che non mi dica immediatamente se si tratta di un singolo relazione o uno-a-molti (voglio elencare invertita solo uno-a-uno relazioni).

Inoltre, posso usare questo pezzo di codice:

from django.db.models.fields.related import SingleRelatedObjectDescriptor 
reversed_f_keys = [attr for attr in Item.__dict__.values() \ 
        if isinstance(attr, SingleRelatedObjectDescriptor)] 

Ma io non sono molto soddisfatto di questo.

Qualsiasi aiuto, idea, suggerimenti sono i benvenuti!

Acclamazioni

+0

Quindi sì, ho una soluzione potenziale per il mio bisogno, ma sarei lieto di averne uno migliore :) –

risposta

0

E che dire di questo:

oneToOneFieldNames = [ 
    field_name 
    for field_name in Item._meta.get_all_field_names() 
    if isinstance(
     getattr(
      Item._meta.get_field_by_name(field_name)[0], 
      'field', 
      None 
     ), 
     models.OneToOneField 
    ) 
] 

relatedObject possono avere un attributo campo per le relazioni. Devi solo verificare se questo è un campo OneToOne e puoi recuperare solo quello che vuoi

3

Ho scoperto che ci sono metodi di Model._meta che possono darmi quello che voglio.

my_model = get_model('app_name','model_name') 
# Reverse foreign key relations 
reverse_fks = my_model._meta.get_all_related_objects() 
# Reverse M2M relations 
reverse_m2ms = my_model._meta.get_all_related_many_to_many_objects() 

Analizzando il contenuto delle relazioni, posso indovinare se il campo "diretta" era un OneToOneField o qualsiasi altra cosa.

5

Questo è stato modificato (in 1.8 credo) e la risposta di Olivier non funziona più. Secondo il docs, il nuovo modo è

[f for f in User._meta.get_fields() 
    if f.auto_created and not f.concrete] 

Questo include uno-a-uno, molti-a-uno, e molti-a-molti.

+0

Grazie per l'avviso sulla deprecazione. Mi salverà il mal di testa quando eseguo l'upgrade a 1.10 :) (bloccato per ora con 1.6) –

+0

Dio Non posso credere di non averlo mai pensato prima, quindi se è auto_created e non concreto sarà sempre una relazione inversa? – Mojimi

+0

C'è un problema con questa soluzione, ma elenca anche molte relazioni che hanno un programma, ho trovato un modo per filtrarle ma è molto noioso – Mojimi

Problemi correlati