import enum from flaskr import db, ma from sqlalchemy.orm import validates from schema import Schema, And, Or, Regex from .Base import BaseModel, Column user_role = db.Table( 'user_role', Column('user_id', db.String(64), db.ForeignKey('user.id')), Column('role_id', db.String(64), db.ForeignKey('role.id'))) class User(BaseModel): """ 用户模型 """ __tablename__ = "user" name = Column("name", db.String(32), nullable=False, comment="名字", validator=(Schema( And(str, lambda v: len(v) >= 3 and len(v) <= 20)), "长度必须3~20位")) nickname = Column("nickname", db.String(64), comment="昵称") gender = Column("gender", db.SmallInteger, comment="性别", validator=(Schema(lambda v: v in set([0, 1, 2])), "值须为[0, 1, 2]之一")) avatar = Column("avatar", db.String(256), comment="头像")
class User(db.Model): id = db.Column(db.Integer, primary_key=True) nickname = db.Column(db.String(64)) email = db.Column(db.String(120), index=True, unique=True) password = db.Column(db.String(20)) about_me = db.Column(db.String(140)) last_seen = db.Column(db.DateTime) items_per_page = db.Column(db.Integer, default=4) avatarPath = db.Column( db.String(140), default= '/home/weijiayun/PycharmProjects/blog/flaskr/static/useravatar/lena.png' ) posts = db.relationship('Post', backref='author', lazy='dynamic') comments = db.relationship('Comment', backref='byuser', lazy='dynamic') likes = db.relationship('Like', backref='byuser', lazy='dynamic') followed = db.relationship('User', secondary=followers, primaryjoin=(followers.c.follower_id == id), secondaryjoin=(followers.c.followed_id == id), backref=db.backref('followers', lazy='dynamic'), lazy='dynamic') rejected = db.relationship('User', secondary=rejecters, primaryjoin=(rejecters.c.rejecter_id == id), secondaryjoin=(rejecters.c.rejected_id == id), backref=db.backref('rejecters', lazy='dynamic'), lazy='dynamic') def get_items_per_page(self): return self.items_per_page def avatar(self, size): return reduce(self.id, self.avatarPath, size, size)[0] def is_authenticated(self): return True def is_active(self): return True def is_anonymous(self): return False def get_id(self): try: return unicode(self.id) #python 2 except NameError: return str(self.id) #python 3 def follow(self, user): #if user has been followed by self,return None if not self.is_following(user): self.followed.append(user) return self def unfollow(self, user): #if user is not followed by self ,return None 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 def Followeds(self): return self.followed.filter(followers.c.followed_id != self.id).all() def cntFolloweds(self): return self.followed.filter(followers.c.followed_id != self.id).count() def Followers(self): return self.followers.filter(followers.c.follower_id != self.id).all() def cntFollowers(self): return self.followers.filter( followers.c.follower_id != self.id).count() def reject(self, user): if self.is_following(user): if not self.is_rejecting(user): self.rejected.append(user) return self def unreject(self, user): if self.is_following(user): if self.is_rejecting(user): self.rejected.remove(user) return self def is_rejecting(self, user): return self.rejected.filter( rejecters.c.rejected_id == user.id).count() > 0 def get_followed_posts_count(self): form1 = db.session.query(Post).join( followers, (followers.c.followed_id == Post.user_id)).filter( followers.c.follower_id == self.id) form2 = db.session.query(Post.id).join( rejecters, (rejecters.c.rejected_id == Post.user_id)).filter( rejecters.c.rejecter_id == self.id) count = form1.filter(~Post.id.in_(form2)) \ .order_by(Post.timestamp.desc()).count() return count def get_followed_posts(self, page): form1 = db.session.query(Post).join( followers, (followers.c.followed_id == Post.user_id)).filter( followers.c.follower_id == self.id) form2 = db.session.query(Post.id).join( rejecters, (rejecters.c.rejected_id == Post.user_id)).filter( rejecters.c.rejecter_id == self.id) form3 = form1.filter(~Post.id.in_(form2)) \ .order_by(Post.timestamp.desc()) form4 = form3.offset( (page - 1) * self.items_per_page).limit(self.items_per_page).all() return form4 def __repr__(self): return '<User %r>' % (self.nickname)
class User(UserMixin, db.Model): __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(64), index=True) email = db.Column(db.String(64), unique=True, index=True) password = db.Column( db.String(128), default=generate_password_hash('snsflaskapp') ) picture_path = db.Column(db.Text) is_active = db.Column(db.Boolean, unique=False, default=False) create_at = db.Column(db.DateTime, default=datetime.now) update_at = db.Column(db.DateTime, default=datetime.now) def __init__(self, username, email): self.username = username self.email = email @classmethod def select_user_by_email(cls, email): return cls.query.filter_by(email=email).first() def validate_password(self, password): return check_password_hash(self.password, password) def create_new_user(self): db.session.add(self) @classmethod def select_user_by_id(cls, id): return cls.query.get(id) def save_new_password(self, new_password): self.password = generate_password_hash(new_password) self.is_active = True # UserConnectと紐付ける outer join @classmethod def search_by_name(cls, username, page=1): user_connect1 = aliased(UserConnect) # from_user_id: 検索相手のid、 to_user_id: ログインユーザーのidでUserConnectに紐づける user_connect2 = aliased(UserConnect) # to_user_id: 検索相手のid、 from_user_id: ログインユーザーのidでUserConnectに紐づける return cls.query.filter( cls.username.like(f'%{username}%'), cls.id != int(current_user.get_id()), cls.is_active == True ).outerjoin( user_connect1, and_( user_connect1.from_user_id == cls.id, user_connect1.to_user_id == current_user.get_id() ) ).outerjoin( user_connect2, and_( user_connect2.from_user_id == current_user.get_id(), user_connect2.to_user_id == cls.id ) ).with_entities( cls.id, cls.username, cls.picture_path, user_connect1.status.label("joined_status_to_from"), user_connect2.status.label("joined_status_from_to") ).order_by(cls.username).paginate(page, 5, False) @classmethod def select_friends(cls): return cls.query.join( UserConnect, or_( and_( UserConnect.to_user_id == cls.id, UserConnect.from_user_id == current_user.get_id(), UserConnect.status == 2 ), and_( UserConnect.from_user_id == cls.id, UserConnect.to_user_id == current_user.get_id(), UserConnect.status == 2 ) ) ).with_entities( cls.id, cls.username, cls.picture_path ).all() @classmethod def select_requested_friends(cls): return cls.query.join( UserConnect, and_( UserConnect.from_user_id == cls.id, UserConnect.to_user_id == current_user.get_id(), UserConnect.status == 1 ) ).with_entities( cls.id, cls.username, cls.picture_path ).all() @classmethod def select_requesting_friends(cls): return cls.query.join( UserConnect, and_( UserConnect.from_user_id == current_user.get_id(), UserConnect.to_user_id == cls.id, UserConnect.status == 1 ) ).with_entities( cls.id, cls.username, cls.picture_path ).all()
class Item(db.Model): id = db.Column(db.Integer, primary_key=True, autoincrement=True) type = db.Column(db.String(300)) name = db.Column(db.String(300)) quantity = db.Column(db.Integer) measurement = db.Column(db.String(300))
class Label(db.Model): __tablename__ = 'label' id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String(100)) number = db.Column(db.Integer)
class Role(db.Model): __tablename__ = 'roles' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(32), nullable=False) default = db.Column(db.Boolean, default=False, index=True) permissions = db.Column(db.Integer) users = db.relationship('User', backref='roles', lazy='dynamic') def __init__(self, **kwargs): super(Role, self).__init__(**kwargs) if self.permissions is None: self.permissions = 0 def add_permission(self, perm): if not self.has_permission(perm): self.permissions += perm def remove_permission(self, perm): if self.has_permission(perm): self.permissions -= perm def reset_permissions(self): self.permissions = 0 def has_permission(self, perm): return self.permissions & perm == perm def __repr__(self): return '<Role {}>'.format(self.name) @staticmethod def insert_roles(): roles = { 'Visitor': [ Permission.read, ], 'Graduate': [ Permission.read, Permission.make_reservations, ], 'Student': [Permission.read, Permission.make_reservations, Permission.loan], 'Teacher': [ Permission.read, Permission.make_reservations, Permission.loan, Permission.add_to_readings ], 'Volunteer': [ Permission.read, Permission.make_reservations, Permission.loan, Permission.create_objects, Permission.edit_objects ], 'Librarian': [ Permission.read, Permission.make_reservations, Permission.loan, Permission.create_objects, Permission.edit_objects, Permission.register_user, Permission.delete_user, Permission.make_loans, Permission.manage_reservations, permission.make_volunteer ], 'Admin': [ Permission.read, Permission.make_reservations, Permission.loan, Permission.create_objects, Permission.create_restricted_objects, Permission.update_restricted_objects, Permission.edit_objects, Permission.register_user, Permission.delete_user, Permission.make_loans, Permission.manage_reservations, Permission.make_volunteer, Permission.make_librarian, Permission.make_admin, Permission.add_to_readings ], } default_role = 'Visitor' for role in roles: r = Role.query.filter_by(name=role).first() if r is None: r = Role(name=role) r.reset_permissions() for perm in roles[role]: r.add_permission(perm) r.default = (r.name == default_role) db.session.add(r) db.session.commit()
class OutageSchedule(db.Model): __tablename__ = 'OUTAGE_SCHEDULE' turbine_id = db.Column(db.String()) id_seq = Sequence('OBJECT_ID_SEQUENCE') teiken_id = db.Column(db.Integer, id_seq, server_default=id_seq.next_value(), primary_key=True) description = db.Column(db.String()) outage_start = db.Column(db.Date) outage_end = db.Column(db.Date) outage_duration = db.Column(db.Integer) outage_type_t = db.Column(db.String()) outage_type_g = db.Column(db.String()) execution = db.Column(db.Integer) pr_date_m = db.Column(db.DateTime) pr_date_e = db.Column(db.DateTime) representive_id = db.Column(db.String()) representive_name = db.Column(db.String()) created_at = db.Column(db.DateTime, default=datetime.now) created_by = db.Column(db.String(), default=lambda: current_user.get_id()) created_by_name = db.Column( db.String(), default=lambda: current_user.get_user_person_name()) updated_at = db.Column(db.DateTime, default=datetime.now) updated_by = db.Column(db.String(), default=lambda: current_user.get_id()) updated_by_name = db.Column( db.String(), default=lambda: current_user.get_user_person_name()) delete_flg = db.Column(db.Integer(), default=0) deleted_at = db.Column(db.DateTime) deleted_by = db.Column(db.String) deleted_by_name = db.Column(db.String()) _outage_type_mapping = { '1': "Major", '2': "Minor", '3': "Other", '4': "N/A", } @property def description_html(self): if self.description is None: return Markup("") return Markup( str(Markup.escape(self.description)).replace("\r\n", "</br>").replace( " ", " ")) @property def outage_type_t_nm(self): return 'Turbine: ' + self._outage_type_mapping.get( self.outage_type_t, "") @property def outage_type_g_nm(self): return 'Generator: ' + self._outage_type_mapping.get( self.outage_type_g, "") @property def outage_type_nm(self): return self.outage_type_t_nm + ', ' + self.outage_type_g_nm
class BaseModel(db.Model): """ 模型的基类 """ __abstract__ = True query_class = CustomQuery id = db.Column("id", db.String(64), primary_key=True, default=lambda: str(uuid.uuid4()), comment="id") createdAt = db.Column("created_at", db.DateTime, default=datetime.datetime.utcnow, comment="创建时间") updatedAt = db.Column("update_at", db.DateTime, default=datetime.datetime.utcnow, comment="更新时间") deletedAt = db.Column("deleted_at", db.DateTime, comment="删除时间") # __mapper_args__ = { # "order_by": createdAt.desc() # } def __new__(cls, *args, **kwargs): """模型验证""" errors = [] for k, v in kwargs.items(): field = getattr(cls, k, None) if field: validator = getattr(field, "validator", None) if validator: schema, msg = validator try: # 验证格式参考 # https://github.com/keleshev/schema schema.validate(v) except Exception as e: errors.append(f'字段[{k}]:{msg or str(e)}') else: # 模型没有该属性 # 即使此处不拦截,SQLAlchemy也会抛出异常 errors.append(f'字段[{k}]:多余的') if errors: abort(500, "; ".join(errors)) return super(BaseModel, cls).__new__(cls) def __setattr__(self, name, value): """属性验证""" field = getattr(self.__class__, name, None) if field is not None: validator = getattr(field, "validator", None) if validator is not None: schema, msg = validator try: # https://github.com/keleshev/schema schema.validate(value) except Exception as e: raise Exception(f'参数[{name}]:{msg or str(e)}') super(BaseModel, self).__setattr__(name, value) def update(self, **kwds): """字典更新到模型""" # self.__dict__.update(kwds) # 软删除的数据不再更新 if self.deletedAt is None: errors = [] for (k, v) in kwds.items(): try: setattr(self, k, v) except Exception as e: errors.append(str(e)) if errors: abort(500, "; ".join(errors)) def delete(self): """软删除""" self.deletedAt = datetime.datetime.utcnow()
class Post(db.Model): __tablename__ = 'post' id = db.Column(db.Integer, primary_key=True) slug = db.Column(db.String, unique=True, nullable=False) title = db.Column(db.String, nullable=False) byline = db.Column(db.String, nullable=False) publish_date = db.Column(db.DateTime, nullable=False) # Image IDs featured_id = db.Column(db.String, nullable=False) banner_id = db.Column(db.String, nullable=False) thumbnail_id = db.Column(db.String, nullable=False) # MD5 hash of the post's Markdown hash = db.Column(db.String, nullable=False) is_featured = db.Column(db.Boolean, nullable=False) is_published = db.Column(db.Boolean, nullable=False) # Note: checking for valid hex colors is left to the application title_color = db.Column(db.String(length=7), nullable=False) # Tags (Many to Many) tags = db.relationship( 'Tag', secondary=relations.posts_to_tags, # Note: this backref allows us to call Tag.posts on a `Tag` instance backref=db.backref('posts', lazy='dynamic'), ) # Images (Many to Many) images = db.relationship( 'Image', secondary=relations.posts_to_images, # Note: this backref allows us to call Image.posts on an `Image` instance backref=db.backref('images', lazy='dynamic'), ) def __init__( self, slug: str, title: str, featured_image: 'Image', banner_image: 'Image', thumbnail_image: 'Image', byline: str = None, publish_date: dt.datetime = None, is_featured: bool = None, is_published: bool = None, title_color: str = None, tags: typing.List[Tag] = None, markdown_text: str = None, ): self.slug = slug self.title = title self.set_featured_image(featured_image) self.set_banner_image(banner_image) self.set_thumbnail_image(thumbnail_image) self.byline = byline if byline else '' self.publish_date = publish_date if publish_date else dt.datetime.now() self.is_featured = is_featured if is_featured is not None else False self.is_published = is_published if is_published is not None else False self.set_title_color(title_color if title_color else '#FFFFFF') self.tags = tags if tags else [] self.set_markdown(markdown_text if markdown_text else '') def get_directory(self) -> pathlib.Path: """Return Path object to static folder.""" return pathlib.Path(flask.current_app.static_folder) / self.slug def get_featured_image(self) -> Image: return Image.query.filter_by(id=self.featured_id).first() def get_banner_image(self) -> Image: return Image.query.filter_by(id=self.banner_id).first() def get_thumbnail_image(self) -> Image: return Image.query.filter_by(id=self.thumbnail_id).first() def get_markdown_path(self) -> pathlib.Path: return self.get_directory() / 'post.md' def set_featured_image(self, image: Image): if (image.width, image.height) != constants.FEATURED_IMG_SIZE: raise ValueError('Featured image has the wrong dimensions') if self.featured_id: curr_featured = Image.query.filter_by(id=self.featured_id).first() self.images.remove(curr_featured) self.featured_id = image.id if image not in self.images: self.images.append(image) def set_banner_image(self, image: Image): if (image.width, image.height) != constants.BANNER_SIZE: raise ValueError('Banner image has the wrong dimensions') if self.banner_id: curr_banner = Image.query.filter_by(id=self.banner_id).first() self.images.remove(curr_banner) self.banner_id = image.id if image not in self.images: self.images.append(image) def set_thumbnail_image(self, image: Image): if (image.width, image.height) != constants.THUMBNAIL_SIZE: raise ValueError('Thumbnail image has the wrong dimensions') if self.thumbnail_id: curr_thumbnail = Image.query.filter_by( id=self.thumbnail_id).first() self.images.remove(curr_thumbnail) self.thumbnail_id = image.id if image not in self.images: self.images.append(image) def set_title_color(self, color: str): if not re.compile(constants.COLOR_REGEX).match(color): raise ValueError('Improper HEX color (expects #[A-F]{6})') self.title_color = color # TODO: honestly, the image stuff needs some real testing def set_markdown(self, markdown_text: str): # Remove all images except for featured, banner, and thumbnail self.images = [ img for img in self.images if img.id == self.featured_id or img.id == self.banner_id or img.id == self.thumbnail_id ] # Look up images referenced in the Markdown and ensure they exist for image_name in md2.find_images(markdown_text): found_image = Image.query.filter_by(filename=image_name).first() if found_image: self.images.append(found_image) else: msg = f'Image file not found on server: {image_name}' raise ValueError(msg) # Render HTML to check for errors try: md2.render_string(markdown_text) except Exception as e: raise ValueError(f'Error processing Markdown: {e}') # Create directory # TODO: probably refactor this out and just have a `posts` folder self.get_directory().mkdir(exist_ok=True) with open(self.get_markdown_path(), 'w+', encoding='utf-8') as out: out.write(markdown_text) self.hash = hashlib.md5(bytes(markdown_text, encoding='utf8')).hexdigest() # Add Markdown file to the search engine index flask.current_app.search_engine.index_string(markdown_text, self.slug, allow_overwrite=True) flask.current_app.search_engine.commit() def render_html(self) -> str: """Retrieve the Markdown file containing the post's contents and render to HTML.""" with open(self.get_markdown_path(), encoding='utf-8', errors='strict') as f: markdown = f.read() # Resolve image URLs. TODO: THIS IS REALLY INEFFICIENT. COULD ALSO ITERATE OVER THE POST'S IMAGES for image_name in md2.find_images(markdown): found_image = Image.query.filter_by( filename=image_name).first() markdown = md2.replace_image(markdown, image_name, found_image.get_url()) html = md2.render_string(markdown) # Render as a template to allow expanding `url_for()` calls (for example) return flask.render_template_string(html) def get_prev(self) -> 'Post': return Post.query\ .filter(Post.publish_date < self.publish_date)\ .order_by(desc(Post.publish_date))\ .first() def get_next(self) -> 'Post': return Post.query\ .filter(Post.publish_date > self.publish_date)\ .order_by(asc(Post.publish_date))\ .first() def to_dict(self) -> dict: return { constants.KEY_SLUG: self.slug, constants.KEY_TITLE: self.title, constants.KEY_BYLINE: self.byline, constants.KEY_DATE: self.publish_date.strftime(constants.DATE_FORMAT), constants.KEY_IMAGE: self.featured_id, constants.KEY_BANNER: self.banner_id, constants.KEY_THUMBNAIL: self.thumbnail_id, constants.KEY_HASH: self.hash, constants.KEY_TAGS: [tag.slug for tag in self.tags], constants.KEY_IMAGES: {image.id: { 'hash': image.hash } for image in self.images}, constants.KEY_FEATURE: self.is_featured, constants.KEY_PUBLISH: self.is_published, } def run_delete_logic(self): """ Perform logic to delete the post. The actual database record must then be deleted via SQLAlchemy. """ shutil.rmtree(self.get_directory()) flask.current_app.search_engine.remove_document(self.slug) def __repr__(self): return 'Post(title="{}", slug="{}", date={}, tags={})'.format( self.title, self.slug, self.publish_date, self.tags, )
class Job_position(db.Model): id = db.Column(db.Integer, primary_key=True) description = db.Column(db.String(400)) deadline = db.Column(db.DATETIME) title = db.Column(db.String(32), nullable=False) contact_mail = db.Column(db.String(32)) tags = db.relationship('Tag', secondary='tag_map', backref=db.backref('job_positions', lazy='dynamic')) startup = db.Column(db.Integer, db.ForeignKey(Startup.id), nullable=False) profile_picture = db.Column(db.String(30), default="profile_man.jpg") def generate_data(): job_position1 = Job_position( description="kjip", deadline=auth.to_datetimefield("2019-03-15"), title="Vi trenger en MaskinMøkk designer", startup=1, contact_mail="kontakt_oss@melon_dusk.no") job_position1.tags.append(Tag.query.filter_by(id=1).one()) job_position1.profile_picture = "Mesla.png" taggers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] job_position2 = Job_position( description="dette er din jobb, bare føl på den", deadline=auth.to_datetimefield("1227-08-27"), title="u the person", startup=2, contact_mail="*****@*****.**") job_position2.tags = (Tag.query.filter(Tag.id.in_( taggers[0:15:2])).all()) job_position2.profile_picture = "KebabnorskBank.png" job_position3 = dummydataJobPosition("best", "spør noen andre", "mhm@krak", "2019-03-15", 3) job_position3.tags = Tag.query.filter(Tag.id.in_(taggers[1:5])).all() job_position3.profile_picture = "MoTube.png" job_position4 = dummydataJobPosition("mindre bra", "ikke vet jeg da hehe", "enseriø[email protected]", "2019-03-15", 3) job_position4.tags = Tag.query.filter(Tag.id.in_(taggers[15:-5])).all() job_position4.profile_picture = "MoTube.png" job_position5 = dummydataJobPosition("senior douche", "ikke min jobb", "*****@*****.**", "2019-03-15", 6) job_position5.tags = Tag.query.filter(Tag.id.in_( taggers[7:14:2])).all() job_position5.profile_picture = "IkkeA.png" job_position6 = dummydataJobPosition("minor bug", "4evaeva", "*****@*****.**", "2019-03-15", 5) job_position6.tags = Tag.query.filter(Tag.id.in_(taggers[::3])).all() job_position6.profile_picture = "AiDiabitus.png" job_position7 = dummydataJobPosition("juicepresser", "grind det shitten der", "*****@*****.**", "2019-03-15", 4) job_position7.tags = Tag.query.filter(Tag.id.in_(taggers[::4])).all() job_position7.profile_picture = "KanAkademi.png" job_position8 = dummydataJobPosition( "PT", "Så lenge du er ripped går det fint", "[email protected]", "2019-03-15", 3) job_position8.tags = Tag.query.filter(Tag.id.in_(taggers[::15])).all() job_position8.profile_picture = "MoTube.png" db.session.add(job_position2) db.session.add(job_position1) db.session.add(job_position3) db.session.add(job_position4) db.session.add(job_position5) db.session.add(job_position6) db.session.add(job_position7) try: db.session.commit() print("ADDED JOB_POSITIONS") except: db.session.rollback() def _repr_(self): return '<position {}>'.format(self.title) def __str__(self): return '<position {}>'.format(self.title)
class Frontpage_post(db.Model): __tablename__ = 'frontpage_post' id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(100), nullable=False, default="") body_text = db.Column(db.String(300)) author = db.Column(db.Integer, db.ForeignKey(AdminUser.id), nullable=False, default=1) made = db.Column(db.Date, default=datetime.datetime.now()) image = db.Column( db.String(100), default="https://mdbootstrap.com/img/Photos/Others/images/10.jpg") # legge til img tags = db.relationship('Tag', secondary='tag_map', backref=db.backref('Frontpage_posts', lazy='dynamic')) def generate_data(): post1 = Frontpage_post( title="Velkommen til Momentum!", body_text= "Velkommen til Momentum, den nyeste nettsiden for startup-bedrifter og andre startup-interesserte! Lag en bruker som enten startup eller jobbsøker, og kom i kontakt med potensielle arbeidsgivere eller -takere. Som investor kan man søke seg frem til bedrifter eller sektorer man ønsker å investere i.", author=1, image= "https://pilbox.themuse.com/image.jpg?url=https%3A%2F%2Fassets.themuse.com%2Fuploaded%2Fattachments%2F16096.jpg%3Fv%3De7619af4a2d0f77ea20a926ecc96ef3f15bec659f629e29195b8b1abbf5af147&bg=0fff&h=367&mode=fill&prog=1&w=750" ) post1.tags.append(Tag.query.first()) post2 = Frontpage_post( title="Trondheim blir første by med 5G", body_text= "Telenor lanserte i fjor høst Norges første 5G-pilot i Kongsberg. Siden den gang har det blitt annonsert en pilot til i Elverum og nå har selskapet bestemt hvor 5G-nettet skal skrus på først når det skal bygges ut som et ordinært mobilnett og ikke et testnett. Valget for hvor man først kan ta i bruk neste generasjons mobilnett falt på Trondheim. Fra og med i sommer begynner installasjonen av de første basestasjonene.", author=1, image= "https://www.ntnu.no/documents/1265258993/1265296258/trondheim_eriksson_1200x400.jpg/85607465-6942-441a-9db7-6ce4696cd22e?t=1446629973278" ) post2.tags.append(Tag.query.filter_by(id=2).one()) post5 = Frontpage_post( title="du er verdt det", body_text= "det er på tide å stå opp, se seg selv i speilet og si 'gjør det heller i morgen, fordi du fortjener det'", author=1, image="https://mdbootstrap.com/img/Photos/Others/images/11.jpg") post6 = Frontpage_post( title="tingen er å ha det", body_text= "mange klager på å ikke ha ting, og det er da såklart et problem som kan påvirke hverdagen fra en tid til en annen når man minst tenker på det. gjerrr det bish", image="https://mdbootstrap.com/img/Photos/Others/images/12.jpg") post3 = Frontpage_post( title="Bergens nye tech-fabrikk: Bygger startups i turbofart", body_text= "Startup-fabrikken New ble grunnlagt av flere profilerte tech-personligheter i Bergen i fjor sommer. De siste månedene har New utviklet konsepter på løpende bånd. Blant annet en brennhet transport-startup. Vi har forsøkt å fjerne alt «hazzle» med å ha bil. Vi skal tilby hele bredden av transportmidler, basert på kundenes brukermønster, forteller Hans Kristian Aas, daglig leder av Imove.", author=1, image= "https://www.travelmarket.dk/gfx/tm_2011/flight/big/21-BGO.jpg") post4 = Frontpage_post( title="Kahoot på børs før sommeren", body_text= "I torsdagens investorpresentasjon varslet edtech-startupen at de kom til å bli notert på Merkur Market i løpet av andre kvartal. Vi velger å gå på børs for å ha muligheten til å hente kapital, for å kunne finansiere den ikke-organiske veksten, som tidvis vil ha et kapitalbehov. I forbindelse med børsnoteringen har vi ikke diskutert hvorvidt vi skal hente mer kapital, sier Furuseth i en artikkel i Finansavisen.", author=1, image="https://shifter.no/wp-content/uploads/2017/11/kahoot2.jpg") db.session.add(post1) db.session.add(post2) db.session.add(post3) db.session.add(post4) db.session.add(post5) db.session.add(post6) db.session.commit() try: print("ADDED FRONTPAGE_POSTS") except: print("ERROR ADDING TAGS") db.session.rollback() def _repr_(self): return '<{}>'.format(self.title) def __str__(self): return '<{}>'.format(self.title)
class StockTransaction(db.Model): __tablename__ = "stock_transaction" id = db.Column(db.Integer, primary_key=True) """StockTransaction's id""" transaction_type = db.Column(db.Enum(StockTransactionType), nullable=False) """StockTransaction's transaction type""" stock_symbol = db.Column(db.String(16), nullable=False) """StockTransaction's stock ticker symbol""" cost_per_unit = db.Column(db.Integer, nullable=False) """StockTransaction's cost per unit of stock in cents""" quantity = db.Column(db.Integer, nullable=False) """The quantity of the stock symbol in this stock transaction""" trade_fee = db.Column(db.Integer, nullable=False) """StockTransaction's trade commission fee in cents""" trade_date = db.Column(db.DateTime, nullable=False) """The date that this stock transaction occurred""" account_id = db.Column(db.Integer, db.ForeignKey('investment_account.id')) """The investment account's id that this stock transaction belongs to""" user_id = db.Column(db.Integer, db.ForeignKey('portfolio_user.id'), nullable=False) """The id of the user that made this stock transaction""" DATA_KEYS = [ 'transaction_type', 'stock_symbol', 'cost_per_unit', 'quantity', 'trade_fee', 'trade_date' ] """The names of the data fields that need to be serialized""" def __iter__(self): yield ('id', self.id) yield ('transaction_type', self.transaction_type.name) yield ('stock_symbol', self.stock_symbol) yield ('cost_per_unit', str(Decimal(self.cost_per_unit) / 100)) yield ('quantity', self.quantity) yield ('trade_fee', str(Decimal(self.trade_fee) / 100)) yield ('trade_date', self.trade_date.strftime('%Y-%m-%d')) yield ('account_id', self.account_id) @staticmethod def serialize(data): """ Returns a dict with the fields formatted in the way the client expects them """ return dict(id=data['id'], transaction_type=data['transaction_type'].name, stock_symbol=data['stock_symbol'].upper(), cost_per_unit=str(Decimal(data['cost_per_unit']) / 100), quantity=data['quantity'], trade_fee=str(Decimal(data['trade_fee']) / 100), trade_date=data['trade_date'].strftime('%Y-%m-%d'), account_id=data['account_id']) @staticmethod def deserialize(data): """ Returns a dict with the fields formatt Keyword arguments: data -- a dict with the stock transaction fields in the client format """ transaction_key = data['transaction_type'].replace(' ', '_').lower() data['transaction_type'] = StockTransactionType[transaction_key] data['stock_symbol'] = data['stock_symbol'].upper() data['cost_per_unit'] = int(Decimal(data['cost_per_unit']) * 100) data['quantity'] = int(data['quantity']) data['trade_fee'] = int(Decimal(data['trade_fee']) * 100) data['trade_date'] = date.fromisoformat(data['trade_date']) return apply_user_id(data)
class User(UserMixin, db.Model): id = db.Column(db.Integer, primary_key=True, autoincrement=True) username = db.Column(db.String(64), unique=True, nullable=False) password = db.Column(db.String(128), nullable=False) posts = db.relationship('Post', backref='user')
class login_log(db.Model): id = db.Column(db.INTEGER, primary_key=True, autoincrement=True) user_id = db.Column(db.Integer, db.ForeignKey('user.id')) ip = db.Column(db.String(200),nullable=False) logintime = db.Column(db.DateTime,nullable=False,default=datetime.datetime.now())
class loginlog(db.Model): id = db.Column(db.INTEGER, primary_key=True, autoincrement=True) user_id = db.Column(db.INTEGER, db.ForeignKey('user.id', onupdate="SET NULL", ondelete="SET NULL"), nullable=True) userIp = db.Column(db.String(30), nullable=False) loginTime = db.Column(db.DateTime, nullable=False, default=datetime.datetime.now()) userId = db.relationship("user", back_populates='loginlogs')
class User(db.Models): id = db.Column(db.Integer, primary_key = True) username = db.Column(db.String(64), index=True, unique=True) email = db.Column(db.String(120), index=True, unique=True)
class User(UserMixin, db.Model): __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True) confirmed = db.Column(db.Boolean, default=False) email = db.Column(db.String(120), unique=True, nullable=False) hashed_password = db.Column(db.String(128)) first_name = db.Column(db.String(32), nullable=False) last_name = db.Column(db.String(32), nullable=False) role_id = db.Column(db.Integer(), db.ForeignKey('roles.id')) # phone_number # regex # division = foreign key (division -> name, school, start_year) # role = foreign key @property def password(self): raise AttributeError('Can not read password property') @password.setter def password(self, password): self.hashed_password = generate_password_hash(password) def check_password(self, password): return check_password_hash(self.hashed_password, password) def generate_confirmation_token(self, expiration=3600): s = Serializer(current_app.config['SECRET_KEY'], expiration) return s.dumps({'confirm': self.id}).decode('utf-8') def confirm(self, token): s = Serializer(current_app.config['SECRET_KEY']) try: data = s.loads(token.encode('utf-8')) except: return False if data.get('confirm') != self.id: return False self.confirmed = True db.session.add(self) return True def generate_reset_token(self, expiration=3600): s = Serializer(current_app.config['SECRET_KEY'], expiration) return s.dumps({'reset': self.id}).decode('utf-8') @staticmethod def reset_password(token, new_password): s = Serializer(current_app.config['SECRET_KEY']) try: data = s.loads(token.encode('utf-8')) except: return False user = User.query.get(data.get('reset')) if user is None: return False user.password = new_password db.session.add(user) return True def can(self, perm): return self.role is not None and self.role.has_permission(perm) def is_admin(self): return self.can(Permission.admin) def __repr__(self): return '<User {} {}>'.format(self.first_name, self.last_name)
class User(UserMixin, db.Model): id = db.Column(db.Integer, primary_key=True) email = db.Column(db.String(100), unique=True) password = db.Column(db.String(100)) name = db.Column(db.String(1000))
class Book(db.Model): __tablename__ = 'books' id = db.Column(db.Integer, primary_key=True) title = db.Column(db.Text) body = db.Column(db.String(255) )
class Demo(db.Model): __tablename__ = 'demo' id_d = db.Column(db.String(64), primary_key=True) year = db.Column(db.String(64)) company = db.Column(db.String(64)) asset = db.Column(db.String(64)) debt = db.Column(db.String(64)) current_assets = db.Column(db.String(64)) inventory = db.Column(db.String(64)) prepayment = db.Column(db.String(64)) unamortized_expenses = db.Column(db.String(64)) current_liabilitie = db.Column(db.String(64)) account_receivable = db.Column(db.String(64)) turnover_days = db.Column(db.String(64)) IDD = db.Column(db.String(64)) DPO = db.Column(db.String(64)) unit = db.Column(db.String(64)) def is_authenticated(self): return True def is_active(self): return True def is_anonymous(self): return False def get_id(self): return unicode(self.id) def __repr__(self): return 'id:%r' % (self.id)
class Recipe(db.Model): id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String(300)) listOfItems = db.Column(db.String(300)) file = db.Column(db.String(300))
class SessionInfo(db.Model): __tablename__ = 'session_info' id = db.Column(db.BigInteger, primary_key=True) session_id = db.Column(db.String(1024), unique=True, nullable=False) username = db.Column(db.String(100), unique=True, nullable=False) c_time = db.Column(db.DateTime, nullable=False)
class Book(SearchableMixin, FlagMixin, db.Model): __sayt__ = 'title' id = db.Column(db.Integer, primary_key=True) ISBN_REGEX = r'^(97(8|9))?\d{9}(\d|X)$' isbn = db.Column(db.String(13), nullable=True) title = db.Column(db.String(255), nullable=False) origin_title = db.Column(db.String(255), nullable=True) first_print = db.Column(db.Boolean(), nullable=True) origin_language = db.Column(db.String(32), nullable=True) # enum? pub_year = db.Column(db.String(32), nullable=True) # pub_place = db.Column(db.String(64)) # do osobnego modelu m2m first_edition = db.Column(db.String(64), nullable=True) literary_form = db.Column(db.Enum(FormChoices), nullable=True) genre = db.Column(db.String(64), nullable=True) # enum? #fiction = db.Column(db.Enum(FictionChoices), nullable=True) fiction = db.Column(db.Boolean(), nullable=True) # subject = db.Column(db.String(64), nullable=True) precision = db.Column(db.Text, nullable=True) nukat = db.Column(db.Text, nullable=True) publisher_id = db.Column(db.Integer, db.ForeignKey('publisher.id'), nullable=True) city_id = db.Column(db.Integer, db.ForeignKey('city.id'), nullable=True) serie_id = db.Column(db.Integer, db.ForeignKey('serie.id'), nullable=True) creator = db.relationship('Creator', backref='book', lazy='dynamic') copies = db.relationship('Copy', backref='book', lazy='dynamic') def __str__(self): return self.title def print_authors(self): authors = [c.person.name for c in self.creator if c.role._name_ == 'A'] # return authors return ", ".join(authors) def print_trans(self): trans = [c.person.name for c in self.creator if c.role._name_ == 'T'] return ", ".join(trans) def print_red(self): red = [c.person.name for c in self.creator if c.role._name_ == 'R'] return ", ".join(red) def print_intro(self): intro = [c.person.name for c in self.creator if c.role._name_ == 'I'] return ", ".join(intro) def person_authors(self): return [c.person for c in self.creator.filter_by(role='A')] def authors(self): return Creator.query.filter_by(role='A', book=self) def translators(self): return Creator.query.filter_by(role='T', book=self) def redaction(self): return Creator.query.filter_by(role='R', book=self) def introduction(self): return Creator.query.filter_by(role='I', book=self) def same_author_title(self, other): '''Returns if two book instances has the same title and the same authors''' if isinstance(other, Book): return (self.authors().all() == other.authors().all()) and (self.title == other.title) @property def is_incorrect(self): return any(c.person.incorrect for c in self.creator)\ or self.city.incorrect or \ self.publisher.incorrect or self.incorrect
class SvcdbFileWk(db.Model): __tablename__ = 'SVCDB_FILE_WK' edit_id = db.Column(db.Integer, primary_key=True) file_id = db.Column(db.Integer, primary_key=True) parent_object_id = db.Column(db.Integer, index=True) file_type_id = db.Column(db.Integer) file_name = db.Column(db.String(400)) file_size = db.Column(db.Integer) dir_name = db.Column(db.String(255)) c_file_name = db.Column(db.String(20)) c_file_size = db.Column(db.Integer) is_deleted = db.Column(db.Integer) created_at = db.Column(db.DateTime, default=datetime.utcnow) created_by = db.Column(db.String(32)) updated_at = db.Column(db.DateTime, default=datetime.utcnow) updated_by = db.Column(db.String(32)) deleted_at = db.Column(db.DateTime) deleted_by = db.Column(db.String(32)) SELECT_COLUMN_STR = ''' EDIT_ID, FILE_ID, PARENT_OBJECT_ID, FILE_TYPE_ID, FILE_NAME, CASE WHEN UPPER(SUBSTRB(FILE_NAME, -3)) = 'PDF' THEN '1' ELSE '0' END IS_PDF_FLG, CASE WHEN FILE_SIZE IS NULL THEN '' WHEN FILE_SIZE > 1024 * 1024 THEN CEIL(FILE_SIZE / (1024 * 1024)) || 'MB' ELSE CEIL(FILE_SIZE / 1024) || 'KB' END FILE_SIZE_DISP, FILE_SIZE, DIR_NAME, C_FILE_NAME, C_FILE_SIZE, IS_DELETED, TO_CHAR(UPDATED_AT, 'YYYY/MM/DD') UPDATED_AT_STR, UPDATED_BY, TO_CHAR(CREATED_AT, 'YYYY/MM/DD') CREATED_AT_STR, CREATED_BY ''' def __init__(self, parent_object_id=None): self.parent_object_id = parent_object_id self.is_deleted = 0 def __repr__(self): return '<Name %r>' % (self.file_name) def getFile(self, edit_id, file_id): return db.session.query(SvcdbFileWk).filter(SvcdbFileWk.edit_id == edit_id, SvcdbFileWk.file_id == file_id, SvcdbFileWk.is_deleted == 0).first() def getFileList(self, edit_id, parent_object_id, file_type_id=None): query = db.session.query(SvcdbFileWk).filter(SvcdbFileWk.edit_id == edit_id, SvcdbFileWk.parent_object_id == parent_object_id) if file_type_id != None and file_type_id > 0: query = query.filter(SvcdbFileWk.file_type_id == file_type_id) return query.all() def addFile(self, svcdbFile, userId): svcdbFile.is_deleted = 0 svcdbFile.created_at = datetime.now() svcdbFile.created_by = userId svcdbFile.updated_at = datetime.now() svcdbFile.updated_by = userId return db.session.add(svcdbFile) def delFile(self, edit_id, file_id, userId): del_file = db.session.query(SvcdbFileWk).filter(SvcdbFileWk.edit_id == edit_id, SvcdbFileWk.file_id == file_id).first() del_file.is_deleted = 1 del_file.deleted_at = datetime.now() del_file.deleted_by = userId def delFiles(self, parent_object_id, file_type_id=None): query = db.session.query(SvcdbFileWk).filter(SvcdbFileWk.parent_object_id == parent_object_id) if file_type_id != None and file_type_id > 0: query = query.filter(SvcdbFileWk.file_type_id == file_type_id) query.delete() def intFileDatas(self, edit_id, parent_object_id): mergeSql = ''' INSERT INTO SVCDB_FILE_WK SELECT :edit_id EDIT_ID, FILE_ID, PARENT_OBJECT_ID, FILE_TYPE_ID, FILE_NAME, FILE_SIZE, DIR_NAME, C_FILE_NAME, C_FILE_SIZE, IS_DELETED, CREATED_AT, CREATED_BY, UPDATED_AT, UPDATED_BY, DELETED_AT, DELETED_BY FROM SVCDB_FILE WHERE PARENT_OBJECT_ID = :parent_object_id AND IS_DELETED = 0 ''' t = text(mergeSql) db.session.execute(t, {"edit_id": edit_id, "parent_object_id": parent_object_id}) def get_file_list(self, edit_id, object_id, file_type_id=None): selectSql = ''' SELECT {select_columns} FROM SVCDB_FILE_WK T WHERE T.IS_DELETED = 0 AND T.EDIT_ID = :edit_id AND T.PARENT_OBJECT_ID = :object_id ''' params = {} params['edit_id'] = edit_id params['object_id'] = object_id if file_type_id != None: selectSql += ' AND T.FILE_TYPE_ID = :file_type_id' params['file_type_id'] = file_type_id selectSql += ' ORDER BY T.UPDATED_AT DESC' selectSql = selectSql.format(select_columns=SvcdbFileWk.SELECT_COLUMN_STR) t = text(selectSql) rst = db.session.execute(t, params) return rst def get_file_list_for_json(self, edit_id, object_id, file_type_id): selectSql = ''' SELECT {select_columns} FROM SVCDB_FILE_WK T WHERE T.IS_DELETED = 0 AND T.EDIT_ID = :edit_id AND T.PARENT_OBJECT_ID = :object_id ''' execParam = {'edit_id': edit_id, 'object_id': object_id} if file_type_id != None and len(file_type_id) > 0: selectSql += " AND T.FILE_TYPE_ID = :file_type_id" execParam["file_type_id"] = file_type_id selectSql += ' ORDER BY T.UPDATED_AT DESC' selectSql = selectSql.format(select_columns=SvcdbFileWk.SELECT_COLUMN_STR) t = text(selectSql) rst = db.session.execute(t, execParam) return rst def getExistsFile(self, af_obj): selectSql = ''' SELECT F.* FROM SVCDB_FILE_WK F WHERE F.EDIT_ID = :edit_id AND F.PARENT_OBJECT_ID = :parent_object_id AND F.IS_DELETED = '0' AND F.FILE_NAME = :file_name ''' execParam = {'edit_id': af_obj.edit_id, 'parent_object_id': af_obj.parent_object_id, 'file_name': af_obj.file_name} if af_obj.file_type_id != None: selectSql += " AND F.FILE_TYPE_ID = :file_type_id" execParam["file_type_id"] = af_obj.file_type_id t = text(selectSql) rst = db.session.execute(t, execParam).first() return rst def chkExistsFile(self, af_obj): svcdbFileE = SvcdbFileWk() file = svcdbFileE.getExistsFile(af_obj) if not file: return False af_obj.file_id = file.file_id return True
from flask_login import UserMixin from datetime import datetime, timedelta from uuid import uuid4 # パスワード発行の際に便利な機能 @login_manager.user_loader # ログインが必要なページの行くたびに呼び出される def load_user(user_id): return User.query.get(user_id) class User(UserMixin, db.Model): __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(64), index=True) email = db.Column(db.String(64), unique=True, index=True) # emailは必ずユニーク password = db.Column(db.String(128), default=generate_password_hash('snsflaskapp')) picture_path = db.Column(db.Text) is_active = db.Column(db.Boolean, unique=False, default=False) create_at = db.Column(db.Datetime, default=datetime.now) update_at = db.Column(db.Datetime, default=datetime.now) class PasswordResetToken(db.Model): __tablename__ = 'password_reset_token' id = db.Column(db.Integer, primary_key=True) token = db.Column(db.String(64), unique=True, index=True, default=str(uuid4)) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
class Users(db.Model): id = db.Column(db.Integer, primary_key=True, autoincrement=True) username = db.Column(db.String(80)) password = db.Column(db.String(80))
class Usuario(db.Model): __tablename__ = 'usuario' __table_args__ = {'schema': 'public'} id = db.Column('id_usuario', db.Integer, primary_key=True) nome = db.Column(db.String(100), nullable=False) email = db.Column(db.String(100), nullable=False) login = db.Column(db.String(25), nullable=False, unique=True) senha = db.Column(db.String(50), nullable=False) is_ativo = db.Column(db.Boolean, nullable=False) push_object = db.Column(db.String(9000), nullable=True) @classmethod def todos(cls): return cls.query.all() @classmethod def por_id(cls, id): return cls.query.filter(cls.id == id).first() def inserir(self): self.senha = criptografa_senha(self.senha) self.is_ativo = True if self.get_por_login(self.login) is not None: raise Exception('Login em uso: ' + self.login) db.session.add(self) def alterar(self): db.session.merge(self) @classmethod def consultar(cls, filtro): query = cls.query if filtro.nome: query = query.filter(cls.nome.ilike('%' + filtro.nome + '%')) if filtro.login: query = query.filter(cls.login.ilike('%' + filtro.login + '%')) query = query.order_by(desc(cls.id)) return ResultadoPaginado(query, filtro, UsuarioDTO.converter_lista) @classmethod def get_por_login(cls, login): return cls.query.filter(cls.login.ilike(login)).first() def is_senha_valida(self, senha_informada): # a senha que está no banco está criptografada hashed = self.senha return senha_valida(senha_informada, hashed) @staticmethod def from_json(json): usuario = Usuario() usuario.id = json.get('id') usuario.nome = json.get('nome') usuario.email = json.get('email') usuario.login = json.get('login') usuario.senha = json.get('senha') usuario.is_ativo = json.get('is_ativo') if json.get( 'is_ativo') is not None else True return usuario def __repr__(self): return '<Usuario %r>' % self.login
class Persona(UserMixin, db.Model): __tablename__ = 'persona' __table_args__ = (db.CheckConstraint( "(cf)::text ~ '^[A-Z]{6}\\d{2}[A-Z]\\d{2}[A-Z]\\d{3}[A-Z]$'::text"), ) id_persona = db.Column( db.Integer, primary_key=True, server_default=db.text("nextval('persona_id_persona_seq'::regclass)")) nome = db.Column(db.String(50), nullable=False) cognome = db.Column(db.String(50), nullable=False) username = db.Column(db.String(50), nullable=False) password = db.Column(db.String(50), nullable=False) cf = db.Column(db.String(16), nullable=False, unique=True) id_indirizzo = db.Column(db.Integer, db.ForeignKey('indirizzo.id_indirizzo'), nullable=False, unique=True) id_email = db.Column(db.Integer, db.ForeignKey('email.id_email'), nullable=False, unique=True) id_documento = db.Column(db.Integer, db.ForeignKey('documento.id_documento'), nullable=False, unique=True) id_telefono = db.Column(db.Integer, db.ForeignKey('telefono.id_telefono'), nullable=False, unique=True) luogo_nascita = db.Column(db.String(50), nullable=False) data_nascita = db.Column(db.Date, nullable=False) indirizzo = db.relationship('Indirizzo', foreign_keys=[id_indirizzo], uselist=False) email = db.relationship('Email', foreign_keys=[id_email]) documento = db.relationship('Documento', foreign_keys=[id_documento]) telefono = db.relationship('Telefono', foreign_keys=[id_telefono]) def get_id(self): return self.id_persona def set_password(self, password): self.password = generate_password_hash(password) def check_password(self, password): return check_password_hash(self.password, password) ''' @login_manager.user_loader def load_user(id_persona): return Persona.query.get(int(id_persona)) ''' @login_manager.request_loader def load_user_from_request(request): token = request.headers.get('token') if token is not "" or token is not None: s = Serializer(app.config['SECRET_KEY']) try: data = s.loads(token) except SignatureExpired: return None # valid token, but expired except BadSignature: return None # invalid token if data: user = Persona.query.get(data['id']) return user return None def generate_auth_token(self, expiration=600): s = Serializer(app.config['SECRET_KEY'], expires_in=expiration) return s.dumps({'id': self.id_persona})
class Tag(db.Model): __tablename__ = 'tags' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(32), unique=True)
class User(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(15), nullable=False) sex = db.Column(db.String(1), nullable=False) is_notice = db.Column(db.Boolean, default=False) img_url = db.Column(db.String(256), nullable=True)