In Django, come si può usare la vista generica update_object di Django per modificare forme di modelli ereditati?
-
03-07-2019 - |
Domanda
In Django, dati estratti da un'applicazione animali likeo:
A animals / models.py con:
from django.db import models
from django.contrib.contenttypes.models import ContentType
class Animal(models.Model):
content_type = models.ForeignKey(ContentType,editable=False,null=True)
name = models.CharField()
class Dog(Animal):
is_lucky = models.BooleanField()
class Cat(Animal):
lives_left = models.IntegerField()
E un animali / urls.py :
from django.conf.urls.default import *
from animals.models import Animal, Dog, Cat
dict = { 'model' : Animal }
urlpatterns = (
url(r'^edit/(?P<object_id>\d+)
Come si possono usare le viste generiche per modificare Dog e / o Cat usando lo stesso modulo?
vale a dire. L'oggetto form che viene passato a animals / animal_form.html sarà Animal, e quindi non conterrà alcuno dei dettagli per le classi derivate Dog and Cat. Come potrei avere Django passare automaticamente un modulo per la classe del bambino a animal / animals_form.html ?
Per inciso, sto usando Djangosnippets # 1031 per la gestione di ContentType, quindi Animal avrebbe ha un metodo chiamato as_leaf_class che restituisce la classe derivata.
Chiaramente, si potrebbero creare moduli per ogni classe derivata, ma si tratta di un sacco di duplicazioni non necessarie (poiché i modelli saranno tutti generici, essenzialmente {{form.as_p}}).
Per inciso, è meglio supporre che Animal sarà probabilmente una delle diverse classi base non correlate con lo stesso problema, quindi una soluzione ideale sarebbe generica.
Grazie in anticipo per l'aiuto.
, 'create_update.update_object', dict),
)
Come si possono usare le viste generiche per modificare Dog e / o Cat usando lo stesso modulo?
vale a dire. L'oggetto form che viene passato a animals / animal_form.html sarà Animal, e quindi non conterrà alcuno dei dettagli per le classi derivate Dog and Cat. Come potrei avere Django passare automaticamente un modulo per la classe del bambino a animal / animals_form.html ?
Per inciso, sto usando Djangosnippets # 1031 per la gestione di ContentType, quindi Animal avrebbe ha un metodo chiamato as_leaf_class che restituisce la classe derivata.
Chiaramente, si potrebbero creare moduli per ogni classe derivata, ma si tratta di un sacco di duplicazioni non necessarie (poiché i modelli saranno tutti generici, essenzialmente {{form.as_p}}).
Per inciso, è meglio supporre che Animal sarà probabilmente una delle diverse classi base non correlate con lo stesso problema, quindi una soluzione ideale sarebbe generica.
Grazie in anticipo per l'aiuto.
Soluzione
Va ??bene, ecco quello che ho fatto, e sembra funzionare ed essere un design ragionevole (anche se sto per essere corretto!).
In una libreria principale (ad esempio mysite.core.views.create_update), ho scritto un decoratore:
from django.contrib.contenttypes.models import ContentType
from django.views.generic import create_update
def update_object_as_child(parent_model_class):
"""
Given a base models.Model class, decorate a function to return
create_update.update_object, on the child class.
e.g.
@update_object(Animal)
def update_object(request, object_id):
pass
kwargs should have an object_id defined.
"""
def decorator(function):
def wrapper(request, **kwargs):
# may raise KeyError
id = kwargs['object_id']
parent_obj = parent_model_class.objects.get( pk=id )
# following http://www.djangosnippets.org/snippets/1031/
child_class = parent_obj.content_type.model_class()
kwargs['model'] = child_class
# rely on the generic code for testing/validation/404
return create_update.update_object(request, **kwargs)
return wrapper
return decorator
E in animals / views.py, ho:
from mysite.core.views.create_update import update_object_as_child
@update_object_as_child(Animal)
def edit_animal(request, object_id):
pass
E in animals / urls.py, ho:
urlpatterns += patterns('animals.views',
url(r'^edit/(?P<object_id>\d+)
Ora ho solo bisogno di una funzione di modifica unica per ogni classe base, che è banale da creare con un decoratore.
Spero che qualcuno lo trovi utile e sarei felice di avere un feedback.
, 'edit_animal', name="edit_animal"),
)
Ora ho solo bisogno di una funzione di modifica unica per ogni classe base, che è banale da creare con un decoratore.
Spero che qualcuno lo trovi utile e sarei felice di avere un feedback.
Altri suggerimenti
AFAICT, cani e gatti si trovano su diverse tabelle DB e forse non esiste una tabella animali. ma stai usando un pattern URL per tutti. da qualche parte devi scegliere tra ciascuna.
Userei un diverso scalpello URL per cani e gatti, entrambi chiamerei 'create_update.update_object'
; ma utilizzando un dict
diverso per ciascuno. uno con 'modello': Dog
e l'altro con 'model':Cat
o forse vuoi una singola tabella in cui ogni record può essere un gatto o un cane? non penso che tu possa usare modelli ereditati per questo.