app.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. import os
  2. import os.path as op
  3. from flask import Flask
  4. from flask_sqlalchemy import SQLAlchemy
  5. from wtforms import validators
  6. import flask_admin as admin
  7. from flask_admin.contrib import sqla
  8. from flask_admin.contrib.sqla import filters
  9. # Create application
  10. app = Flask(__name__)
  11. # Create dummy secrey key so we can use sessions
  12. app.config['SECRET_KEY'] = '123456790'
  13. # Create in-memory database
  14. app.config['DATABASE_FILE'] = 'sample_db.sqlite'
  15. app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + app.config['DATABASE_FILE']
  16. app.config['SQLALCHEMY_ECHO'] = True
  17. db = SQLAlchemy(app)
  18. # Create models
  19. class User(db.Model):
  20. id = db.Column(db.Integer, primary_key=True)
  21. first_name = db.Column(db.String(100))
  22. last_name = db.Column(db.String(100))
  23. username = db.Column(db.String(80), unique=True)
  24. email = db.Column(db.String(120), unique=True)
  25. def __str__(self):
  26. return self.username
  27. # Create M2M table
  28. post_tags_table = db.Table('post_tags', db.Model.metadata,
  29. db.Column('post_id', db.Integer, db.ForeignKey('post.id')),
  30. db.Column('tag_id', db.Integer, db.ForeignKey('tag.id'))
  31. )
  32. class Post(db.Model):
  33. id = db.Column(db.Integer, primary_key=True)
  34. title = db.Column(db.String(120))
  35. text = db.Column(db.Text, nullable=False)
  36. date = db.Column(db.DateTime)
  37. user_id = db.Column(db.Integer(), db.ForeignKey(User.id))
  38. user = db.relationship(User, backref='posts')
  39. tags = db.relationship('Tag', secondary=post_tags_table)
  40. def __str__(self):
  41. return self.title
  42. class Tag(db.Model):
  43. id = db.Column(db.Integer, primary_key=True)
  44. name = db.Column(db.Unicode(64))
  45. def __str__(self):
  46. return self.name
  47. class UserInfo(db.Model):
  48. id = db.Column(db.Integer, primary_key=True)
  49. key = db.Column(db.String(64), nullable=False)
  50. value = db.Column(db.String(64))
  51. user_id = db.Column(db.Integer(), db.ForeignKey(User.id))
  52. user = db.relationship(User, backref='info')
  53. def __str__(self):
  54. return '%s - %s' % (self.key, self.value)
  55. class Tree(db.Model):
  56. id = db.Column(db.Integer, primary_key=True)
  57. name = db.Column(db.String(64))
  58. parent_id = db.Column(db.Integer, db.ForeignKey('tree.id'))
  59. parent = db.relationship('Tree', remote_side=[id], backref='children')
  60. def __str__(self):
  61. return self.name
  62. # Flask views
  63. @app.route('/')
  64. def index():
  65. return '<a href="/admin/">Click me to get to Admin!</a>'
  66. # Customized User model admin
  67. class UserAdmin(sqla.ModelView):
  68. inline_models = (UserInfo,)
  69. # Customized Post model admin
  70. class PostAdmin(sqla.ModelView):
  71. # Visible columns in the list view
  72. column_exclude_list = ['text']
  73. # List of columns that can be sorted. For 'user' column, use User.username as
  74. # a column.
  75. column_sortable_list = ('title', ('user', 'user.username'), 'date')
  76. # Rename 'title' columns to 'Post Title' in list view
  77. column_labels = dict(title='Post Title')
  78. column_searchable_list = ('title', User.username, 'tags.name')
  79. column_filters = ('user',
  80. 'title',
  81. 'date',
  82. 'tags',
  83. filters.FilterLike(Post.title, 'Fixed Title', options=(('test1', 'Test 1'), ('test2', 'Test 2'))))
  84. # Pass arguments to WTForms. In this case, change label for text field to
  85. # be 'Big Text' and add required() validator.
  86. form_args = dict(
  87. text=dict(label='Big Text', validators=[validators.required()])
  88. )
  89. form_ajax_refs = {
  90. 'user': {
  91. 'fields': (User.username, User.email)
  92. },
  93. 'tags': {
  94. 'fields': (Tag.name,)
  95. }
  96. }
  97. def __init__(self, session):
  98. # Just call parent class with predefined model.
  99. super(PostAdmin, self).__init__(Post, session)
  100. class TreeView(sqla.ModelView):
  101. form_excluded_columns = ['children', ]
  102. # Create admin
  103. admin = admin.Admin(app, name='Example: SQLAlchemy', template_mode='bootstrap3')
  104. # Add views
  105. admin.add_view(UserAdmin(User, db.session))
  106. admin.add_view(sqla.ModelView(Tag, db.session))
  107. admin.add_view(PostAdmin(db.session))
  108. admin.add_view(TreeView(Tree, db.session))
  109. def build_sample_db():
  110. """
  111. Populate a small db with some example entries.
  112. """
  113. import random
  114. import datetime
  115. db.drop_all()
  116. db.create_all()
  117. # Create sample Users
  118. first_names = [
  119. 'Harry', 'Amelia', 'Oliver', 'Jack', 'Isabella', 'Charlie', 'Sophie', 'Mia',
  120. 'Jacob', 'Thomas', 'Emily', 'Lily', 'Ava', 'Isla', 'Alfie', 'Olivia', 'Jessica',
  121. 'Riley', 'William', 'James', 'Geoffrey', 'Lisa', 'Benjamin', 'Stacey', 'Lucy'
  122. ]
  123. last_names = [
  124. 'Brown', 'Smith', 'Patel', 'Jones', 'Williams', 'Johnson', 'Taylor', 'Thomas',
  125. 'Roberts', 'Khan', 'Lewis', 'Jackson', 'Clarke', 'James', 'Phillips', 'Wilson',
  126. 'Ali', 'Mason', 'Mitchell', 'Rose', 'Davis', 'Davies', 'Rodriguez', 'Cox', 'Alexander'
  127. ]
  128. user_list = []
  129. for i in range(len(first_names)):
  130. user = User()
  131. user.first_name = first_names[i]
  132. user.username = first_names[i].lower()
  133. user.last_name = last_names[i]
  134. user.email = user.username + "@example.com"
  135. user_list.append(user)
  136. db.session.add(user)
  137. # Create sample Tags
  138. tag_list = []
  139. for tmp in ["YELLOW", "WHITE", "BLUE", "GREEN", "RED", "BLACK", "BROWN", "PURPLE", "ORANGE"]:
  140. tag = Tag()
  141. tag.name = tmp
  142. tag_list.append(tag)
  143. db.session.add(tag)
  144. # Create sample Posts
  145. sample_text = [
  146. {
  147. 'title': "de Finibus Bonorum et Malorum - Part I",
  148. 'content': "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor \
  149. incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud \
  150. exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure \
  151. dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. \
  152. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt \
  153. mollit anim id est laborum."
  154. },
  155. {
  156. 'title': "de Finibus Bonorum et Malorum - Part II",
  157. 'content': "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque \
  158. laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto \
  159. beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur \
  160. aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi \
  161. nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, \
  162. adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam \
  163. aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam \
  164. corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum \
  165. iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum \
  166. qui dolorem eum fugiat quo voluptas nulla pariatur?"
  167. },
  168. {
  169. 'title': "de Finibus Bonorum et Malorum - Part III",
  170. 'content': "At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium \
  171. voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati \
  172. cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id \
  173. est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam \
  174. libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod \
  175. maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. \
  176. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet \
  177. ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur \
  178. a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis \
  179. doloribus asperiores repellat."
  180. }
  181. ]
  182. for user in user_list:
  183. entry = random.choice(sample_text) # select text at random
  184. post = Post()
  185. post.user = user
  186. post.title = entry['title']
  187. post.text = entry['content']
  188. tmp = int(1000*random.random()) # random number between 0 and 1000:
  189. post.date = datetime.datetime.now() - datetime.timedelta(days=tmp)
  190. post.tags = random.sample(tag_list, 2) # select a couple of tags at random
  191. db.session.add(post)
  192. # Create a sample Tree structure
  193. trunk = Tree(name="Trunk")
  194. db.session.add(trunk)
  195. for i in range(5):
  196. branch = Tree()
  197. branch.name = "Branch " + str(i+1)
  198. branch.parent = trunk
  199. db.session.add(branch)
  200. for j in range(5):
  201. leaf = Tree()
  202. leaf.name = "Leaf " + str(j+1)
  203. leaf.parent = branch
  204. db.session.add(leaf)
  205. db.session.commit()
  206. return
  207. if __name__ == '__main__':
  208. # Build a sample db on the fly, if one does not exist yet.
  209. app_dir = op.realpath(os.path.dirname(__file__))
  210. database_path = op.join(app_dir, app.config['DATABASE_FILE'])
  211. if not os.path.exists(database_path):
  212. build_sample_db()
  213. # Start app
  214. app.run(debug=True)