Warum braucht es SQLAlchemy?

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
meego
User
Beiträge: 380
Registriert: Montag 4. März 2013, 14:36

Ich habe mal etwas zusammen gecoded. Die User können sich Nachrichten schicken. Wie wäre die Beziehung hier zu definieren? Sonstige Kritik?:

Code: Alles auswählen

import os
import sys
from sqlalchemy import Column, Integer, String, ForeignKey, Boolean
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
from sqlaclhemy import create_engine

Base = declarative_base
#datenbankblaupausen
class User(Base):
	__tablename__ = 'user'
	#Columns for the table user
	id = Column(Integer, primary_key=True)
	vorname = Column(String(80), nullable=False)
	name = Column(String(80), nullable=False)
	email = Column(String(80), index=True, nullable=False)
	strasse = Column(String(80), nullable=False)
	plz = Column(String(80), nullable=False)
	ort = Column(String(80), nullable=False)
	password_hash = Column(String(500), nullable=False)
	salt = Column(String(250), nullable=False)
	id_messages = Column(Integer, ForeignKey('message.id'))

class Messages(Base):
	id = Column(Integer, primary_key=True)
	zeitstempel = Column(TIMESTAMP, nullable=False)
	gelesen = Column(Boolean, nullable=False)
	betreff = Column(String(250), nullable=False)
	text = Column(String, nullable=False)
BlackJack

@meego: Ich würde mal sagen das funktioniert so nicht. Schreib doch mal ein paar konkrete Datensätze auf ein Blatt Papier (oder in eine Textdatei) mit sagen wir mal zwei Benutzern die sich gegenseitig ein paar Nachrichten geschickt haben.
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

jeder User kann N Messages schicken und jede Message hat genau einen (1) User (=Absender) und einen (?) Empfänger. Das spiegelt dein Entwurf nicht wieder.

Gruß, noisefloor
meego
User
Beiträge: 380
Registriert: Montag 4. März 2013, 14:36

Hallo. Ist es so besser?:

Bild

Code: Alles auswählen

class User(Base):
	__tablename__ = 'user'
	#Columns for the table user
	id = Column(Integer, primary_key=True)
	vorname = Column(String(80), nullable=False)
	name = Column(String(80), nullable=False)
	email = Column(String(80), index=True, nullable=False)
	strasse = Column(String(80), nullable=False)
	plz = Column(String(80), nullable=False)
	ort = Column(String(80), nullable=False)
	password_hash = Column(String(500), nullable=False)
	salt = Column(String(250), nullable=False)
	id_messages = Column(Integer, ForeignKey('message.id'))

class Messages(Base):
	id = Column(Integer, primary_key=True)
	zeitstempel = Column(TIMESTAMP, nullable=False)
	empfaenger = Column(Integer, ForeignKey('user.id'))
	sender = Column(Integer, ForeignKey('user.id'))
	gelesen = Column(Boolean, nullable=False)
	betreff = Column(String(250), nullable=False)
	text = Column(String, nullable=False)
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@meego:
fast richtig - das `id_messages = Column(Integer, ForeignKey('message.id'))` in User macht keinen Sinn, statt dessen ist es sinnvoll, in User 2 (Rück-)Relationen anzulegen - eine für empfangene und eine für gesendete Nachrichten.
BlackJack

Und bei `Messages` fehlt der Tabellenname.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Würde vorschlagen recht früh unittests schreiben. Dann sieht man schnell ob das Modell stimmt.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
meego
User
Beiträge: 380
Registriert: Montag 4. März 2013, 14:36

jerch hat geschrieben:@meego:
fast richtig - das `id_messages = Column(Integer, ForeignKey('message.id'))` in User macht keinen Sinn, statt dessen ist es sinnvoll, in User 2 (Rück-)Relationen anzulegen - eine für empfangene und eine für gesendete Nachrichten.
Kannst du das mit der Rückrelation noch etwas ausführen? Was soll da konkret stehen?

@BlackJack: Danke.
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

EMail Addressen können 254 Zeichen lang sein. Password hash und Salt sollten zusammen in einem String sein, so verhalten sich zumindest alle Hashing Algorithmen die man nutzen kann um sicher Passwörter zu speichern.
meego
User
Beiträge: 380
Registriert: Montag 4. März 2013, 14:36

@DasIch: Merci. Aber woher soll der User (bzw. meine Application) beim einloggen den Salt nehmen, wenn er nicht in der Tabelle abgelegt ist?
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

@meego: hier mal ein typisches Passwort von django:

Code: Alles auswählen

pbkdf2_sha256$100000$uQnpRoxmZyyM$4YDFEj3nK6MTBrC/7xrrTT1YlDVoueBhd3uptLRPJNc=
Du siehst, es besteht aus mehreren Teilen: Hash-Algorithmus, Iterationen, Salt, Passwort.
Das hat den Vorteil, dass man das Verfahren austauschen kann, um es sicherer zu machen, ohne dass alle Nutzer ihre Passwörter neu eingeben müssen.
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

