zwei Datumsangaben vergleichen

Django, Flask, Bottle, WSGI, CGI…
narpfel
User
Beiträge: 658
Registriert: Freitag 20. Oktober 2017, 16:10

Der Cache ist zwar ein Speicher, aber halt nicht der Speicher. Wenn du mehrere CPU-Kerne hast, hast du auch mehrere getrennte L1- und L2-Caches, die jeweils komplett unabhängig voneinander sind. Und wenn du auf die gleichen Werte aus zwei verschiedenen Kernen zugreifst, hast du am Ende in jedem Cache eine eigene Kopie. Zusätzlich zu der Kopie im RAM.

Das Programm weiß davon aber nichts, und die CPU kümmert sich vollständig alleine darum, dass alles passt. Meistens. Und wenn die Daten gerade nicht im Cache sind, führt die CPU einfach weiter die nächsten Instruktionen aus, die nach dem Lesezugriff im Programm kommen.

Und wenn da ein bedingter Sprung vorkommt, führt die CPU einfach einen der beiden Fälle aus, bevor die Bedingung überhaupt ausgewertet ist. Bei normalen Programmen rät eine CPU heutzutage in >95% der Fälle richtig. Und wenn sie nicht richtig liegt, macht sie einfach alles wieder rückgängig und fängt von vorne an.

Muss man alles wissen, um `datetime.datetime` richtig benutzen zu können. :mrgreen:
Benutzeravatar
__blackjack__
User
Beiträge: 13572
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Wobei die >95% richtig raten bei Verzweigungsvorhersagen nicht unbedingt daran liegt, dass die CPU gut im raten wäre, sondern auch weil die Leute die Compiler schreiben, wissen wie die CPU ”rät” und nach Möglichkeit Maschinencode erzeugen der die CPU richtig ”raten” lässt.
„Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.“ — Brian W. Kernighan
Pitwheazle
User
Beiträge: 982
Registriert: Sonntag 19. September 2021, 09:40

narpfel hat geschrieben: Sonntag 17. September 2023, 18:00 Und was hat das jetzt alles mit `datetime.datetime` zu tun?
Na ganz einfach: Ich bin zu blöd für diese komplexen neuen Möglichkeiten - mit einer Kommazahl kann ich umgehen!
Jetzt hänge ich schon wieder fest:
In meinem Rechentrainer melden sich ziemlich viele Nutzer doppelt, dreifach an oder auch noch öfter. Ich habe keine Ahnung, ob ihnen ihr Anmeldename nicht gefällt oder sie nach der Anmeldung sofort wieder ihr Passwort vergessen oder sie sich nur gerne irgendwo registrieren. Diese Anmeldungen sind nicht so leicht zu finden und ich hattte jetzt die Idee, wenigsten bei den Anmeldungen im letzten Schulhalbjahr schon mal diejenigen zu löschen, die sich nur einmal angemeldet haben und auch keine Anufgaben gerechnet haben. Dazu wollte ich nur einfach überprüfen, ob der letzte Login mit dem Datum der Registriereung identisch ist. Ich habe es geschafft, zu überprüfen ob der Tag (im Monat) der selbe ist aber nicht das Datum. (Bei "meinem" Starbasic war das halt einfach der ganzahlige Anteil - das hatte ich verstanden.)
Also:

Code: Alles auswählen

def loeschen(req):
    auswahl = Profil.objects.filter(user__date_joined__lt=date(2023,8,1))
    for a in auswahl:
        if (a.user.date_joined.day ) == ((a.user.last_login.day )):
            print(a)
    return HttpResponse("fertig!")
... geht - aber halt der Tag im Monat aber "date" anstelle von "day" geht natürlich nicht.
Benutzeravatar
grubenfox
User
Beiträge: 542
Registriert: Freitag 2. Dezember 2022, 15:49

