Форум сайта python.su
Не в базах данных потому, что не уверен касается ли это именно баз или проектирования в общем…
С базами данных пробую первый раз.
Пытаюсь сделать программку на SQLAlchemy.
Находясь на форуме, придумал тренировочное задание - хранить список тем одной доски форума.
Читаю темы из json-файла:
data.json
[
{
"msg_count": 12, # Количество сообщений в теме.
"number": 7005, # Номер темы на форуме (предполагаю возможность неуникальности, потому не делаю первичным ключом).
"name": "Topic number one.", # Название темы.
"dates": "2011.05.05", # Дата создания (пусть пока в виде строки).
"starter": "knkd" # Топикстартер.
},
{
"msg_count": 21,
"number": 5007,
"name": "Topic number two.",
"dates": "2011.01.01 ",
"starter": "ne_knkd"
},
{
"msg_count": 212,
"number": 5700,
"name": "Topic number three.",
"dates": "2011.09.09 ",
"starter": "ne_knkd_to"
}
]
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import json
from sqlalchemy import create_engine, Table, Column, Integer, String, MetaData
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
Base = declarative_base()
class Topic(Base):
__tablename__ = 'topics'
id = Column(Integer, primary_key=True, nullable=False)
name = Column(String(128))
starter = Column(String(30))
date = Column(String(30), nullable=True)
number = Column(Integer)
msg_count = Column(Integer)
def __init__(self, data):
self.name = data["name"]
self.starter = data["starter"]
self.date = data["dates"]
self.number = data["number"]
self.msg_count = data["msg_count"]
def __repr__(self):
return "<Topic ({0}, {1}, {2})>".format(self.number,
self.msg_count, self.page_count)
def update(self, topic):
self.name = topic.name
self.starter = topic.starter
self.date = topic.date
self.number = topic.number
self.msg_count = topic.msg_count
def main():
engine = create_engine('sqlite:///./data.sqlite', echo=False)
metadata = Base.metadata
metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
data_list = json.load(open("data.json"))
for topic in data_list:
topic_object = Topic(topic)
dupl = session.query(Topic).filter_by(number=topic["number"]).first()
if dupl == None:
session.add(topic_object)
else:
dupl.update(topic_object)
session.commit()
if __name__ == '__main__':
main()
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import json
from sqlalchemy import create_engine, Table, Column, Integer, String, MetaData, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True, nullable=False)
name = Column(String(30), nullable=False, primary_key=True)
def __init__(self, user_name):
self.name = user_name
def __repr__(self, name):
return "<User {0}, {1}>".format(self.name, self.id)
class Topic(Base):
__tablename__ = 'topics'
id = Column(Integer, primary_key=True, nullable=False)
name = Column(String(128))
#starter = Column(String(30))
starter = Column(ForeignKey("users.id"))
date = Column(String(30), nullable=True)
number = Column(Integer)
msg_count = Column(Integer)
def __init__(self, data):
self.name = data["name"]
self.date = data["dates"]
self.number = data["number"]
self.msg_count = data["msg_count"]
#starter = data["starter"]
#user = session.query(User).filter_by(name=starter).first()
def __repr__(self):
return "<Topic ({0}, {1})>".format(self.number, self.starter)
def update(self, topic):
self.name = topic.name
self.starter = topic.starter
self.date = topic.date
self.number = topic.number
self.msg_count = topic.msg_count
def main():
engine = create_engine('sqlite:///data.sqlite', echo=False)
metadata = Base.metadata
metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
data_list = json.load(open("data.json"))
for topic in data_list:
topic_object = Topic(topic)
dupl = session.query(Topic).filter_by(number=topic["number"]).first()
if dupl == None:
session.add(topic_object)
else:
dupl.update(topic_object)
session.commit()
if __name__ == '__main__':
main()
Отредактировано (Июнь 15, 2011 22:58:59)
Офлайн
Получилось так.
Всё ещё не ясно - правильно ли хранить ссылку на сессию в каждом объекте?
Какие это может вызвать проблемы?
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import json
from sqlalchemy import create_engine, Table, Column, Integer, String, MetaData, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=True)
name = Column(String(30), nullable=False, autoincrement=False, unique=True)
def __init__(self, session, name):
self.session = session
self.name = name
def __repr__(self):
return "<User {0}>".format(self.name)
def add(self):
dupl = self.session.query(User).filter_by(name=self.name).first()
if dupl == None:
self.session.add(self)
class Topic(Base):
__tablename__ = 'topics'
id = Column(Integer, primary_key=True, nullable=False)
name = Column(String(128), nullable=False)
dates = Column(String(30), nullable=True)
number = Column(Integer, nullable=False)
msg_count = Column(Integer, nullable=False)
page_count = Column(Integer, nullable=False)
starter = Column(ForeignKey("users.id"), nullable=False)
def __init__(self, session, data):
self._session = session
starter = data["starter"]
user = session.query(User).filter_by(name=starter).first()
if user == None:
user = User(session, starter)
user.add()
self.name = data["name"]
self.dates = data["dates"]
self.number = data["number"]
self.msg_count = data["msg_count"]
self.page_count = data["page_count"]
self.starter = session.query(User).filter_by(name=starter).first().id #user.id
def __repr__(self):
return "<Topic ({0}, {1}, {2})>".format(self.number,
self.msg_count, self.page_count)
def update(self, topic):
self.name = topic.name
self.starter = topic.starter
self.dates = topic.dates
self.number = topic.number
self.msg_count = topic.msg_count
self.page_count = topic.page_count
def add(self):
dupl = self._session.query(Topic).filter_by(number=self.number).first()
if dupl == None:
self._session.add(self)
else:
dupl.update(self)
def main():
engine = create_engine('sqlite:///data.sqlite', echo=False)
Session = sessionmaker(bind=engine)
session = Session()
metadata = Base.metadata
metadata.create_all(engine)
data_list = json.load(open("data.json"))
for topic in data_list:
topic_object = Topic(session, topic)
topic_object.add()
session.commit()
if __name__ == '__main__':
main()
Офлайн
Нда. Получается что я делаю руками то, что должна делать алхимия.
Но как работает релатионшип я так и не понял :(
Офлайн
Все еще не понимаю ваше затруднение
Офлайн
Андрей Светлов1) Правильно ли отдавать сессию в каждый объект?
Все еще не понимаю ваше затруднение
user = session.query(User).filter_by(name=starter).first()
if user == None:
user = User(session, starter)
user.add()
...
dupl = self.session.query(User).filter_by(name=self.name).first()
if dupl == None:
self.session.add(self)
Офлайн
Вчитался внимательней. Сессию параметром конструктора давать не следует. Просто потому, что при поднятии из базы конструктор не вызывается, насколько помню.
Передавать сессию явно в метод — это нормально, если такое требуется.
Ваша же задача решается через obj = session.merge(obj)
Офлайн
Андрей СветловПонятно, спасибо.
Вчитался внимательней. Сессию параметром конструктора давать не следует. Просто потому, что при поднятии из базы конструктор не вызывается, насколько помню.
Передавать сессию явно в метод — это нормально
Андрей СветловА это не понял.
Ваша же задача решается через obj = session.merge(obj)
Офлайн
Прочитайте что в доке по этому методу пишут.
Если совсем просто — то он добавит объект в сессию.
Если при этом по primary key в базе уже есть объект — вернется поднятый из базы.
Иначе копия объекта будет зарегистрирована в сессии.
В любом случае все последующие действия нужно проводить с объектом, возвращенным из .merge
Офлайн
Андрей СветловЭто по факту всего лишь более короткий способ сделать вот так?
Если совсем просто — то он добавит объект в сессию.
Если при этом по primary key в базе уже есть объект — вернется поднятый из базы.
user = session.query(User).filter_by(name=starter).first()
if user == None:
user = User(session, starter)
user.add()
Офлайн
В примере из английской википедии:
from sqlalchemy import *
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relation, sessionmaker
Base = declarative_base()
class Movie(Base):
__tablename__ = 'movies'
id = Column(Integer, primary_key=True)
title = Column(String(255), nullable=False)
year = Column(Integer)
directed_by = Column(Integer, ForeignKey('directors.id'))
director = relation("Director", backref='movies', lazy=False)
def __init__(self, title=None, year=None):
self.title = title
self.year = year
def __repr__(self):
return "Movie(%r, %r, %r)" % (self.title, self.year, self.director)
class Director(Base):
__tablename__ = 'directors'
id = Column(Integer, primary_key=True)
name = Column(String(50), nullable=False, unique=True)
def __init__(self, name=None):
self.name = name
def __repr__(self):
return "Director(%r)" % (self.name)
engine = create_engine('sqlite:///this.sqlite')
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
m1 = Movie("Star Trek", 2009)
m1.director = Director("JJ Abrams")
d2 = Director("George Lucas")
d2.movies = [Movie("Star Wars", 1977), Movie("THX 1138", 1971)]
try:
session.add(m1)
session.add(d2)
session.commit()
except:
session.rollback()
alldata = session.query(Movie).all()
for somedata in alldata:
print somedata
Офлайн