2017-08-15 1 views
0

J'ai un peu un problème étrange que je ne suis pas en mesure d'expliquer.Django supprimant des jeux de requête avec pagination, n'attrapant pas toutes les parties de l'ensemble

J'ai un projet django avec des objets vieux et vieux. Par exemple, disons que mes objets ressemblent à ceci:

class blog_post(models.Model): 
    user_account = models.ForeignKey('accounts.Account') 
    text = models.CharField(max_length=255) 
    authors = models.ManyToManyField(author) 
    created = models.DateTimeField(blank=True, null=True) 

Ce n'est pas une copie exacte de mon modèle, mais est assez proche.

J'ai créé une commande de gestion pour construire QuerySets ordonnés de ces objets, puis supprimez avec un Paginator

Ma commande ressemble à ceci:

all_accounts = Account.objects.all() 
for act in all_accounts.iterator(): 
    stale_objects = blog_post.objects.filter(user_account=act, 
    created=django.utils.timezone.now() - datetime.timedelta(days=7)) 

    paginator = Paginator(stale_objects.order_by('id'), 100) 
    for page in range(1, paginator.num_pages + 1): 
     page_stale_objects = blog_post.objects.filter(id__in=paginator.page(page).object_list.values_list('id')) 
     page_stale_objects.delete() 

Le problème que je vais avoir est, après avoir supprimé ces objets avec ma commande, il y a encore des objets qui correspondent aux paramètres de l'ensemble de requêtes, mais qui ne sont pas supprimés. Donc, je dois exécuter la commande 3+ fois pour trouver et supprimer correctement tous les objets. J'ai d'abord pensé que ma plage de dates était juste étrangement à la limite du DateTime, donc je n'ai pas attrapé les objets fabriqués peu après 1 semaine après mon temps de commandement. Ce n'est pas le cas, j'ai supprimé le filtre created = ... du jeu de requête, et j'ai les mêmes résultats.

Pourquoi mes sous-jeux ne capturent-ils pas tous les objets la première fois que cette commande est exécutée? Il n'y a pas d'objets excessifs, au maximum ~ 30 000 lignes.

+0

Paginaator pages vos données. Je suppose que si vous supprimez 'page_stale_objects' il n'y aura qu'une seule page à supprimer (ce qui signifierait que le nombre d'objets que vous trouvez dépasse la valeur de' per_page' de paginator) –

Répondre

0

La recherche d'un jeu de requête est traduite en appels LIMIT/OFFSET consécutifs.Alors, pensez à la séquence:

  • obtenir des articles avec offset 0 et la limite de 20
  • supprimer ces articles
  • obtenir la page suivante, à savoir 20 articles de l'offset 21

Mais attendez! Une fois le premier ensemble supprimé, le QuerySet recommence à 0. Les éléments compris entre 0 et 20 sont ignorés.

La solution est, ne faites pas cela. La pagination est pour afficher des objets, ne pas les supprimer.

+0

Ah oui, c'est ce que je commençais à comprendre grâce à d'autres tests. Merci. – rob

0

Je ne comprends pas pourquoi vous utilisez le Paginator si vous voulez simplement supprimer votre jeu de requête. Corrigez-moi si je me trompe, mais semble que vous faites ce qui suit:

  • obtenir un queryset
  • sorte ce queryset par id
  • paginer
  • obtenir les objets de chaque liste
  • supprimer les

Lorsque vous pouvez simplement faire ceci:

  • obtenir un queryset
  • supprimer le queryset

Ce sera un énorme coup de pouce de la performance si vous avez beaucoup d'objets.

Alors, je vous suggère de faire ceci:

stale_objects = blog_post.objects.filter(...) 
stale_objects.delete() 

Hope it helps!

+0

Cela ne tente pas vraiment de répondre à la question de base, plus j'ai déjà montré la compréhension pour la suppression de QuerySet. Mais, pour répondre au vôtre, je le fais de cette façon pour quelques raisons, 1) il y a d'autres objets connexes qui sont mis à jour ou supprimés pendant ce processus et 2) L'utilisation d'un delete() sur un grand ensemble de requêtes prend beaucoup plus de temps. supprimer que par pagination et suppression d'un sous-ensemble à la fois. J'ai testé cela plusieurs fois et j'ai trouvé que c'était vrai pour tous mes cas. – rob