7
votes

Django post_save est-il déclenché avant / après avoir enregistré une instance à la base de données?

J'ai un site Web utilisant Django. Chaque message est un objet appelé article. Je veux récupérer le code HTML de la poteau après l'avoir sauvegardé afin que j'ai écrit le crochet post_save suivant: xxx

Il attend essentiellement 20s (ajouté en tant que test) puis essaie de récupérer le code HTML de l'article Son URL et écrit le code d'état de la demande à un fichier de débogage.

Le problème est que je reçois toujours le statut = 404 lors de la première sauvegarde, il fonctionne sur la 2e et les sauvegardes suivantes. Je pensais que la façon dont Django fonctionne serait, afin que:

  1. Enregistrer l'instance à la base de données à l'aide de sauvegarde (). À ce stade, le message obtiendrait une URL
  2. Envoyer le signal post_save

    Mais je devrais alors pouvoir récupérer le HTML dans Post_save. Suis-je compréhension post_save de manière incorrecte?

    Notes ajoutées:

    1. Mettre ce code dans Save () ne fonctionne pas. Cela ne devrait pas non plus. L'article est ajouté à la base de données à la fin de la méthode Enregistrer () et ne doit donc pas avoir d'URL tant que la sauvegarde () se termine.
    2. Ceci est sur un site de production et non sur le serveur de développement.
    3. Je veux utiliser les liens dans le HTML pour envoyer des "Pingbacks" ou réellement Webmention . Mais tous mes pingbacks sont rejetés parce que le poste n'a pas encore d'URL. Ceci est le code minimum nu qui ne fonctionne pas.

2 commentaires

Avez-vous envisagé une façon différente de le faire: au lieu de récupérer l'article à l'aide de HTTP, il suffit de rendre directement un modèle d'article à une chaîne. Voir docs.djangoproject.com/ FR / 1.6 / REF / Modèles / API / ...


Je souhaite utiliser les liens dans le HTML pour envoyer des "Pingbacks" ou réellement Webmentition . Mais tous mes pingbacks sont rejetés parce que le poste n'a pas encore d'URL. C'est le code minimum nu qui ne fonctionne pas.


4 Réponses :


0
votes

Avez-vous essayé de remplacer la méthode de sauvegarde de l'objet, appelant Super, en attente, puis essayez de récupérer le HTML? Utilisez-vous également le serveur de développement? Il peut avoir des problèmes de manipulation de la deuxième demande alors que le premier se passe toujours. Peut-être l'essayer sur un serveur approprié?


1 commentaires

Oui. Le message n'a aucune URL sauf si la sauvegarde est complètement exécutée, ce qui semble correct. Et je fais tout cela sur un serveur réel.



0
votes

J'avais le même problème causé probablement par la même question (Question posée différemment, https: //plus.google.com/u/0/1067298915868988564412/posts/aoq3x1g4mvx ). Je n'ai pas résolu de manière appropriée, mais vous pouvez essayer de jouer avec le cache de base de données ou (l'a vu dans un autre problème de base de données Django) fermer toutes les connexions et requête de base de données.


0 commentaires

0
votes

edit 2: strong>
J'ai créé un exemple simple (à l'aide de Django 1.5.5) pour tester si cela fonctionne comme prévu. Pour autant que je puisse dire, ça fait. Pre_save incendie avant une base de données commit et post_save incendie après.
Exemple détaillé:

deux exemple de modèles.
L'article est utilisé pour déclencher des signaux.
L'articleurl est utilisé pour enregistrer les réponses de l'article.get_absolute_url (). P> xxx pré>

exemple vues.py et urls.py ont été omis comme ils sont simples. Je peux les ajouter si nécessaire. P> xxx pré>

Création de signaux pré_save et post_save pour l'article: p> xxx pré>

Importation de mes signaux.py Donc, Django peut l'utiliser: p> xxx pré>

Après avoir défini ce qui précède, je suis allé de l'avant et j'ai créé un nouvel article dans Django Shell (python.exe geper.py shell). P>