von welchem Typ sind denn `date_joined` und `last_login`,welche Attribute hat/haben der Typ/die Typen?
Benutzeravatar
__blackjack__
User
Beiträge: 13572
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Pitwheazle: Im Grunde ist da doch eigentlich nichts anders als bei StarBASIC. Wenn Du dort zwei „serial“ Zahlen hast die Tage repräsentieren kannst Du die einfach Vergleichen. Sollte einer oder beide der Werte auch Zeitanteile enthaltenm musst Du davon vorher den Tagesanteil isolieren, mit einer Funktion. Wenn Du in Python zwei `Date`-Objekte hast, kannst Du die einfach vergleichen. Sollte einer oder beide der Werte auch Zeitanteile haben, musst Du davon vorher den Tagesanteil isolieren, mit einer Methode. Grundsätzlich das gleiche vorgehen.
„Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.“ — Brian W. Kernighan
Pitwheazle
User
Beiträge: 982
Registriert: Sonntag 19. September 2021, 09:40

grubenfox hat geschrieben: Donnerstag 21. September 2023, 15:31 von welchem Typ sind denn `date_joined` und `last_login`,welche Attribute hat/haben der Typ/die Typen?
... das sind die datetime Werte aus der django.contrib.auth
__blackjack__ hat geschrieben: Donnerstag 21. September 2023, 15:44 ... Sollte einer oder beide der Werte auch Zeitanteile enthaltenm musst Du davon vorher den Tagesanteil isolieren, mit einer Funktion. Wenn Du in Python zwei `Date`-Objekte hast, kannst Du die einfach vergleichen. Sollte einer oder beide der Werte auch Zeitanteile haben, musst Du davon vorher den Tagesanteil isolieren, mit einer Methode. Grundsätzlich das gleiche vorgehen.
... das ist mir sogar (ausnahmsweise) klar - nur bei StarBasic kann ich das, bei Django nicht. Welche Methode isoliert das Datum (ohne Zeit)?
Benutzeravatar
noisefloor
User
Beiträge: 3942
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,
Welche Methode isoliert das Datum (ohne Zeit)
dateime-Objekte haben eine date() Methode. datetime und date-Objekte haben Attribute für day, month und year:

Code: Alles auswählen

>>> from datetime import datetime
>>> some_time = datetime.now()
>>> some_time.date()
datetime.date(2023, 9, 21)
>>> some_time.date().day
21
>>> some_time.date().month
9
>>> some_time.date().year
2023
>>> some_time.year
2023
>>> some_time.month
9
>>> some_time.day
21
>>>
Wenn du mal eine alternative, stark beispiellastige Doku als Alternative zur Python-Doku lesen möchtest: https://pymotw.com/3/datetime/index.htm ... e-datetime

Gruß, noisefloor
Pitwheazle
User
Beiträge: 982
Registriert: Sonntag 19. September 2021, 09:40

Danke. Ich fürchte, ich habe einfach grundsätzliche Probleme im Verständnis des objektorientierten Programmieren. Obwohl ich viele Anleitungen gelesen habe und auch weiß, das man Auto-modelle rot und blau färben kann und in Lkws umwandeln kann, es fällt es mir einfach schwer dies auf meine Probleme anzuwenden. ... und ich glaube, auch die Sprache der Django Dokumentation überfordert mich und Anleitungen wie die, von dir verlinkte, hilft mir weiter. Und auch w3shool oder delftstack haben mir eher weitergeholfen oder natürlich stackoverflow.
Benutzeravatar
noisefloor
User
Beiträge: 3942
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

die ganze Python Module of the Week Seite ist schon ziemlich gut. Weil das halt viel (bzw.fast alles) aus der Standardbibliothek erklärt wird, viel mit Beispielen. PMOTW gab's früher übrigens auch mal als Buch.

Die Django Doku ist auch schon ziemlich gut - nur geht die halt davon aus, dass man ein bisschen was kennt. Z.B. was ein datetime Objekt ist.

