3
votes

Est-il possible de désactiver la mise en cache depuis les pages d'administration de Django?

[informations supplémentaires]

J'ai demandé un moyen de désactiver la mise en cache à l'échelle du site. C'est probablement exagéré , car tout ce dont j'ai besoin est d'un moyen de pouvoir voir la version la plus récente d'une page , lorsque la base de données ou le programme pour la générer a été modifié.

Il existe un large consensus sur le fait que modifier les paramètres à l'exécution est une très mauvaise idée .

Donc, quelques idées: effacer le cache pourrait fonctionner, tout comme envoyer un indicateur pour spécifier que je ne veux pas voir de version mise en cache, ou spécifier que les requêtes de mon adresse IP ne doivent pas être mises en cache pages .

[question d'origine]

J'ai un site Web basé sur Django à l'adresse ozake.com , et je réécris fréquemment des parties de la programmation ou change le contenu de la page.

Chaque fois que je travaille dessus, je modifie les paramètres .py pour désactiver la mise en cache afin que je puisse voir mes modifications en temps réel.

Lorsque j'ai terminé, je réactive la mise en cache.

J'utilise mise en cache basée sur les fichiers . Voici la partie pertinente de settings.py:

CACHES = {
  'default': {'BACKEND':
 #'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
  'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
  'LOCATION': '/var/www/mysite.com/cache',

Lorsque je travaille sur le site, je commente les deux dernières lignes et décommente la ligne de cache factice.

Cela signifie entrer en SSH sur le site, modifier settings.py, travailler sur le site, puis le modifier à nouveau.

Est-il possible que je puisse en faire une case à cocher quelque part dans / admin avec admin.py?


10 commentaires

Je commence à penser que je dois simplement maintenir un site séparé pour le développement.


peut-être placer un script (shell) sur la machine où votre site est déployé, sur une certaine action que le script est exécuté et modifie le fichier de paramètres?


Peut-être utiliser django-constance pour définir un indicateur booléen dynamique de l'administrateur, puis créer un backend de cache personnalisé qui se comporte comme DummyCache ou FileBasedCache en fonction de la valeur de l'indicateur?


Plan long, mais github.com/jazzband/django-configurations vous donne la possibilité d'utiliser l'environnement variables comme valeurs dans les paramètres de django. Vous pouvez éventuellement créer un bouton dans l'administrateur qui modifie la variable d'environnement et redémarre le serveur.


"Je commence à penser que je dois simplement maintenir un site séparé pour le développement." - Vous devriez vraiment, vraiment . Ou, en fait, vous devez gérer un site distinct pour la production , car votre Le site "production" est vraiment un site de développement .


Quelle est votre raison spécifique pour désactiver le cache lorsque vous êtes dans l'administrateur? Est-ce simplement pour que vous puissiez modifier certaines données et voir les modifications immédiatement? Y a-t-il des vues / objets / etc. spécifiques qui vous intéressent?


Mon propre site, Ozake.com, est hébergé avec plusieurs sites de mes clients sur un seul serveur. À l'heure actuelle, lorsque je mets à jour des pages, je ne vois pas les changements tout de suite à cause de la mise en cache. Cela rend frustrant de modifier le contenu. Je voudrais pouvoir désactiver temporairement la mise en cache pendant que je modifie des pages. Il se peut qu'une meilleure approche consisterait à signaler au système de mise en cache que la page a été modifiée. Je devrais probablement poser cela dans une question distincte.


Si vous voulez simplement invalider tout le cache à volonté, vous pouvez créer une vue triviale qui fait à partir du cache d'importation de django.core.cache; cache.clear () , et invoquez-le via l'url "cachée"


Pouvez-vous écrire cela comme réponse? Cela semble être un bon choix. Peut-être pourrais-je ajouter un argument pour appeler la vue, de sorte que ozake.com/about?cc viderait le cache.


Sûr ! Veuillez noter que j'ai déjà publié une solution à votre question initiale qui ne nécessite pas de modifier les paramètres au moment de l'exécution. Cela pourrait encore être excessif dans votre cas d'utilisation, mais pourrait être facilement étendu pour basculer entre différentes stratégies de mise en cache. Je voudrais ici votre commentaire à ce sujet, car votre question a été très inspirante, et pour moi la motivation de regarder en profondeur le framework de cache Django;)


5 Réponses :



0
votes

Utiliser un site séparé pour le développement est toujours une très bonne chose. Néanmoins, avoir la possibilité de désactiver facilement la mise en cache sur le site de production peut apporter des avantages supplémentaires:

  • pour enquêter sur les bogues subtils liés à la mise en cache
  • pour mesurer le gain de performance efficace avec des données de production réelles

Je pense que cela peut être résolu avec succès avec une petite quantité de code fournissant un backend de mise en cache personnalisé léger.

En gros:

  • Django instancie un objet de cache "par défaut" une fois au démarrage, le traitant comme un singleton et l'utilise pour toujours
  • Dans notre backend de cache personnalisé, nous conserverons une instance interne de deux objets séparés (un cache "factice" et un cache "basé sur un fichier") et n'exposerons qu'un seul d'entre eux via les méthodes d'interface requises
  • De cette façon, nous agissons en fait comme un proxy de classe pour FileBasedCache ou DummyCache
  • Nous pouvons facilement contrôler quel objet est actif avec une variable, changeant ainsi le comportement au moment de l'exécution, sans avoir besoin de redémarrer Django

Le POC suivant a été vérifié dans un petit projet de test avec des résultats positifs.

D'abord, écrivez la classe "proxy" qui se comporte comme FileBasedCache ou DummyCache:

fichier 'project / mycache.py':

pip install django-constance[database]
python manage.py migrate

et référencez-le dans les paramètres du projet comme suit:

INSTALLED_APPS = [
    ...
    'constance',
    'constance.backends.database',
]

CONSTANCE_BACKEND = 'constance.backends.database.DatabaseBackend'
CONSTANCE_CONFIG = {
    'CACHING_ENABLED': (True, 'Set to False to disable caching'),
}

Veuillez noter que les actions réelles sont déléguées à l'un des deux objets internes, en fonction de la valeur actuelle de config.CACHING_ENABLED . Aucune logique de mise en cache n'a été réimplémentée dans le modèle proxy.

Enfin, pour contrôler l'indicateur de commutation de l'administrateur (la partie facile) définissez une valeur booléenne 'CACHING_ENABLED' pour django-constance (une application populaire qui fournit une interface d'administration pour modifier les paramètres dynamiques).

Ajoutez ceci aux paramètres du projet:

CACHES = {
    'default': {
        'BACKEND': 'project.mycache.MyCache',
        'LOCATION': '/var/www/mysite.com/cache,
    }
}

puis:

from django.core.cache.backends.filebased import FileBasedCache
from django.core.cache.backends.dummy import DummyCache
from django.core.cache.backends.base import DEFAULT_TIMEOUT
from constance import config


class MyCache(DummyCache):

    def __init__(self, *args, **kwargs):
        self.dummy_cache = DummyCache(*args, **kwargs)
        self.file_cache = FileBasedCache(*args, **kwargs)

    def _active_cache(self):
        """
        Select either DummyCache or FileBasedCache based on configuration
        """
        return self.file_cache if config.CACHING_ENABLED else self.dummy_cache

    def add(self, key, value, timeout=DEFAULT_TIMEOUT, version=None):
        return self._active_cache().add(key, value, timeout, version)

    def get(self, key, default=None, version=None):
        return self._active_cache().get(key, default, version)

    def set(self, key, value, timeout=DEFAULT_TIMEOUT, version=None):
        self._active_cache().set(key, value, timeout, version)

    def touch(self, key, timeout=DEFAULT_TIMEOUT, version=None):
        return self._active_cache().touch(key, timeout, version)

    def delete(self, key, version=None):
        self._active_cache().delete(key, version)

    def has_key(self, key, version=None):
        return self._active_cache().has_key(key, version)

    def clear(self):
        self._active_cache().clear()


1 commentaires

Cela ressemble à une solution solide, mais je n'ai pas le temps ni l'expertise pour la mettre en œuvre maintenant. J'y reviendrai lorsque je serai plus avancé dans le projet global et que j'aurai besoin d'une solution plus robuste. Je suis vraiment très inexpérimenté chez Django et quiconque regarderait mon projet grincerait probablement des dents.



0
votes

Vous pouvez utiliser le module django-admin-caching . Tout d'abord, pour l'installer, tapez ceci dans votre terminal bash:

settings.INSTALLED_APPS = [
   #...
   'django_admin_caching',
   #...
]

Une fois installé, vous ajoutez ce morceau de code à votre settings.py afin qu'il soit automatique- s'enregistre:

pip install django-admin-caching

Cela devrait activer la mise en cache sur votre page d'administration django.


1 commentaires

Il semble que ce soit pour mettre en cache les pages d'administration, pas le site principal. Est-ce que je me trompe?



1
votes

Si vous voulez simplement invalider tout le cache à volonté, vous pouvez créer une vue triviale qui fait cela:

fichier views.py:

http://HOST/clear_cache


9 commentaires

Je vais modifier légèrement la solution… l'idée d'avoir une adresse non protégée qui affecte la mise en cache me fait frissonner. La technique est juste ce dont j'avais besoin. Merci beaucoup.


De rien ! En remarque: la vue est déjà protégée contre les accès non autorisés - si l'utilisateur qui émet la demande n'est pas un superutilisateur, une exception est levée et aucune mise en cache n'est affectée du tout


Je pourrais donc simplement ajouter ceci à la vue par défaut habituelle, et les super utilisateurs obtiendraient toujours la version la plus récente. Je n'ai pas besoin de l'URL. C'est drôle à quel point les choses peuvent devenir plus simples quand on a plus de connaissances.


Je comprends votre point de vue ... mais bien que cela puisse sembler pratique, vous perdez également un peu de contrôle. Tout d'abord, veuillez noter que lorsque le superutilisateur accède à la "page par défaut", tous les utilisateurs sont affectés, car le cache est invalidé à l'échelle du système. Deuxièmement, vous obtenez toujours une invalidation du cache chaque fois que vous appelez la vue par défaut (et jamais lorsque vous travaillez avec d'autres vues), même si cela n'est pas nécessaire. Cela ressemble beaucoup à un effet secondaire incontrôlé. Même si ce n'est pas un gros problème dans ce cas, ce n'est pas non plus la solution la plus sûre ...


... Je suis toujours convaincu qu'une URL spécifique pour l'invalidation du cache est plus appropriée qu'une efficace. Ouvrez un nouvel onglet dans le navigateur avec cette adresse, travaillez avec le contenu de votre site, et lorsque vous avez terminé l'édition, actualisez la "page clear_cache" ... c'est aussi simple que cela;)


Il s'avère qu'il y a un problème avec cette réponse: l'adresse elle-même est mise en cache. Si vous y revenez une seconde fois, vous verrez le message "Le cache a été effacé", mais en fait rien ne se sera produit. J'ai fini par ajouter un indicateur que je peux attribuer à des valeurs aléatoires (voir ma solution finale ci-dessous). Merci encore!


Bonne prise @AndrewSwift ... J'ai mis à jour le code en ajoutant le décorateur "never_cache" à la vue, pour demander au navigateur de ne pas mettre en cache cette page. Pourriez-vous confirmer si cela aide?


A parfaitement fonctionné. Serait-il possible d'écrire quelque chose comme "if request.user.is_superuser: @never_cache" avant (ou dans) la définition de la vue?


En principe, cela pourrait être possible en appelant sélectivement add_never_cache_headers () explicitement au lieu d'utiliser le décorateur never_cache. Cependant, ce serait délicat car vous pourriez invoquer l'URL en tant qu'utilisateur anonyme, puis l'invoquer à nouveau en tant que superutilisateur, mais à ce stade, le navigateur avait déjà reçu l'instruction de mettre la page en cache. D'un autre côté, il n'y a aucun avantage réel à mettre en cache une page aussi simple, donc dans l'ensemble, je pense que cela n'en vaut pas la peine.



1
votes

Ce que j'ai fini par faire:

from django.core.cache import cache

def PageView(request):
    ...
    if request.GET.get('clear') == 'cache':
        if request.user.is_superuser:
            title = request.GET.get('flag') + ' ' + title 
            cache.clear()
    ...
    return render(request, template, context)

Je peux maintenant accéder à https://ozake.com/en/home?clear=cache&flag=sdf

Et le cache sera effacé (si je suis connecté aux pages d'administration).

Deux remarques:

  1. Cette adresse sera mise en cache, donc il est nécessaire de changer la chaîne d'indicateur à chaque fois, pour vider le cache.

    li >
  2. L'indicateur est ajouté au titre de la page afin que vous puissiez être sûr que vous voyez la version la plus récente.


2 commentaires

Évidemment, le drapeau ajouté au titre est spécifique à mon programme CMS.


Vous pouvez aller plus loin et placer cette URL dans l'un des ModelAdmin en utilisant get_urls () et en l'enveloppant dans admin_view () pour que cette fonction n'est accessible qu'aux utilisateurs Admin connectés.