2010-10-08 25 views
13

Come rendere entry.category come istanza di CategoryProxy? Vedere codice per i dettagli:Modello proxy Django e ForeignKey

class Category(models.Model): pass 

class Entry(models.Model): 
    category = models.ForeignKey(Category) 

class EntryProxy(Entry): 
    class Meta: 
     proxy = True 

class CategoryProxy(Category): 
    class Meta: 
     proxy = True 

entry = EntryProxy.objects.get(pk=1) 
entry.category # !!! I want CategoryProxy instance here 

Fusioni dalla categoria a CategoryProxy è ok troppo, ma io non sono molto familiare con interni ORM per copiare correttamente stato interno ...

EDIT. Motivo: metodo che ho aggiunto al CategoryProxy e si desidera utilizzare lui:

EntryProxy.objects.get(pk=1).category.method_at_category_proxy() 

EDIT 2. Attualmente ho implementato in questo modo:

EntryProxy._meta.get_field_by_name('category')[0].rel.to = CategoryProxy 

ma sembra terribile ...

+0

Qual è il motivo particolare per cui si vuole fare questo? –

+0

Ho aggiunto il metodo a CategoryProxy e voglio usarlo come EntryProxy.objects.get (pk = 1) .category.method_at_category_proxy() –

risposta

11

Per passare da una classe del modello per una classe proxy senza colpire il database:

class EntryProxy(Entry): 
    @property 
    def category(self): 
     new_inst = EntryProxy() 
     new_inst.__dict__ = super(EntryProxy, self).category.__dict__ 
     return new_inst 

edit: il frammento di cui sopra non sembra lavorare su Django 1.4.

Dal Django 1.4, prendo tutti i campi di valore manualmente in questo modo:

class EntryProxy(Entry): 
    @property 
    def category(self): 
     category = super(EntryProxy, self).category 
     new_inst = EntryProxy() 
     for attr in [f.attname for f in category.__class__._meta.fields] + ['_state']: 
      setattr(new_inst, attr, getattr(category, attr)) 
     return new_inst 

Per passare da un set di query a una classe proxy bambino senza colpire database:

class CategoryProxy(Category): 
    @property 
    def entry_set(self): 
     qs = super(CategoryProxy, self).entry_set 
     qs.model = EntryProxy 
     return qs 
+0

+1 +1 grazie! Come sei arrivato a questo? Ero curioso di sapere se hai un post sul blog o qualcosa che spiega in dettaglio come funziona QuerySet.model ... –

+0

Per il primo l'ho trovato qui, in StackOverflow, per il secondo, ho trovato il mio sé stesso in un test di shell bpython. Piacere di vederlo aiutato. – christophe31

-1

Definire una proprietà category su EntryProxy che ricerca il CategoryProxy tramite il suo id:

La risposta di
class EntryProxy(Entry): 
    @property 
    def category(self): 
     cid = super(EntryProxy, self).category.id 
     return CategoryProxy.objects.get(id=cid) 

    class Meta: 
     proxy = True 
+1

Questo implica un hit del database per ogni ricerca di categoria! Cosa succede se stiamo andando in loop? –

0

Joseph Spiros a una delle mie domande potrebbe aiutare:

Django Inheritance and Permalinks

io non sono sicuro di come sarà il lavoro con i modelli proxy.

+0

Uno potrebbe probabilmente ottenere qualcosa di paragonabile aggiungendo un discriminatore o un campo del tipo di contenuto al modello di base e hackerando un gestore di modelli personalizzato. Tuttavia, non sono sicuro che ciò rifletta ciò che Vladimir intendeva. Potrebbe aver bisogno di punti di vista diversi sui suoi dati, quindi ha scelto i modelli proxy. Posso immaginare che voglia persino essere in grado di definire diverse categorie di modelli proxy e si aspetta che i riferimenti tra questi modelli siano risolti con i proxy della stessa categoria. Questo non sarebbe possibile se il tipo di proxy è memorizzato nel modello base. –

-1

adattamento leggermente la risposta di Bernd Petersohn , abbiamo quindi:

class EntryProxy(Entry): 
    @property 
    def category(self): 
     return CategoryProxy.objects.get(id=self.category_id) 

Questo dovrebbe essere più economico con il Banca dati. Per ulteriori miglioramenti, è possibile impostare un attributo privato (self._category) la prima volta che viene chiamato il metodo, quindi restituire tutte le volte successive.

+1

Downvoted perché questo ha un hit del database. – knite

2

Questa domanda ha già una risposta accettata, ma volevo postare questo per chiunque possa venire a cercare.

È possibile applicare una patch al modello in fase di esecuzione con il nuovo campo in modo che le relazioni funzionino come previsto.Un esempio completo può essere visto qui - https://gist.github.com/carymrobbins/8721082

from django.db.models.fields.related import ReverseSingleRelatedObjectDescriptor 

def override_model_field(model, field, field_name, column_name): 
    """Force override a field in a Django Model. 
    Usage: override_model_field(
     MyModel, models.ForeignKey(OtherModel), 'other', 'other_id') 
    :type model: django.db.models.base.ModelBase 
    :type field: django.db.models.fields.Field 
    :type field_name: basestring 
    :type column_name: basestring 
    """ 
    field.name = field_name 
    field.attname = column_name 
    for i, f in enumerate(model._meta.fields): 
     if f.name == field_name: 
      model._meta.fields[i] = field 
      break 
    else: 
     raise TypeError('Model {!r} does not have a field {!r}.' 
         .format(model, field_name)) 
    model.add_to_class(field_name, 
         ReverseSingleRelatedObjectDescriptor(field)) 
Problemi correlati