Gruß, noisefloor
Pitwheazle
User
Beiträge: 982
Registriert: Sonntag 19. September 2021, 09:40

noisefloor hat geschrieben: Donnerstag 21. September 2023, 17:46 Die Django Doku ist auch schon ziemlich gut - nur geht die halt davon aus, dass man ein bisschen was kennt. Z.B. was ein datetime Objekt ist.
Vielleicht erklärt das mein Problem mithilfe der Django Doku zu lernen was ein datetime Objekt ist :)
Pitwheazle
User
Beiträge: 982
Registriert: Sonntag 19. September 2021, 09:40

Bevor ich hier noch ein neues Posting aufmache, hänge ich die Frage doch hier gleich an:
Ich habe ja geschrieben, dass ich auf der Suche nach ungenutzten Accounts bin. Dabei habe ich fetsgestellt, dass es zwei Accounts gibt, die nicht mit einem Profil vernüpft sind. Die habe ich so gefunden:

Code: Alles auswählen

def fake(req):
    auswahl = User.objects.filter(date_joined__lt=date(2023,8,1))
    for a in auswahl:
        try:
            print(a.profil)
        except:
            print(" kein Profil: ", a)
    return HttpResponse("fertig!")
... das ist sicher nicht elegant. Mein "Profil" ist so verknüpft:

Code: Alles auswählen

class Profil(models.Model):
    user = models.OneToOneField(User, related_name='profil', on_delete=models.CASCADE )
... wie finde ich offiziell die Accounts, die keine Verknüfung haben?
Pitwheazle
User
Beiträge: 982
Registriert: Sonntag 19. September 2021, 09:40

Und auch hier finde ich den Fehler nicht:
Ich habe geschrieben, dass ich alle Accounts aus dem letzten Halbjahr löschen will, bei denen die Registrierung und der letzte Login am gleichen Tag erfolgte und die keine Aufgaben (im "Protokoll") gemacht haben.
Jedesmal wenn ich den Code:

Code: Alles auswählen

def loeschen(req):
    auswahl = Profil.objects.filter(user__date_joined__lt=date(2023,8,1))
    for a in auswahl:
        if (a.user.date_joined.date() ) == ((a.user.last_login.date() )):
            aufgaben = Protokoll.objects.filter(user_id = a.user.id).count() 
            if aufgaben == 0:
                print( a, ": ", aufgaben)
                account = User.objects.get(id=a.user.id)
                print(account, " gelöscht")                
                account.delete()
    return HttpResponse("fertig!")
ausführe, bekomme ich neue User gemeldet die gelöscht wurden. Was habe ich denn da wieder übersehen? Die "id"s werden doch nicht neu vergeben?
Pitwheazle
User
Beiträge: 982
Registriert: Sonntag 19. September 2021, 09:40

Ich lerne ja dank eurer unermüdlichen Hilfe immer wieder (ein Bisschen) dazu - vielleicht bekomme ich das mit dem Filter ja auch mal hin (ohne rumprobieren zu müssen).
Das funktioniert:

Code: Alles auswählen

    auswahl = User.objects.filter(date_joined__lt=date(2023,8,1))
    for a in auswahl:
        if (a.date_joined.date() ) == ((a.last_login.date() )):
aber das nicht:

Code: Alles auswählen

auswahl = User.objects.filter(date_joined__lt=date(2023,8,1), date_joined.date() = last_login.date())
Benutzeravatar
sparrow
User
Beiträge: 4370
Registriert: Freitag 17. April 2009, 10:28

Ja nee, das kann auch nicht funktionieren.
Ich hatte bereits an anderer Stetlle einmal erklärt, dass das eine Python Code ist und das andere wird vom ORM in eine SQL-Query gewandelt.
Ich hoffe, du hast die Namen vernünftig vergeben und "date_joined" ist ein date. Dann brauchst du da gar nicht wandeln. Wenn es eine DatetTimeField ist, dann ist deine Namensgebung kaputt.

