57
Databaser TDDD80 Mobila och sociala applikationer

TDDD80 databas w codeTDDD80/lectures/TDDD80_databas_w... · 2018-02-16 · Översikt TDDD80 Mobila och sociala applikationer 18-01-20 • Relationsdatabaser(tabeller) • SQL (Structured

  • Upload
    others

  • View
    3

  • Download
    0

Embed Size (px)

Citation preview

DatabaserTDDD80 Mobila och sociala applikationer

Översikt

18-01-20TDDD80 Mobila och sociala applikationer

• Relationsdatabaser (tabeller)• SQL (Structured Query Language)• Relationsmodeller– Många-till-många relationer

• Alchemy• Enhetstestning• Modulär kod – designmönstret MVC

Olika typer av databaser

18-01-21TDDD80 Mobila och sociala applikationer

• Relationsdatabaser (SQL-databaser)– Fokus på entiteter och relationer mellan dessa– Tabeller

• Unika rader• NoSQL databaser– Dokument-orienterade databaser (t.ex. MongoDB)– JSON-databaser (t.ex. Firebase)– Key-value databaser (Redis)

SQLite

18-01-20TDDD80 Mobila och sociala applikationer

• Liten SQL-databas som kan lagras på en fil– Oftast lokalt på egen dator– Används med fördel för utveckling och testing

TDDD80 Mobila och sociala applikationer

Entity-relationship diagram (ER)

18-01-21

mångaen

noll el. många

Relationsdatabaser har tabeller

18-01-21TDDD80 Mobila och sociala applikationer

ISBN titel författare ……

Nycklar

18-01-21TDDD80 Mobila och sociala applikationer

• Varje tabell har primär nyckel (ID)– Alltid unik för varje rad

• Dvs. varje relationstupel kan hittas entydigt via primär nyckeln

• Foreign key– Referens till annan tabells primär nyckel– T.ex. länka bok till bok-exemplar, till lån, etc.

Tabeller (exempel)

18-01-20TDDD80 Mobila och sociala applikationer

data saknas (motsv. ingen som har lästdetta meddelande)

Foreign key (kopplar till annan

tabell)

primär nyckel (fördenna tabell)

primär nyckel (fördenna tabell)

Schema (“tabellhuvud”)

18-01-20TDDD80 Mobila och sociala applikationer

• Mall, bestämmer vilka kolumner som ingår i tabellen– Namn– Typ av tillåtna värden

• Integer• String

– Constraints• Unik• Non-null

Data (tabellrader)

18-01-20TDDD80 Mobila och sociala applikationer

• Läggs till t.ex. när app körs• Krux– Singulära värden i tabellen, dvs. ej listor, etc.

• Ställer krav på hur data organiseras i tabeller– Relationsmodellering

RelationsmodellerER (Entity-Relationship diagrams )

18-01-21TDDD80 Mobila och sociala applikationer

many one

Modell = data + relationer mellan dessa

18-01-20TDDD80 Mobila och sociala applikationer

• One-to-one relation– Kan läggas i samma tabell– Men, kanske konceptuellt tydligare i två tabeller

• One-to-many– Två tabeller, där den ena länkar till den andra via

foreign key

One-to-many relation

18-01-20TDDD80 Mobila och sociala applikationer

Many-to-many relation

18-01-20TDDD80 Mobila och sociala applikationer

associationstabell

Associationstabell

18-01-21TDDD80 Mobila och sociala applikationer

SQLStructured Query Language

Structured Query Language (SQL)• Microsoft Access

• SELECT [Firstname], [Lastname] FROM [Employees] WHERE [Lastname] = "Davolio";

Från denna tabell Detta kriterium

Vill ha ut dessa två kolumner

18-01-20TDDD80 Mobila och sociala applikationer

Ibland måste tabeller kombineras• Ge mig alla avdelningar och dess chef, i hela företaget– Två tabeller behöver kombineras!

SELECT Employees.[Department], Managers.[Manager] FROM Employees INNER JOIN Managers WHERE Employees.[Department] = Managers.[Department];

18-01-21TDDD80 Mobila och sociala applikationer

tabell kolumn

Inner join

A INNER JOIN B behåll bara matchande rader

B 1

D 2

F 3

ABCDE

B 1D 2

18-01-20TDDD80 Mobila och sociala applikationer

Left join (outer join)

B 1

D 2

F 3

ABCDE

AB 1CD 2E

A LEFT JOIN B behåll alla rader från B

18-01-20TDDD80 Mobila och sociala applikationer

Right join (outer join)

B 1

D 2

F 3

A xB zC gD hE p

B 1 zD 2 hF 3

A RIGHT JOIN B alla rader från A

18-01-20TDDD80 Mobila och sociala applikationer

Join

18-01-20TDDD80 Mobila och sociala applikationer

• Läs mer på:– https://community.qlik.com/thread/39177

SQLAlchemy

SQLAlchemy

18-01-20TDDD80 Mobila och sociala applikationer

• Object-Relational Mapper (ORM)• Du kan definiera klasser och metoder som vanligt• SQLAlchemy översätter– Klass till tabell– Variabler till kolumner– Metoder till queries

Sätta upp en databas

18-01-20TDDD80 Mobila och sociala applikationer

from flask_sqlalchemy import SQLAlchemy

db_path = os.path.join(os.path.dirname(__file__), 'app.db')db_uri = 'sqlite:///{}'.format(db_path)app.config['SQLALCHEMY_DATABASE_URI'] = config.db_uriapp.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True

db = SQLAlchemy(app)

Flask-SQLAlchemy

18-01-20TDDD80 Mobila och sociala applikationer

• Configurerar Alchemy, ger db-objekt

Tabell:class User(db.Model):

__tablename__ = 'users'id = db.Column(db.Integer, primary_key=True)name = db.Column(db.String(5))

Exempel (Flask-SQLAlchemy)

18-01-20TDDD80 Mobila och sociala applikationer

class User(Base):__tablename__ = 'users' id = Column(Integer, Sequence('user_id_seq'), primary_key=True) name = Column(String(50)) fullname = Column(String(50)) password = Column(String(12)) def __repr__(self): return "<User(name='%s', fullname='%s',

password='%s')>" % ( self.name, self.fullname, self.password)