>>> from article.models import *
>>> a = Article(name='abcdd')
>>> a.save()
>>> ArticleUrl.objects.all()
[<ArticleUrl: pre abcdd: 404>, <ArticleUrl: post abcdd: /article/article/8>]


4 commentaires

Je ne vois pas comment. Par exemple, le code ci-dessus fonctionne si je sauvegarde le message une seconde fois et à chaque fois. Cela ne fonctionne pas sur la toute première sauvegarde.


J'ai ajouté un exemple détaillé de pré_save et de post_save travaillant comme prévu. Pourriez-vous comparer cela à votre propre code?


Votre exemple de code fonctionne. Il semble que le poste ait une URL extrêmement récupérée par l'inverse mais n'est pas accessible par d'autres agents, par exemple le navigateur avant la fin de Post_save. J'ai testé cela en ayant juste un sommeil de 60s dans Post_save et en accédant à la poste via le navigateur et qu'il n'a pas fonctionné. Il semble que @brice ait raison, même pensé que je ne comprends pas ce qu'il a dit.


@Brice soulignait que vous pouvez frapper des problèmes de validation de la transaction SQL. Votre code fonctionne essentiellement dans 2 threads distincts. Le premier est la sauvegarde () elle-même alors que la seconde est la demande de contenu de l'URL. Il semble que Django n'engage pas les modifications (et les nouvelles données) de la première à la base de données jusqu'à ce que Save () complète complètement. Cela ne se produit qu'après post_save. Avez-vous envisagé de faire ce dont vous avez besoin d'une manière différente? Peut-être accéder au contenu via le modèle plutôt que l'URL?



4
votes

Bien que ce soit une approche complètement incorrecte (*), le problème est probablement dans les transactions de base de données. Le thread actuel enregistre l'article mais dans cette transaction non initiée, vous essayez d'obtenir ces données via un autre thread (via Web Server). Dans ce cas, ce comportement est complètement correct. Soit vous devez vous engager avant de récupérer un autre fil ou d'obtenir le code HTML d'une autre manière.

(*) doit être fait de manière asynchrone à l'arrière-plan (céleri ou autre application de file d'attente ASYNC plus léger) ou vous pouvez appeler la vue directement si vous souhaitez obtenir le code HTML (selon votre vue, vous devrez peut-être avoir à forger la demande. ; Si trop compliqué, vous pouvez créer une fonction d'assistance que Cherrypicks minimal code pour rendre le modèle). Si vous n'avez besoin que d'appeler une API de 3ème partie après avoir enregistré quelque chose, vous voulez le faire de manière asynchrone. Si vous ne le faites pas, le succès de votre code "Save ()" dépendra de la disponibilité de votre connexion ou du service tiers et vous aurez besoin de traiter les transactions sur place où vous ne pourrez pas traiter des transactions. ;)


4 commentaires

Vous semblez juste à propos de la chose des threads, bien que je ne comprenne pas du tout. Je mettais un sommeil de 60s dans le post_save et pendant qu'il était en cours d'exécution essayé d'accéder à l'article par le navigateur et donne 404.


Dans des bases de données transactionnelles, si vous faites une requête d'insertion / mise à jour, les données modifiées ne sont pas vraiment enregistrées, elles sont temporaires. C'est le même principe que si vous ouvrez un fichier TXT, vous apportez des modifications, mais vous ne enregistrez pas le fichier. Vous voyez les modifications à l'écran (fil de courant), mais lorsque quelqu'un d'autre ouvre le même fichier (un autre fil de serveur Web), il y a l'ancien contenu. Peu importe la durée de l'ouverture du fichier (votre temps de sommeil), vous devez d'abord faire Ctrl + S (commit), puis visibles pour d'autres.


Oui, cela a du sens maintenant! Merci.


C'est une bonne explication. J'avais ce problème lorsque j'utilise post_save pour transmettre des objets ID et la tâche de céleri pour récupérer le même objet