class DancingClassCouple(db.Model, TrackModifications): __tablename__ = TABLE_DANCING_CLASS_COUPLE __table_args__ = ( db.UniqueConstraint("dancing_class_id", "person_id", "partner_id", name="_dancing_class_couple_uc"), ) id = db.Column(db.Integer(), primary_key=True) dancing_class_id = db.Column(db.Integer(), db.ForeignKey(f"{TABLE_DANCING_CLASS}.id", ondelete="CASCADE"), nullable=False) dancing_class = db.relationship("DancingClass", lazy=False) person_id = db.Column(db.Integer(), db.ForeignKey(f"{TABLE_DANCING_CLASS_PERSON}.id", ondelete="CASCADE"), nullable=False) person = db.relationship("DancingClassPerson", foreign_keys=person_id, lazy=False) partner_id = db.Column(db.Integer(), db.ForeignKey(f"{TABLE_DANCING_CLASS_PERSON}.id", ondelete="CASCADE"), nullable=False) partner = db.relationship("DancingClassPerson", foreign_keys=partner_id, lazy=False) def __repr__(self): return f"{self.person} - {self.partner}" def json(self): data = { "id": self.id, "lead": self.person.json(), "follow": self.partner.json(), } return data
class Couple(db.Model, TrackModifications): __tablename__ = TABLE_COUPLE __table_args__ = (db.UniqueConstraint("lead_id", "follow_id", name="_lead_follow_uc"), ) id = db.Column(db.Integer(), primary_key=True) lead_id = db.Column( db.Integer(), db.ForeignKey(f"{TABLE_PERSON}.id", ondelete="CASCADE")) lead = db.relationship("Person", foreign_keys=lead_id) follow_id = db.Column( db.Integer(), db.ForeignKey(f"{TABLE_PERSON}.id", ondelete="CASCADE")) follow = db.relationship("Person", foreign_keys=follow_id) def __repr__(self): return f"{self.lead}-{self.follow}" def json(self): data = { "id": self.id, "lead": { "id": self.lead.id, "full_name": self.lead.full_name, }, "follow": { "id": self.follow.id, "full_name": self.follow.full_name, }, "couple": f"{self.lead.full_name} & {self.follow.full_name}" } return data
class Contact(BaseMixin, db.Model): """关注和被关注""" __tablename__ = 'contacts' to_id = db.Column(db.Integer) from_id = db.Column(db.Integer) __table_args__ = ( db.UniqueConstraint('from_id', 'to_id', name='uk_from_to'), db.Index('idx_to_time_from', to_id, 'created_at', from_id), db.Index('idx_time_to_from', 'created_at', to_id, from_id), ) @classmethod def __flush_event__(cls, target): rdb.delete(MC_KEY_CONTACT_N % (target.target_id, target.target_kind)) @classmethod @cache(MC_KEY_CONTACT_N % ('{target_id}', '{target_kind}')) def get_count_by_target(cls, target_id, target_kind): return cls.query.filter_by(target_id=target_id, target_kind=target_kind).count() @classmethod def get(cls, user_id, target_id, target_kind): return cls.query.filter_by(user_id=user_id, target_id=target_id, target_kind=target_kind).first()
class LoginModel(db.Model): __tablename__ = 'login' __table_args__ = {'schema': 'membership'} id = db.Column(db.Integer, primary_key=True, autoincrement=True) login_name = db.Column(db.String(255), nullable=False) display_name = db.Column(db.String(100), nullable=False) password = db.Column(db.String(100), nullable=False) email = db.Column(db.String(255)) organization_id = db.Column(db.Integer, db.ForeignKey('membership.organization.id'), nullable=False) organization = db.relationship('OrganizationModel', foreign_keys=[organization_id]) db.UniqueConstraint('email', 'login_name') @property def serialize(self): return { 'id': str(self.id), 'login_name': self.login_name, 'display_name': self.display_name, 'password': self.password, 'email': self.email, 'organization_id': str(self.organization_id), }
class OrganizationModel(db.Model): __tablename__ = 'organization' __table_args__ = {'schema': 'membership'} id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String(50), nullable=False) is_master = db.Column(db.Boolean, nullable=False) db.UniqueConstraint('name') @property def serialize(self): return { 'id': str(self.id), 'name': self.name, 'is_master': str(self.is_master), }
class DancingClassPerson(db.Model, TrackModifications): __tablename__ = TABLE_DANCING_CLASS_PERSON __table_args__ = (db.UniqueConstraint("dancing_class_id", "person_id", name="_dancing_class_person_uc"),) id = db.Column(db.Integer(), primary_key=True) dancing_class_id = db.Column(db.Integer(), db.ForeignKey(f"{TABLE_DANCING_CLASS}.id", ondelete="CASCADE"), nullable=False) dancing_class = db.relationship("DancingClass", lazy=False) person_id = db.Column(db.Integer(), db.ForeignKey(f"{TABLE_PERSON}.id", ondelete="CASCADE"), nullable=False) person = db.relationship("Person", lazy=False) passed_triage = db.Column(db.Boolean, nullable=False, default=True) notes = db.Column(db.String(256), nullable=True) dancing_class_couples_leads = db.relationship("DancingClassCouple", foreign_keys="DancingClassCouple.person_id", cascade="all, delete, delete-orphan", lazy=False) dancing_class_couples_follows = db.relationship("DancingClassCouple", foreign_keys="DancingClassCouple.partner_id", cascade="all, delete, delete-orphan", lazy=False) def __repr__(self): return f"{self.person} - {self.dancing_class}" @property def partners(self): return [dcc.partner.person for dcc in self.dancing_class_couples_leads] + \ [dcc.person.person for dcc in self.dancing_class_couples_follows] def json(self): data = { "id": self.id, "person": { "id": self.person.id, }, "email": self.person.email, "full_name": self.person.full_name, "student_number": self.person.student_number, "passed_triage": self.passed_triage, "notes": self.notes, } return data
class Contact(BaseMixin, db.Model): __tablename__ = "contacts" to_id = db.Column(db.Integer) from_id = db.Column(db.Integer) __table_args__ = ( db.UniqueConstraint("from_id", "to_id", name="uk_from_to"), db.Index("idx_to_time_from", to_id, "created_at", from_id), db.Index("idx_time_to_from", "created_at", to_id, from_id), ) def update(self, **kwargs): # Contact表不应该被更新 raise NotImplementedError("contact table can`t update ") @classmethod def create(cls, **kwargs): ok, obj = super().create(**kwargs) cls.clear_mc(obj, 1) if ok: from .feed import feed_to_followers feed_to_followers(obj.from_id, obj.to_id) # from handler.tasks import feed_to_followers # feed_to_followers.delay(obj.from_id, obj.to_id) return ok, obj def delete(self): super().delete() self.clear_mc(self, -1) from handler.tasks import remove_user_posts_from_feed remove_user_posts_from_feed.delay(self.from_id, self.to_id) @classmethod @cache(MC_KEY_FOLLOW_ITEM.format("{from_id}", "{to_id}")) def get_follow_item(cls, from_id, to_id): return cls.query.filter_by(from_id=from_id, to_id=to_id).first() @classmethod @cache(MC_KEY_FOLLOWING.format("{user_id}", "{page}")) def get_following_ids(cls, user_id, page=1): query = cls.query.with_entities(cls.to_id).filter_by(from_id=user_id) following = query.paginate(page, PER_PAGE) following.items = [id for id, in following.items] del following.query return following @classmethod @cache(MC_KEY_FOLLOWERS.format("{user_id}", "{page}")) def get_follower_ids(cls, user_id, page=1): query = cls.query.with_entities(cls.from_id).filter_by(to_id=user_id) follower = query.paginate(page, PER_PAGE) follower.items = [id for id, in follower.items] del follower.query return follower @classmethod def clear_mc(cls, target, amount): to_id = target.to_id from_id = target.from_id st = userFollowStats.get_or_create(to_id) follower_count = st.follower_count or 0 st.follower_count = follower_count + amount st.save() st = userFollowStats.get_or_create(from_id) following_count = st.following_count or 0 st.following_count = following_count + amount st.save() rdb.delete(MC_KEY_FOLLOW_ITEM.format(from_id, to_id)) for user_id, total, mc_key in ( (to_id, follower_count, MC_KEY_FOLLOWERS), (from_id, following_count, MC_KEY_FOLLOWING), ): pages = math.ceil((max(total, 0) or 1) / PER_PAGE) for p in range(1, pages + 1): rdb.delete(mc_key.format(user_id, p))
class Contact(BaseMixin, db.Model): __tablename__ = 'contacts' to_id = db.Column(db.Integer) from_id = db.Column(db.Integer) __table_args__ = ( db.UniqueConstraint('from_id', 'to_id', name='uk_from_to'), db.Index('idx_to_time_from', to_id, 'created_at', from_id), db.Index('idx_time_to_from', 'created_at', to_id, from_id), ) def update(self, **kwargs): raise NotAllowedException @classmethod def create(cls, **kwargs): ok, obj = super().create(**kwargs) cls.clear_mc(obj, 1) # amount = 1 if ok: from handler.tasks import feed_to_followers feed_to_followers.delay(obj.from_id, obj.to_id) return ok, obj def delete(self): super().delete() self.clear_mc(self, -1) from handler.tasks import remove_user_posts_from_feed remove_user_posts_from_feed.delay(self.from_id, self.to_id) @classmethod @cache(MC_KEY_FOLLOWERS % ('{user_id}', '{page}')) def get_follower_ids(cls, user_id, page=1): query = cls.query.with_entities(cls.from_id).filter_by(to_id=user_id) followers = query.paginate(page, PER_PAGE) followers.items = [id for id, in followers.items] del followers.query # fix 'TypeError: can't pickle _thread.lock objects' return followers @classmethod @cache(MC_KEY_FOLLOWING % ('{user_id}', '{page}')) def get_following_ids(cls, user_id, page=1): query = cls.query.with_entities(cls.to_id).filter_by(from_id=user_id) following = query.paginate(page, PER_PAGE) following.items = [id for id, in following.items] del following.query return following @classmethod @cache(MC_KEY_FOLLOW_ITEM % ('{from_id}', '{to_id}')) def get_follow_item(cls, from_id, to_id): return cls.query.filter_by(from_id=from_id, to_id=to_id).first() @classmethod def clear_mc(cls, target, amount): to_id = target.to_id from_id = target.from_id st = userFollowStats.get_or_create(to_id) follower_count = st.follower_count or 0 st.follower_count = follower_count + amount st.save() st = userFollowStats.get_or_create(from_id) following_count = st.following_count or 0 st.following_count = following_count + amount st.save() # `class:BaseMixin:save` rdb.delete(MC_KEY_FOLLOW_ITEM % (from_id, to_id)) # should be `follower_count + amount`, `following_count + amount`? for user_id, total, mc_key in ((to_id, follower_count, MC_KEY_FOLLOWERS), (from_id, following_count, MC_KEY_FOLLOWING)): pages = math.ceil((max(total, 0) or 1) / PER_PAGE) for p in range(1, pages + 1): rdb.delete(mc_key % (user_id, p))