web-dev-qa-db-fra.com

Requête base de données Django: Comment filtrer les objets par plage de dates?

J'ai un champ dans un modèle comme

class Sample(models.Model):
    date = fields.DateField(auto_now=False)

Maintenant, je dois filtrer les objets en fonction d'une plage de données, par exemple tous les objets dont la date est comprise entre le 1er janvier 2011 et le 31 janvier 2011?

Merci de votre aide!

181
user469652

Utilisation 

Sample.objects.filter(date__range=["2011-01-01", "2011-01-31"])

Ou si vous essayez simplement de filtrer par mois: 

Sample.objects.filter(date__year='2011', 
                      date__month='01')

Modifier

Comme Bernhard Vallant l'a dit, si vous voulez un ensemble de requêtes excluant le specified range ends, vous devriez envisager sa solution , qui utilise gt/lt (supérieur à/inférieur à).

325
crodjer

Vous pouvez utiliser Django's filter with datetime.date objects :

import datetime
samples = Sample.objects.filter(sampledate__gte=datetime.date(2011, 1, 1),
                                sampledate__lte=datetime.date(2011, 1, 31))
153
Bernhard Vallant

Lorsque vous créez des plages Django avec un filtre, assurez-vous de connaître la différence entre utiliser un objet de date et un objet de date/heure. __range inclut les dates, mais si vous utilisez un objet datetime pour la date de fin, il n'inclura pas les entrées de ce jour si l'heure n'est pas définie.

    startdate = date.today()
    enddate = startdate + timedelta(days=6)
    Sample.objects.filter(date__range=[startdate, enddate])

renvoie toutes les entrées de startdate à enddate, y compris les entrées à ces dates. Mauvais exemple car il renvoie des entrées une semaine dans le futur, mais vous obtenez la dérive.

    startdate = datetime.today()
    enddate = startdate + timedelta(days=6)
    Sample.objects.filter(date__range=[startdate, enddate])

il manquera 24 heures d’entrées selon l’heure définie pour les champs de date.

71
cademan

Vous pouvez contourner le "décalage d'impédance" provoqué par le manque de précision de la comparaison d'objet DateTimeField/date - qui peut se produire si vous utilisez range - en utilisant un datetime.timedelta pour ajouter un jour de retard date dans la gamme. Cela fonctionne comme:

start = date(2012, 12, 11)
end = date(2012, 12, 18)
new_end = end + datetime.timedelta(days=1)

ExampleModel.objects.filter(some_datetime_field__range=[start, new_end])

Comme indiqué précédemment, sans que cela ne se produise, les enregistrements sont ignorés le dernier jour.

Edité pour éviter l'utilisation de datetime.combine - semble plus logique de s'en tenir aux instances de date lors de la comparaison avec un DateTimeField, au lieu de déconner avec des objets datetime jetables (et déroutants). Voir plus d'explications dans les commentaires ci-dessous.

16
trojjer

Est simple,  

YourModel.objects.filter(YOUR_DATE_FIELD__date=timezone.now())

Travaille pour moi

5
Jonhatan Fajardo

Pour le rendre plus flexible, vous pouvez concevoir un FilterBackend comme ci-dessous:

class AnalyticsFilterBackend(generic_filters.BaseFilterBackend):
    def filter_queryset(self, request, queryset, view):
        predicate = request.query_params # or request.data for POST

        if predicate.get('from_date', None) is not None and predicate.get('to_date', None) is not None:
            queryset = queryset.filter(your_date__range=(predicate['from_date'], predicate['to_date']))

        if predicate.get('from_date', None) is not None and predicate.get('to_date', None) is None:
            queryset = queryset.filter(your_date__gte=predicate['from_date'])

        if predicate.get('to_date', None) is not None and predicate.get('from_date', None) is None:
            queryset = queryset.filter(your_date__lte=predicate['to_date'])
        return queryset
0
saran3h

Toujours d'actualité aujourd'hui ... vous pouvez aussi faire:

import dateutil
import pytz

date = dateutil.parser.parse('02/11/2019').replace(tzinfo=pytz.UTC)
0
Bhavik Shah