Flask-SQLAlchemy queries inom klassdef

18-01-20TDDD80 Mobila och sociala applikationer

class User(db.Model): #...

def follow(self, user): if not self.is_following(user):

self.followed.append(user) return self

def unfollow(self, user): if self.is_following(user):

self.followed.remove(user) return self

def is_following(self, user): return self.followed.filter(followers.c.followed_id == user.id).count() > 0

https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-viii-followers-contacts-and-friends

SQLAlchemy query (forts)

18-01-20TDDD80 Mobila och sociala applikationer

• Tillåter vanlig “python”-syntax– Dina egna data-repr i form av klasser och objekt

• T.ex. message.users.append(user) • Bakom ligger databas-tabeller och SQL-queries

Tre lager av query-syntax

18-01-20TDDD80 Mobila och sociala applikationer

• Flask-SQLAlchemy– Konfigurerar Alchemy åt oss, förenklad syntax

(query_by, etc.)• Alchemy– Kan använda Klasser och vanliga metoder istf

“lågnivå” SQL-queries• SQL– Allt översätts till SQL som loggas om man är i

debug-mode

Exempel1• db.session.query(Employees.lastname).

filter_by(lastname=‘Davalio’).all()

• Employees.query.filter(last_name=‘Davalio’).all()

• SELECT [lastname] FROM [Employees] WHERE [lastname] = "Davolio";

18-01-22TDDD80 Mobila och sociala applikationer

Exempel2

18-01-22TDDD80 Mobila och sociala applikationer

db.session.query(User).filter(User.name.like('%ed')).order_by(User.id)

SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password

FROM users WHERE users.name LIKE ? ORDER BY users.id('%ed',)

Join i Alchemy (exempel)

18-01-22TDDD80 Mobila och sociala applikationer

db.session.query(Message).join(User).filter(User.name == ‘Kalle’).all()

• Skapar en sammanslagen tmp-tabell, med kolumner frånbåda tabellerna och de rader som matchar (jfr. outerjoin)

• Se vidare: http://docs.sqlalchemy.org/en/latest/orm/query.html

Dynamic queries

18-01-22TDDD80 Mobila och sociala applikationer

• Om man anger lazy=‘dynamic’ i sin tabell-def:– Query exekveras inte utan kan byggas på– Kan lägga på ytterligare filter på en query

• Exekveras vid trigger, t.ex. ‘all()’

• Ändringar i databasen måste commit:as

Alchemy session

18-01-22TDDD80 Mobila och sociala applikationer

• Ändringar i databasen måste commit:as– Tex. skapa nytt objekt från User– db.session.add(user1)

• Session.dirty flaggar nu True– db.session.commit()

• Lägg in ändringar i databasen

Many-to-many relationer

18-01-20TDDD80 Mobila och sociala applikationer

survey_questions = db.Table('survey_questions',db.Column('survey_id', db.Integer, db.ForeignKey('surveys.id')), db.Column('question_id', db.Integer, db.ForeignKey('questions.id')))

class Survey(db.Model): __tablename__ = 'surveys' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(50), unique=True) ending = db.Column(db.DateTime)

class Question(db.Model): __tablename__ = 'questions' id = db.Column(db.Integer, primary_key=True) text = db.Column(db.Text) help = db.Column(db.Text)

Ytterligare exempel

18-01-22TDDD80 Mobila och sociala applikationer