Was hast du denn in der Dokumentation zu Djangos Querysets gefunden? Welche Lookups gibt es denn für Felder, die dir eventuell weiterhelfen können?
Pitwheazle
User
Beiträge: 982
Registriert: Sonntag 19. September 2021, 09:40

Das "last_login" wird genauso wie "date_joined", wie schon beschrieben, von django.contrib.auth zur Verfügung gestellt und ich dachte, das seien beides datetime Objekt und

Code: Alles auswählen

]auswahl = User.objects.filter(last_login__lt=date(2023,8,1)
funktioniert auch aber

Code: Alles auswählen

auswahl = User.objects.filter(date_joined__lt=date(2023,8,1), date_joined = last_login)
nicht. Ich bekomme die Fehlermeldung

Code: Alles auswählen

name 'last_login' is not defined
... außerdem wollte ich ja nicht die Daten von date_joined und last_login inklusive Uhrzeit vergleichen sondern nur den Tag.
Benutzeravatar
sparrow
User
Beiträge: 4370
Registriert: Freitag 17. April 2009, 10:28

Wie gesagt, die Antwort liegt immer in der Dokumentation. Schau dir mal die Field lookups an. Darauf habe ich ja in meinem letzten Post schon hingewiesen. Es ist wichtig, sich mit dem ORM und den Queries in Django zu beschäftigen.

Und um auf Felder im selben Datensatz zu verlinken benötigst du F() Expressions.
Benutzeravatar
__blackjack__
User
Beiträge: 13572
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Pitwheazle: Das die beiden folgenden Varianten…

Code: Alles auswählen

auswahl = User.objects.filter(date_joined__lt=date(2023,8,1), date_joined.date() = last_login.date())

auswahl = User.objects.filter(date_joined__lt=date(2023,8,1), date_joined = last_login)
…nicht funktionieren hat aber auch erst einmal überhaupt nichts mit Django zu tun. Das sollte also eigentlich nicht überraschen, sondern klar sein. Spätestens nach der Fehlermeldung und kurz überlegen sollte man sich darüber nicht wundern.

Django verändert nichts an der Python-Syntax, die gilt natürlich für jede Bibliothek die man verwendet. Da Python keine Referenzen als Datentyp kennt, kann man einem Rückgabewert, beziehungsweise noch allgemeiner einem Ausdruck nichts zuweisen. Auch in Django-Code geht das nicht. Bei Aufrufen mit Schlüsselwortargumenten muss vor dem ``=`` immer ein Name stehen. Daran kann Django nichts ändern.

Und was nach dem ``=`` steht muss natürlich ein Ausdruck sein, dessen Bestandteile die nicht literale sind, vorher irgendwo definiert worden sind. Wenn man `last_login` übergibt, muss Python das *vor* dem eigentlichen Aufruf durch einen konkreten Wert ersetzen können, wie bei jedem anderen Aufruf auch. Auch daran kann eine Bibliothek nichts ändern.
„Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.“ — Brian W. Kernighan
Pitwheazle
User
Beiträge: 982
Registriert: Sonntag 19. September 2021, 09:40

sparrow hat geschrieben: Sonntag 24. September 2023, 19:47 Und um auf Felder im selben Datensatz zu verlinken benötigst du F() Expressions.
Das habe ich mir angeschaut und (glaube ich) auch verstanden. Hätte das denn einen Vorteil zu meinem Code:

Code: Alles auswählen

    auswahl = User.objects.filter(date_joined__lt=date(2023,8,1))
    for a in auswahl:
        if (a.date_joined.date() ) == ((a.last_login.date() ))
... der hätte auch den Vorteil, dass ich den Tag vergleichen kann.
__blackjack__ hat geschrieben: Montag 25. September 2023, 09:10 Bei Aufrufen mit Schlüsselwortargumenten muss vor dem ``=`` immer ein Name stehen. Daran kann Django nichts ändern.
Und was nach dem ``=`` steht muss natürlich ein Ausdruck sein, dessen Bestandteile die nicht literale sind, vorher irgendwo definiert worden sind.
... und das habe ich auch verstanden. ... wenn ich jetzt auch wieder nicht genau weiß was ein "literal" ist - das ist ein Zeichen oder eine Zahl, richtig?. Auch wenn es nicht so aussieht, ich lerne doch immer wieder ein Bisschen dazu :).... ich vergesse halt immer wieder mal was.

