|
|
|
@ -1,6 +1,14 @@
|
|
|
|
|
from sqlalchemy.ext.declarative import declarative_base
|
|
|
|
|
from sqlalchemy import Column, ForeignKey, DateTime, BigInteger, Text, Table, ARRAY
|
|
|
|
|
from sqlalchemy.orm import relationship, backref
|
|
|
|
|
from sqlalchemy import (
|
|
|
|
|
Column,
|
|
|
|
|
Integer,
|
|
|
|
|
ForeignKey,
|
|
|
|
|
DateTime,
|
|
|
|
|
BigInteger,
|
|
|
|
|
Text,
|
|
|
|
|
Table,
|
|
|
|
|
)
|
|
|
|
|
from sqlalchemy.orm import relationship
|
|
|
|
|
from sqlalchemy.sql import expression
|
|
|
|
|
from sqlalchemy.ext.compiler import compiles
|
|
|
|
|
from sqlalchemy.types import DateTime as DateTimeType
|
|
|
|
@ -31,63 +39,174 @@ class DBMixin:
|
|
|
|
|
return d
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def ReferenceCol(tablename, nullable=False, **kw):
|
|
|
|
|
return Column(ForeignKey('{}.id'.format(tablename)), nullable=nullable, **kw)
|
|
|
|
|
# Reference Tables
|
|
|
|
|
article_author = Table(
|
|
|
|
|
'article_author', Base.metadata,
|
|
|
|
|
Column('article_id,', ForeignKey('article.id')),
|
|
|
|
|
Column('author_id,', ForeignKey('author.id'))
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
article_tag = Table(
|
|
|
|
|
'articles_tag', Base.metadata,
|
|
|
|
|
Column('article_id,', ForeignKey('article.id')),
|
|
|
|
|
Column('tag_id,', ForeignKey('tag.id'))
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
categories = Table('news_source_category', Base.metadata,
|
|
|
|
|
Column('news_source_id,', ForeignKey('news_source.id')),
|
|
|
|
|
Column('category_id,', ForeignKey('category.id'))
|
|
|
|
|
)
|
|
|
|
|
source_author = Table(
|
|
|
|
|
'sources_author', Base.metadata,
|
|
|
|
|
Column('source_id,', ForeignKey('source.id')),
|
|
|
|
|
Column('author_id,', ForeignKey('author.id'))
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
tags = Table('news_article_tag', Base.metadata,
|
|
|
|
|
Column('news_article_id', ForeignKey('news_article.id')),
|
|
|
|
|
Column('tag_id', ForeignKey('tag.id')),
|
|
|
|
|
)
|
|
|
|
|
source_category = Table(
|
|
|
|
|
'source_category', Base.metadata,
|
|
|
|
|
Column('source_id,', ForeignKey('source.id')),
|
|
|
|
|
Column('category_id,', ForeignKey('category.id'))
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Tables
|
|
|
|
|
class Tag(DBMixin, Base):
|
|
|
|
|
__tablename__ = 'tag'
|
|
|
|
|
tag_name = Column(Text, unique=True)
|
|
|
|
|
tag = Column(Text, unique=True, nullable=False)
|
|
|
|
|
articles = relationship(
|
|
|
|
|
'Article',
|
|
|
|
|
secondary=article_tag,
|
|
|
|
|
back_populates='tags',
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
|
def get_or_create(session, name):
|
|
|
|
|
try:
|
|
|
|
|
return session.query(Tag).filter_by(tag_name=name).one()
|
|
|
|
|
return session.query(Tag).filter_by(tag=name).one()
|
|
|
|
|
except NoResultFound:
|
|
|
|
|
return Tag(tag_name=name)
|
|
|
|
|
return Tag(tag=name)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Category(DBMixin, Base):
|
|
|
|
|
__tablename__ = 'category'
|
|
|
|
|
category_name = Column(Text, unique=True)
|
|
|
|
|
category = Column(Text, unique=True, nullable=False)
|
|
|
|
|
sources = relationship(
|
|
|
|
|
'Source',
|
|
|
|
|
secondary=source_category,
|
|
|
|
|
back_populates='categories',
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
|
def get_or_create(session, name):
|
|
|
|
|
try:
|
|
|
|
|
return session.query(Category).filter_by(category_name=name).one()
|
|
|
|
|
return session.query(Category).filter_by(category=name).one()
|
|
|
|
|
except NoResultFound:
|
|
|
|
|
return Category(category_name=name)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class NewsSource(DBMixin, Base):
|
|
|
|
|
__tablename__ = 'news_source'
|
|
|
|
|
url = Column(Text, unique=True)
|
|
|
|
|
source_name = Column(Text)
|
|
|
|
|
source_type = Column(Text)
|
|
|
|
|
categories = relationship('Category', secondary=categories,
|
|
|
|
|
backref=backref('news_sources', lazy='dynamic'))
|
|
|
|
|
articles = relationship('NewsArticle',
|
|
|
|
|
backref=backref('news_source'),
|
|
|
|
|
cascade="all, delete, delete-orphan")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class NewsArticle(DBMixin, Base):
|
|
|
|
|
__tablename__ = 'news_article'
|
|
|
|
|
news_source_id = ReferenceCol('news_source')
|
|
|
|
|
url = Column(Text, unique=True)
|
|
|
|
|
title = Column(Text)
|
|
|
|
|
authors = Column(ARRAY(Text))
|
|
|
|
|
return Category(category=name)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MediaProtocol(DBMixin, Base):
|
|
|
|
|
__tablename__ = 'media_protocol'
|
|
|
|
|
protocol = Column(Text, nullable=False)
|
|
|
|
|
sources = relationship('Source', back_populates='media_protocol')
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
|
def get_or_create(session, name):
|
|
|
|
|
try:
|
|
|
|
|
return session.query(MediaProtocol).filter_by(protocol=name).one()
|
|
|
|
|
except NoResultFound:
|
|
|
|
|
return MediaProtocol(protocol=name)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Source(DBMixin, Base):
|
|
|
|
|
__tablename__ = 'source'
|
|
|
|
|
url = Column(Text, unique=True, nullable=False)
|
|
|
|
|
name = Column(Text, nullable=False)
|
|
|
|
|
# One-to-Many
|
|
|
|
|
media_protocol_id = Column(Integer, ForeignKey('media_protocol.id'))
|
|
|
|
|
media_protocol = relationship('MediaProtocol', back_populates='sources')
|
|
|
|
|
# Many-to-one
|
|
|
|
|
articles = relationship('Article', back_populates='source')
|
|
|
|
|
# Many-to-Many
|
|
|
|
|
authors = relationship(
|
|
|
|
|
'Author',
|
|
|
|
|
secondary=source_author,
|
|
|
|
|
back_populates='sources',
|
|
|
|
|
)
|
|
|
|
|
categories = relationship(
|
|
|
|
|
'Category',
|
|
|
|
|
secondary=source_category,
|
|
|
|
|
back_populates='sources',
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
|
def get_or_create(session, source, url):
|
|
|
|
|
try:
|
|
|
|
|
return session.query(Source).filter_by(
|
|
|
|
|
source=source,
|
|
|
|
|
url=url
|
|
|
|
|
).one()
|
|
|
|
|
except NoResultFound:
|
|
|
|
|
return Source(source=source, url=url)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Author(DBMixin, Base):
|
|
|
|
|
__tablename__ = 'author'
|
|
|
|
|
first_name = Column(Text, nullable=False)
|
|
|
|
|
middle_name = Column(Text, nullable=True)
|
|
|
|
|
last_name = Column(Text, nullable=False)
|
|
|
|
|
# __table_args__ = (
|
|
|
|
|
# UniqueConstraint('first_name', 'last_name', name='full_name'),
|
|
|
|
|
# )
|
|
|
|
|
# Many-to-Many
|
|
|
|
|
articles = relationship(
|
|
|
|
|
'Article',
|
|
|
|
|
secondary=article_author,
|
|
|
|
|
back_populates='authors',
|
|
|
|
|
)
|
|
|
|
|
sources = relationship(
|
|
|
|
|
'Source',
|
|
|
|
|
secondary=source_author,
|
|
|
|
|
back_populates='authors',
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
|
def get_or_create(session, first_name, middle_name, last_name):
|
|
|
|
|
try:
|
|
|
|
|
return session.query(Author).filter_by(
|
|
|
|
|
first_name=first_name,
|
|
|
|
|
middle_name=middle_name,
|
|
|
|
|
last_name=middle_name,
|
|
|
|
|
).one()
|
|
|
|
|
except NoResultFound:
|
|
|
|
|
return Author(
|
|
|
|
|
first_name=first_name,
|
|
|
|
|
middle_name=middle_name,
|
|
|
|
|
last_name=last_name
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Article(DBMixin, Base):
|
|
|
|
|
__tablename__ = 'article'
|
|
|
|
|
url = Column(Text, unique=True, nullable=False)
|
|
|
|
|
title = Column(Text, nullable=False)
|
|
|
|
|
published_date = Column(DateTime)
|
|
|
|
|
news_blob = Column(Text)
|
|
|
|
|
tags = relationship('Tag', secondary=tags, backref=backref('articles', lazy='dynamic'))
|
|
|
|
|
blob = Column(Text, nullable=False)
|
|
|
|
|
# Many-to-One
|
|
|
|
|
source_id = Column(Integer, ForeignKey('source.id'))
|
|
|
|
|
source = relationship('Source', back_populates='articles')
|
|
|
|
|
# Many-to-Many
|
|
|
|
|
authors = relationship(
|
|
|
|
|
'Author',
|
|
|
|
|
secondary=article_author,
|
|
|
|
|
back_populates='articles',
|
|
|
|
|
lazy='dynamic',
|
|
|
|
|
)
|
|
|
|
|
tags = relationship(
|
|
|
|
|
'Tag',
|
|
|
|
|
secondary=article_tag,
|
|
|
|
|
back_populates='articles',
|
|
|
|
|
lazy='dynamic',
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
|
def get_or_create(session, url):
|
|
|
|
|
try:
|
|
|
|
|
return session.query(Article).filter_by(url=url).one()
|
|
|
|
|
except NoResultFound:
|
|
|
|
|
return Article(url=url)
|
|
|
|
|