read_by = db.Table('read_by',

db.Column('user_id', db.Integer,db.ForeignKey('users.id')),

db.Column('message_id', db.Integer, db.ForeignKey('messages.id’)))

class User(db.Message):__tablename__ = ’messages’

Exempel på vanlig tabell

18-01-20TDDD80 Mobila och sociala applikationer

class Message(db.Model):__tablename__ = 'messages'id = db.Column(db.Integer, primary_key=True)mess_id = db.Column(db.Integer, unique=True)message = db.Column(db.String(140))

users = db.relationship('User',secondary=read_by,primaryjoin=(read_by.c.message_id == id),# back_populates='messages',backref=db.backref('messages', lazy='dynamic'),lazy="dynamic")

Many-to-many relationships

18-01-20TDDD80 Mobila och sociala applikationer

• Läs vidare på:• http://www.ergo.io/blog/sqlalchemy-relationships-

from-beginner-to-advanced/

• http://docs.sqlalchemy.org/en/latest/orm/tutorial.html– Klicka på navigationsfältet:

• Building a Many to Many Relationship

Statiskt schema – dynamiska data

Statiska klasser – dynamiskt skapade objekt

18-01-20TDDD80 Mobila och sociala applikationer

• Java– Klasser statiska (finns i koden, filerna)– Objekt skapas när ett javaprogram körs igång

• Skilda världar– Kan t.ex. inte komma åt vanliga variabler förrän ett

objekt har skapats som är “värd” för variabeln• Detta eftersom olika objekt kan ha olika värden på

samma variabel– myTriangle = new Triangle().setColor(“Red”)– hisTriangle = new Triangle().setColor(“Blue”)

Modell – databas

18-01-20TDDD80 Mobila och sociala applikationer

• Modell (databas-schema) statisk– Anger vilken typ av data som ska repr

• Databas dynamisk– Innehåller data från en speciell körning– Data för företag X vs. data för företag Y– Data under utveckling och testning != data för

deployment (sjösatt system)

Kod som ska sjösättas

18-01-20TDDD80 Mobila och sociala applikationer

• All kod– Utom log-filer, etc.

• Datamodell– Ej själva databasen– Databasen skapas dynamiskt på plats (på den

server som ska hantera de riktiga kunderna)

• Databasen ska inte versionshanteras– Om man inte vill ha “hårdlödd” databas

Enhetstestning

Skickar “fejk” requests

18-01-20TDDD80 Mobila och sociala applikationer

• Sätter upp test-databas med start-data• Kör ett antal testfall• Varje testfall: sekvens av anrop som bygger upp

“scenen”• T.ex. “Steg för steg, lägg i 2 meddelanden i

databasen, med första meddelandet läst av‘Kalle’

– Slutligt anrop som utvärderas i scenen somskapades

Exempel

18-01-20TDDD80 Mobila och sociala applikationer

def test_mark_and_retrieve_message(self):payload = {'message': 'hej3'}rv = self.app.post('/messages', data=json.dumps(payload),

content_type='application/json')message_id1 = rv.dataassert rv.status_code == 200assert len(message_id1) == 8…rv = self.app.post('/messages/' + message_id1 + '/flag/' + user_name1)assert ……rv = self.app.get('/messages/unread/' + user_name2)assert b'hej3' in rv.dataassert b'hejhej3' in rv.data

Sätta upp/ta ner tmp-databas

18-01-20TDDD80 Mobila och sociala applikationer

def setUp(self):self.db_fd, app.config['DATABASE'] = tempfile.mkstemp()app.config['TESTING'] = Trueself.app = app.test_client()with app.app_context():

data.initialize_db()

def tearDown(self):os.close(self.db_fd)os.unlink(app.config['DATABASE'])

Anrop till egendatabas-

hanteringsmodul

MVC (Model-View-Controler)

MVC

Serverkod(views)

Databashanteringskod18-01-20TDDD80 Mobila och sociala applikationer

Modulär kod

18-01-20TDDD80 Mobila och sociala applikationer

• Bra om kod kan återanvändas– T.ex. db-anrop direkt från unit_test

• Bra om db och views kan bytas oberoende avvarandra, dvs. “plug-n-play”– Lägg @app.route – metoderna i server.py eller

views.py– Lägg databas-hantering i egen modul (egen mapp

eller fil)

Cirkulära referenser

18-01-22TDDD80 Mobila och sociala applikationer

• Problem att vyn är beroende av data och vice versa (för initiering av db)

• Läs mer på:– http://flask.pocoo.org/docs/0.12/patterns/packa

ges/

Modulär kodstruktur

18-01-22TDDD80 Mobila och sociala applikationer

• app.py

from lab2 import app

if __name__=='__main__':app.run(host='0.0.0.0’,

port=8080)

Modulär kodstruktur

18-01-22TDDD80 Mobila och sociala applikationer

• __init__.py

from lab2 import config

app = Flask(__name__)

app.config['DEBUG'] = config.debug_flag

app.config['SQLAL…'] = config.db_uri

import lab2.server

Modulär kodstruktur

18-01-22TDDD80 Mobila och sociala applikationer

• server.py

from lab2 import appfrom lab2 import data

data.initialize_db()

Modulär kodstruktur

18-01-22TDDD80 Mobila och sociala applikationer

• data.py

from lab2 import appdb = SQLAlchemy(app)…

www.liu.se

[email protected]