Wenn ihr mir das erklärt verstehe ich das - mit der Dokumentation bin ich meistens überfordert.
Bei der Gelegenheit. Das mit dem einfachen und dem doppelten Unterstrich in den Filtern muss ich auch immer wieder ausprobieren. Könnt ihr das auch nochmal für einen Dummie erklären? Der doppelte Unterstich greift, soweit ich das verstanden habe, auf eine andere Tabelle zu.
Benutzeravatar
__blackjack__
User
Beiträge: 13572
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Literale sind feste Werte von einem bestimmten Typ für die es eine Notation/Syntax gibt. Also beispielsweise Zeichenketten und Zahlen. Das haben die meisten Programmiersprachen. Python bietet beispielsweise auch Syntax um beispielsweise Tupel, Listen, Wörterbücher, und Mengen direkt als Wert in den Quelltext zu schreiben. So etwas haben nicht alle Programmiersprachen.

Code: Alles auswählen

# Liste als literal:
values = [42, 23, 4711]

# Hätte man das nicht, müsste man das mit Code ausdrücken:
values = list()
values.append(42)
values.append(23)
values.append(4711)
Weiss nicht wie das bei StarBASIC ist, aber beim CBM BASIC auf meinem C64 müsste man ein Array mit Werten auch durch Code füllen, wie bei den meisten klassischen BASIC-Dialekten:

Code: Alles auswählen

10 DIM A(2):A(0)=42:A(1)=23:A(2)=4711
oder mit DATA-Zeilen und einer Schleife:

Code: Alles auswählen

10 DIM A(2):FOR I=0 TO 2:READ A(I):NEXT
20 DATA 42,23,4711
In FreeBASIC gibt's zwar keine Array-Literale aber immerhin Syntax für „initializers“, wo man beim deklarieren des Arrays die Werte angeben kann:

Code: Alles auswählen

Dim values(2) As Integer = {42, 23, 4711}
Doppelte Unterstriche bei den Filtern sind die Trennstellen zwischen Attributen und ggf. am Ende einem Operator oder eine Funktion die alle in den Namen gequetscht werden. Ist halt der Hack den man in der Python-Syntax machen kann, weil die Methode am Ende diesen Schlüssel als Zeichenkette bekommt und die auseinandernehmen und interpretieren kann wie sie will. Was das am Ende bedeutet ist ja nicht Teil der Python-Syntax, sondern was auch immer der Code der diese Argumente verarbeitet, daraus macht.
„Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.“ — Brian W. Kernighan
Benutzeravatar
sparrow
User
Beiträge: 4370
Registriert: Freitag 17. April 2009, 10:28

@Pitwheazle: Es geht schon darum den Tag zu vergleichen. Bzw explizit das Datum. Und wenn du dir die Lookups angeschaut hast, hast du __date gefunden um mit dem Datum in einem DateTimeField zu arbeiten.

Ob das einen Unterschied macht? Klar.
Stell dir vor, du hast eine Datenbank mit 1000 Datensätzen und möchtest alle löschen, die einen bestimmten Wert haben.
Was du gerade tust: Du holst dir alle Datensätze, prüfst in Programm die Bedingung und löscht dann wahrscheinlich jeden einzelnen Datensatz einzeln.

Was man eigentlich tut: Der Datenbank sagen, dass man alle Datensätze löschen möchte, die einer bestimmten Bedingung entsprechen und die Datenbank dann ihren Job machen lassen.
Antworten