meego hat geschrieben:@DasIch: Merci. Aber woher soll der User (bzw. meine Application) beim einloggen den Salt nehmen, wenn er nicht in der Tabelle abgelegt ist?
Der Salt wird schon in der Tabelle abgelegt bloß nicht in einer eigenen Spalte. Davon abgesehen gibt es ja noch mehr als nur Hash und Salt, wie z.B. Kostenfaktoren. Aufgrund der großen Unterschiede zwischen existierenden Algorithmen und solchen die noch kommen werden macht es keinen Sinn auf soetwas im Datenbankschema einzugehen.
meego
User
Beiträge: 380
Registriert: Montag 4. März 2013, 14:36

Hab's hier gesehen:
Link

Also nur ein Feld, wo hinter dem Hash der Salt einfach angehängt und auch von dort ausgelesen wird?

Da stellt sich die Frage, wie die empfohlene Tabelle für Facebook-Logins: remote_source_users (user_id:integer, remote_source_id:string, remote_source:string)
mit meiner users Tabelle zu verknüpfen ist. Wenn sich einer über FB anmeldet wird in remote_source_users ein Datensatz erstellt, aber was passiert in Users? Mir ist das Prinzip nicht ganz klar.
meego
User
Beiträge: 380
Registriert: Montag 4. März 2013, 14:36

@Sirius:
Sirius3 hat geschrieben:@meego: hier mal ein typisches Passwort von django:

Code: Alles auswählen

pbkdf2_sha256$100000$uQnpRoxmZyyM$4YDFEj3nK6MTBrC/7xrrTT1YlDVoueBhd3uptLRPJNc=
Du siehst, es besteht aus mehreren Teilen: Hash-Algorithmus, Iterationen, Salt, Passwort.
Das hat den Vorteil, dass man das Verfahren austauschen kann, um es sicherer zu machen, ohne dass alle Nutzer ihre Passwörter neu eingeben müssen.
Da fehlt mir der kryptographische Kennerblick. :mrgreen:
Aber warum müssten die Benutzer bei zwei Feldern das Passwort neu eingeben?
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

@meego: Du hast in Deinem Design nicht vorgesehen, dass sich der Hash-Algorithmus ändern kann. Vielleicht gibt es andere Algorithmen, die andere Parameter brauchen. Kurz, Dein Design ist unnötig kompliziert und unflexibel.
meego
User
Beiträge: 380
Registriert: Montag 4. März 2013, 14:36

Sirius3 hat geschrieben:@meego: Du hast in Deinem Design nicht vorgesehen, dass sich der Hash-Algorithmus ändern kann. Vielleicht gibt es andere Algorithmen, die andere Parameter brauchen. Kurz, Dein Design ist unnötig kompliziert und unflexibel.
@sirius: Okay. Hier einmal ein Update:

Code: Alles auswählen

class Member(Base):
	__tablename__ = 'member'
	#Columns for the table user
	id = Column(Integer, primary_key=True)
	first_name = Column(String(80))
	last_name = Column(String(80))
	email = Column(String(255), index=True)
	street = Column(String(80))
	plz = Column(String(40))
	city = Column(String(80))
	password_salt_hash = Column(String(500))
	selfdescription = Column(String(500))
	verified = Column(Boolean)
	created = Column(TIMESTAMP)
	deleted = Column(TIMESTAMP)
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

meego hat geschrieben:...
Da fehlt mir der kryptographische Kennerblick. :mrgreen:
Aber warum müssten die Benutzer bei zwei Feldern das Passwort neu eingeben?
Wenn Du Dich damit nicht auskennst, spricht das ganz stark dafür, was Fertiges zu nehmen. Das Problem ist schon zigmal vor Dir gelöst und auf Fehler abgeklopft worden, z.B. in Django ;)

Wie man Relationen und deren Rückbindungen erstellt, findest Du in der SQLAlchemy-Dokumentation http://docs.sqlalchemy.org/en/rel_1_0/o ... ne-to-many
meego
User
Beiträge: 380
Registriert: Montag 4. März 2013, 14:36

jerch hat geschrieben:Wenn Du Dich damit nicht auskennst, spricht das ganz stark dafür, was Fertiges zu nehmen. Das Problem ist schon zigmal vor Dir gelöst und auf Fehler abgeklopft worden, z.B. in Django ;)
Was ist "was Fertiges"? Eine Bibliothek?
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,
meego hat geschrieben:Was ist "was Fertiges"? Eine Bibliothek?
Ja - bzw. ein fertiges Framework wie Django. Das hat die Benutzerverwaltung inkl. Gruppen, zugehöriger Methoden und Dekoratoren bereits an Bord. Und das ganze dann auch noch integriert mit einem ORM, Template Engine, Form Framework, URL-Routing usw usw

Gruß, noisefloor
meego
User
Beiträge: 380
Registriert: Montag 4. März 2013, 14:36

Aber ich denke, erst muss einmal das Datenbankdesign stehen.
Antworten