J'ai un modèle pour les commandes dans une application webshop, avec une clé primaire auto-incrémentée et une clé étrangère à elle-même, puisque les commandes peuvent être divisées en plusieurs commandes, mais la relation à l'ordre original doit être maintenue.Django: accéder à l'instance du modèle depuis ModelAdmin?
class Order(models.Model):
ordernumber = models.AutoField(primary_key=True)
parent_order = models.ForeignKey('self', null=True, blank=True, related_name='child_orders')
# .. other fields not relevant here
J'ai enregistré une classe OrderAdmin pour le site d'administration. Pour l'affichage détaillé, j'ai inclus parent_order
dans l'attribut fieldsets
. Bien sûr, par défaut, cela liste toutes les commandes dans une boîte de sélection, mais ce n'est pas le comportement souhaité. Au lieu de cela, pour les ordres qui n'ont pas d'ordre parent (c'est-à-dire qui n'ont pas été séparés d'un autre ordre, parent_order
est NULL/Aucun), aucune commande ne doit être affichée. Pour les commandes qui ont été fractionnées, cela ne devrait afficher que l'ordre du parent unique.
Il existe une méthode ModelAdmin plutôt nouvelle, formfield_for_foreignkey
, qui semble parfaite pour cela, puisque le jeu de requête peut être filtré à l'intérieur. Imaginons que nous regardions la vue détaillée de la commande n ° 11234, qui a été séparée de la commande n ° 11208. Le code est ci-dessous
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == 'parent_order':
# kwargs["queryset"] = Order.objects.filter(child_orders__ordernumber__exact=11234)
return db_field.formfield(**kwargs)
return super(OrderAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
La ligne commentée fonctionne lorsqu'il est exécuté dans un shell Python, un retour queryset item unique contenant l'ordre # 11208 pour # 11234 et toutes les autres commandes qui peuvent avoir été séparées de celle-ci.
Bien sûr, nous ne pouvons pas coder en dur le numéro de commande ici. Nous avons besoin d'une référence au champ ordernumber
de l'instance de commande dont nous examinons la page détaillée. Comme ceci:
kwargs["queryset"] = Order.objects.filter(child_orders__ordernumber__exact=?????)
Je n'ai trouvé aucun moyen de remplacer ????? avec une référence à l'instance de commande "actuelle", et j'ai creusé assez profondément. self
à l'intérieur formfield_for_foreignkey
fait référence à l'instance ModelAdmin, et bien que cela ait un attribut model
, ce n'est pas l'instance du modèle de commande (c'est une référence ModelBase, self.model() renvoie une instance, mais son numéro de commande est None).
Une solution pourrait être de tirer le numéro de commande de request.path (/ admin/orders/order/11234 /), mais c'est vraiment moche. J'aimerais vraiment qu'il y ait un meilleur moyen.
Cela fonctionne! Merci beaucoup!Je suis complètement nouveau à toutes ces affaires ModelForm/ModelAdmin, et regardais au mauvais endroit. –
Je me rends compte que ce post est ancien, mais cela a également fonctionné comme une solution de contournement décent pour moi pour get_readonly_fields sur un InlineModelAdmin depuis le paramètre obj passé à lui est actuellement l'objet parent, pas l'objet de l'instance inline. À toutes fins utiles, cela a rendu mon objet en lecture seule en me permettant de ne retourner qu'un seul objet dans ma clé étrangère. – dgraves
Assurez-vous d'avoir appelé super .__ init__ en premier. Cela définit self.instance. – yellottyellott