ããã¯ã·ãªãŒãºã®8çªç®ã®èšäºã§ãFlaskãã€ã¯ããã¬ãŒã ã¯ãŒã¯ã䜿çšããŠPython Webã¢ããªã±ãŒã·ã§ã³ãäœæããçµéšã説æããŠããŸãã
ãã®ã¬ã€ãã®ç®çã¯ãããªãæ©èœçãªãã€ã¯ãããã°ã¢ããªã±ãŒã·ã§ã³ãéçºããããšã§ãããªãªãžããªãã£ãå®å
šã«æ¬ åŠããŠããããããã€ã¯ãããã°ã¢ããªã±ãŒã·ã§ã³ãšåŒã¶ããšã«ããŸããã
çãç¹°ãè¿ã
ç§ãã¡ã®å°ããªãã€ã¯ãããã°ã¯ãã£ãããšæé·ããŠãããä»æ¥ã¯å®å
šãªã¢ããªã±ãŒã·ã§ã³ã«å¿
èŠãªãããã¯ãåãäžããŸãã
ä»æ¥ã¯ãããŒã¿ããŒã¹ã§å°ãäœæ¥ããŸãã
ã¢ããªã±ãŒã·ã§ã³ã®åãŠãŒã¶ãŒã¯ã远跡ãããŠãŒã¶ãŒãéžæã§ããå¿
èŠããããããŒã¿ããŒã¹ã«ã¯ã誰ã誰ã远跡ããŠãããã«é¢ããããŒã¿ãä¿åããå¿
èŠããããŸãã ãã¹ãŠã®ãœãŒã·ã£ã«ã¢ããªã±ãŒã·ã§ã³ã«ã¯ãããŸããŸãªããªãšãŒã·ã§ã³ã®ãããã®æ©èœããããŸãã é£çµ¡å
ããªã³ã¯ãåéãåéã賌èªè
ãªã©ãšåŒã°ãã人ãããŸãã äžéšã®ãµã€ãã§ã¯ãèš±å¯ãŠãŒã¶ãŒãšç¡èŠãŠãŒã¶ãŒã®ãªã¹ãã«åæ§ã®èãæ¹ã䜿çšããŠããŸãã ãããããµãã¹ã¯ã©ã€ããŒãšåŒã³ãŸãããååãä¿æããŠå®è£
ããããšã¯ãããŸããã
ãµãã¹ã¯ã©ã€ããŒæ©èœã®èšèš
ã³ãŒããæžãå§ããåã«ããã®æ©èœããååŸãããæ©èœã«ã€ããŠèããŠã¿ãŸãããã æãæçœãªãã®ããå§ããŸãããã ãŠãŒã¶ãŒãä»ã®ãŠãŒã¶ãŒãžã®ãµãã¹ã¯ãªãã·ã§ã³ã®ãªã¹ãã䟿å©ã«ç®¡çã§ããããã«ããããšèããŠããŸãã äžæ¹ãåãŠãŒã¶ãŒã®ãµãã¹ã¯ã©ã€ããŒã®ãªã¹ããç¥ãããã§ãã ãŸãããŠãŒã¶ãŒããµãã¹ã¯ã©ã€ããŒãæã£ãŠãããã©ããããŸãã¯ä»ã®ãŠãŒã¶ãŒããµãã¹ã¯ã©ã€ãããŠãããã©ããã確èªã§ããããã«ããããšèããŠããŸãã ãŠãŒã¶ãŒã¯ãä»ã®ãŠãŒã¶ãŒã®ãããã¡ã€ã«ã«ããã賌èªããªã³ã¯ãã¯ãªãã¯ããŠã远跡ãéå§ããŸãã åæ§ã«ãç»é²è§£é€ãªã³ã¯ãã¯ãªãã¯ãããšããŠãŒã¶ãŒã®ç»é²ã解é€ãããŸãã æåŸã®èŠä»¶ã¯ããŠãŒã¶ãŒãããŒã¿ããŒã¹ããç£èŠå¯Ÿè±¡ãŠãŒã¶ãŒã®ãã¹ãŠã®æçš¿ãèŠæ±ã§ããããšã§ãã
ããã§ãããªãããããéããŠç°¡åã§ãããšæã£ããªãã°ãããäžåºŠèããŠãã ããïŒ
ããŒã¿ããŒã¹å
ã®éä¿¡
ãã¹ãŠã®ãŠãŒã¶ãŒã®ãµãã¹ã¯ã©ã€ããŒãšãµãã¹ã¯ãªãã·ã§ã³ã®ãªã¹ããå¿
èŠã ãšèšããŸããã æ®å¿µãªããããªã¬ãŒã·ã§ãã«ããŒã¿ããŒã¹ã¯@@ list @@åã§ã¯ãããŸãããã¬ã³ãŒããšã¬ã³ãŒãéã®ãªã¬ãŒã·ã§ã³ãæã€ããŒãã«ã ãããããŸãã ããŒã¿ããŒã¹ã«ã¯ãã§ã«ãŠãŒã¶ãŒãè¡šãããŒãã«ããããŸããããµãã¹ã¯ã©ã€ããŒãšãµãã¹ã¯ãªãã·ã§ã³ã®é¢ä¿ãã·ãã¥ã¬ãŒãããäŸåé¢ä¿ãèãåºãå¿
èŠããããŸãã ããã¯ããªã¬ãŒã·ã§ãã«ããŒã¿ããŒã¹ã®3çš®é¡ã®é¢ä¿ã解æããè¯ãæ©äŒã§ãã
1察å€
ããŒã¿ããŒã¹ã«é¢ãã以åã®èšäºã§ã1察å€ã®é¢ä¿ããã§ã«èŠãŸããã

ãã®ãããªé¢ä¿ã§æ¥ç¶ãããŠãã2ã€ã®ãšã³ãã£ãã£ã¯ã
users
ãš
posts
ã§ãã ãŠãŒã¶ãŒã¯å€ãã®æçš¿ãæã€ããšãã§ããæçš¿ã«ã¯ãŠãŒã¶ãŒã1人ããããªããšèšããŸãã ãããã®é¢ä¿ã¯ããå€ãåŽã«å€éšããŒïŒFKïŒãæã€ããŒã¿ããŒã¹ã§äœ¿çšãããŸãã äžèšã®äŸã§ã¯ãå€éšããŒã¯
posts
ããŒãã«ã«è¿œå ããã
user_id
ãã£ãŒã«ãã§ãã ãã®ãã£ãŒã«ãã¯ãåæçš¿ããŠãŒã¶ãŒããŒãã«ã®äœæè
ã«é¢ããæçš¿ã«é¢é£ä»ããŸãã
user_id
ãã£ãŒã«ãããã®æçš¿ã®èè
ãžã®çŽæ¥ã¢ã¯ã»ã¹ãæäŸããããšã¯æããã§ããããã£ãŒãããã¯ã«ã€ããŠã¯ã©ãã§ããïŒ ãªã³ã¯ã圹ç«ã€ããã«ã¯ããŠãŒã¶ãŒãæžããæçš¿ã®ãªã¹ããååŸã§ããªããã°ãªããŸããã ããŒã¿ããŒã¹ã«ã¯ãuser_idãXã§ãããã¹ãŠã®ã¡ãã»ãŒãžãååŸããããªã©ã®ã¯ãšãªãäœæã§ããã€ã³ããã¯ã¹ãããããã
posts
ããŒãã«ã®
user_id
ãã£ãŒã«ãã§è³ªåã«çããããšãã§ããŸãã
å€å¯Ÿå€
å€å¯Ÿå€ã®é¢ä¿ã¯ããå°ãè€éã§ãã ããšãã°ã
students
ãš
teachers
ãä¿åãããŠããããŒã¿ããŒã¹ãèããŠã¿ãŸãããã åŠçã¯å€ãã®æåž«ãæã€ããšãã§ããæåž«ã¯å€ãã®åŠçãæã€ããšãã§ãããšèšããŸãã ããã¯ã2ã€ã®éšåçã«éè€ãã1察å€ã®é¢ä¿ã«äŒŒãŠããŸãã
ãã®ã¿ã€ãã®é¢ä¿ã«ã€ããŠã¯ãããŒã¿ããŒã¹ã«ã¯ãšãªãå®è¡ããåŠçãæããæåž«ã®ãªã¹ããšæåž«ã®ã¯ã©ã¹ã®åŠçã®ãªã¹ããååŸã§ããå¿
èŠããããŸãã ããŒã¿ããŒã¹ã§ã¯æ³åããã®ãããªãé£ããããšãããããŸãããã®ãããªé¢ä¿ã¯ãæ¢åã®ããŒãã«ã«å€éšããŒãè¿œå ããŠã¢ãã«åããããšã¯ã§ããŸããã
å€å¯Ÿå€ã®ãªã¬ãŒã·ã§ã³ã·ãããå®è£
ããã«ã¯ãããããããŒãã«ãšåŒã°ããè£å©ããŒãã«ã䜿çšããå¿
èŠããããŸãã ããšãã°ãããã§ã¯ãçåŸãšæåž«ã®ããŒã¿ããŒã¹ã®ããã«ãªããŸãã

ããã¯è€éã«æãããããããŸããããããããããŒãã«ã¯ã次ã®ãããªå€ãã®è³ªåã«çããããšãã§ããŸãã
- çåŸSã¯èª°ããåŠãã§ããŸããïŒ
- Tå
çã¯èª°ã«æããŸããïŒ
- æåž«TãããçåŸã¯äœäººã§ããïŒ
- çåŸSã«ã¯äœäººã®æåž«ãããŸããïŒ
- å
çTã¯çåŸSãæããŸããïŒ
- åŠçSã¯æåž«ã¯ã©ã¹Tã«åå ããŸããïŒ
äžå¯Ÿäž
1察1ã®é¢ä¿ã¯ã1察å€ã®é¢ä¿ã®ç¹æ®ãªã±ãŒã¹ã§ãã ãã¥ãŒã¯éåžžã«äŒŒãŠããŸããã1察å€ã«ãªããªãããã«ãè€æ°ã®ãªã³ã¯ã®è¿œå ãçŠæ¢ãããŠããŸãã ãã®ã¿ã€ãã®é¢ä¿ã圹ç«ã€å ŽåããããŸãããããã¯ä»ã®2ã€ã®ã¿ã€ãã®å Žåã»ã©é »ç¹ã«ã¯èµ·ãããŸããã2ã€ã®ããŒãã«ã1察1ã®é¢ä¿ã§æ¥ç¶ãããŠããç¶æ³ã§ã¯ãããŒãã«ã1ã€ã«çµåããããšãçã«ããªã£ãŠããããã§ãã
ãµãã¹ã¯ã©ã€ããŒ/ãµãã¹ã¯ãªãã·ã§ã³ã®æåº
äžèšã®é¢ä¿ããããŠãŒã¶ãŒã¯ä»ã®å€ãã®ãŠãŒã¶ãŒããã©ããŒã§ãããŠãŒã¶ãŒã¯å€ãã®ãµãã¹ã¯ã©ã€ããŒãæã€ããšãã§ãããããå€å¯Ÿå€ã®ããŒââã¿ã¢ãã«ãé©ããŠãããã©ãããç°¡åã«å€æã§ããŸãã ããããæ©èœããããŸãã ä»ã®ãŠãŒã¶ãŒã«ãµãã¹ã¯ã©ã€ãããŠãããŠãŒã¶ãŒãè¡šãããã®ã§ããããŠãŒã¶ãŒããŒãã«ã¯1ã€ãããããŸããã ããã§ã¯ãå€å¯Ÿå€ã®é¢ä¿ã§2çªç®ã®ãšã³ãã£ãã£ãšããŠäœã䜿çšãã¹ãã§ããããïŒ
ãã¡ããããªã¬ãŒã·ã§ã³ã·ããã®2çªç®ã®ãšã³ãã£ãã£ã¯åããŠãŒã¶ãŒããŒãã«ã«ãªããŸãã ãšã³ãã£ãã£ã®ã€ã³ã¹ã¿ã³ã¹ãåããšã³ãã£ãã£ã®ä»ã®ã€ã³ã¹ã¿ã³ã¹ã«é¢é£ä»ããããŠããé¢ä¿ã¯ãèªå·±åç
§é¢ä¿ãšåŒã°ãããŸãã«ãããå¿
èŠãªãã®ã§ãã
ããã¯ãå€å¯Ÿå€ã®é¢ä¿ã®å³ã§ãã

followers
ããŒãã«ã¯ããããããŒãã«ã§ãã äž¡æ¹ã®å€éšããŒã¯ã
user
ããŒãã«ãæããŸãã ããŒãã«ãèªåèªèº«ã«ãªã³ã¯ããŸããã ãã®è¡šã®åãšã³ããªã¯ã賌èªããŠãããŠãŒã¶ãŒãšè³ŒèªããŠãããŠãŒã¶ãŒãšã®é¢ä¿ãè¡šããŸãã çåŸãšæåž«ã®äŸã®ããã«ããã®ãããªæ§æã«ãããããŒã¿ããŒã¹ã¯å¿
èŠãªãµãã¹ã¯ã©ã€ããŒãšãã®ãµãã¹ã¯ãªãã·ã§ã³ã«é¢ãããã¹ãŠã®è³ªåã«çããããšãã§ããŸãã ãšãŠãç°¡åã§ãã
DBã¢ãã«
ã¢ãã«ã®å€æŽã¯ããã»ã©å€§ãããããŸããã ããŒãã«@@ãã©ãã¯ãŒ@@ïŒãã¡ã€ã«@@ app / models.py @@ïŒãè¿œå ããããšããå§ããŸãã
followers = db.Table('followers', db.Column('follower_id', db.Integer, db.ForeignKey('user.id')), db.Column('followed_id', db.Integer, db.ForeignKey('user.id')) )
ããã¯ãå³ããã®ããŒãã«ãªã³ã¯ã®ã©ã€ãå€æã§ãã
users
ãš
posts
ã«å¯ŸããŠè¡ã£ãããã«ããã®ããŒãã«ãã¢ãã«ãšããŠå®£èšããªãã£ãããšã«æ³šæããŠãã ããã ããã¯å€éšããŒä»¥å€ã®ããŒã¿ãæããªããã«ããŒããŒãã«ã§ãããããäœã¬ãã«ã®ãã©ã¹ã³sqlalchemy APIã䜿çšããŠãã¢ãã«ãäœæããã«ããŒãã«ãäœæããŸãã
次ã«ã
users
ããŒãã«ïŒãã¡ã€ã«
app/models.py
ïŒã§å€å¯Ÿå€ã®é¢ä¿ã説æããŸã
class User(db.Model): id = db.Column(db.Integer, primary_key = True) nickname = db.Column(db.String(64), unique = True) email = db.Column(db.String(120), index = True, unique = True) role = db.Column(db.SmallInteger, default = ROLE_USER) posts = db.relationship('Post', backref = 'author', lazy = 'dynamic') about_me = db.Column(db.String(140)) last_seen = db.Column(db.DateTime) 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')
é¢ä¿ã®æ§æã¯éèŠã§ããã説æãå¿
èŠã§ãã åã®èšäºã§è¡ã£ãããã«ã
db.relationship
é¢æ°ã䜿çšããŠãããŒãã«éã®é¢ä¿ã決å®ããŸãã
User
ã€ã³ã¹ã¿ã³ã¹ãå¥ã®
User
ã€ã³ã¹ã¿ã³ã¹ã«é¢é£ä»ããŸããåæããããã«ãé¢é£ãããŠãŒã¶ãŒã®ãã¢ã§ã¯ãå·Šã®ãŠãŒã¶ãŒãå³ã®ãŠãŒã¶ãŒã«ãµãã¹ã¯ã©ã€ãããããšèšããŸãã é¢ä¿ã®èª¬æãããããããã«ãå·ŠåŽã®é¢ä¿ãèŠæ±ãããšããµãã¹ã¯ã©ã€ãã®ãªã¹ããååŸããããããå·ŠåŽãfollowdãšåŒã³ãŸãã ãã¹ãŠã®
db.relationship
åŒæ°ã
db.relationship
èŠãŠã¿ãŸãããã
'User'
é¢ä¿ã®ãšã³ãã£ãã£ã®å³åŽã§ãïŒå·ŠåŽã¯èŠªã¯ã©ã¹ã§ãïŒã èªå·±åç
§é¢ä¿ãå®çŸ©ããå Žåãäž¡åŽã§åãã¯ã©ã¹ã䜿çšããŸãã- ãã®é¢ä¿ã§äœ¿çšãããããããããŒãã«ãžã®
secondary
ãã€ã³ãã primaryjoin
ã¯ããšã³ãã£ãã£ã®å·ŠåŽãšããããããŒãã«ã®éã®é¢ä¿ãèšè¿°ããŸãã followers
ããŒãã«ã¯ã¢ãã«ã§ã¯ãªãããããã£ãŒã«ãåãååŸããããã«å°ãå¥åŠãªæ§æã䜿çšãããŠããããšã«æ³šæããŠãã ãããsecondaryjoin
ã¯ãå³åŽãšããããããŒãã«ã®é¢ä¿ãè¡šããŸããbackref
ã¯ããšã³ãã£ãã£ã®å³åŽã§ãããã®é¢ä¿ãã©ã®ããã«å©çšå¯èœã«ãªããã説æããŸãã ç¹å®ã®ãŠãŒã¶ãŒã«ã€ããŠã followed
ã¯ãšãªã¯ãå·ŠåŽã®ãŠãŒã¶ãŒã«é¢é£ä»ããããŠããå³åŽã®ãã¹ãŠã®ãŠãŒã¶ãŒãè¿ããšèšããŸããã ããã¯ãªã³ã¯ã¯followers
ãšåŒã°ããå³åŽã®ãŠãŒã¶ãŒã«é¢é£ä»ããããŠããå·ŠåŽã®ãã¹ãŠã®ãŠãŒã¶ãŒãè¿ããŸãã ãªãã·ã§ã³ã®lazy
åŒæ°ã¯ããã®ãªã¯ãšã¹ãã®å®è¡æ¹æ³ãæå®ããŸãã ãã®ã¢ãŒãã¯ãæ瀺çã«èŠæ±ããããŸã§èŠæ±ãå®è¡ããªãããšã瀺ããŸãã ããã¯ããã©ãŒãã³ã¹ãæ¹åããã®ã«åœ¹ç«ã¡ãŸãããŸããå®è¡åã«ãã®ãªã¯ãšã¹ããåä¿¡ããŠââå€æŽã§ããããã§ãã ããã«ã€ããŠã¯åŸã§è©³ãã説æããŸããlazy
ãã©ã¡ãŒã¿ãŒã¯backref
ã®åãååã®ãã©ã¡ãŒã¿ãŒã«å°ã䌌ãŠããŸãããããã¯ãã£ãŒãããã¯ã§ã¯ãªããªã¯ãšã¹ããåç
§ããŠããŸãã
ç解ããã®ãé£ããå Žåã絶æããªãã§ãã ããã ãããã®ã¯ãšãªã®äœ¿çšæ¹æ³ã確èªãããšããã¹ãŠãæ確ã«ãªããŸãã ããŒã¿ããŒã¹ã®æŽæ°ãè¡ã£ãã®ã§ãæ°ãã移è¡ãäœæã§ããŸãã
./db_migrate.py
ããã§ããŒã¿ããŒã¹ã®å€æŽãå®äºããŸããã å°ãçªã£èŸŒãã ãŸãŸã§ãã
ãµãã¹ã¯ã©ã€ããŒã®è¿œå ãšåé€
ã³ãŒãã®åå©çšããµããŒãããããã«ã
User
ã¢ãã«å
ã«subscription \ subscribersæ©èœãå®è£
ãããã¥ãŒã«é
眮ããŸããã ãããã£ãŠããã®é¢æ°ãçŸåšã®ã¢ããªã±ãŒã·ã§ã³ïŒãã¥ãŒããåç
§ïŒã«äœ¿çšãããã¹ãã§äœ¿çšã§ããŸãã ååãšããŠãã¢ããªã±ãŒã·ã§ã³ããžãã¯ããã¥ãŒããã¢ãã«ã«ç§»åããæ¹ãåžžã«åªããŠããŸããããã«ããããã¹ãã倧å¹
ã«ç°¡çŽ åãããŸãã èªåã¢ãŒãã§ãã¹ãããã®ã¯é£ãããããæåºç©ã¯ã§ããã ãã·ã³ãã«ã«ããŠããå¿
èŠããããŸãã
以äžã¯ã
User
ã¢ãã«ã®ã¡ãœããïŒãã¡ã€ã«
app/models.py
ïŒãšããŠå®çŸ©ãããŠããããµãã¹ã¯ã©ã€ããŒãè¿œå ããã³åé€ããããã®ã³ãŒãã§ãã
class User(db.Model):
å€ãã®äœæ¥ãè¡ãSQL Alchemyã®ãã¯ãŒã®ãããã§ããããã®æ¹æ³ã¯é©ãã»ã©ç°¡åã§ãã èŠçŽ ãè¿œå ãŸãã¯åé€ããã ãã§ãæ®ãã¯SQLAlchemyãè¡ããŸãã
follow
unfollow
ãš
unfollow
ããã¹ãŠãããŸããã£ããšãã«ãªããžã§ã¯ããè¿ããæäœã倱æãããšãã«Noneãè¿ãããã«å®çŸ©ãããŠããŸãã ãªããžã§ã¯ããè¿ãããããããŒã¿ããŒã¹ã«è¿œå ããŠã³ãããããå¿
èŠããããŸãã
is_following
ã¡ãœããã¯ã1è¡ã®ã³ãŒãã«ãããããããéåžžã«å€ãã®ããšãè¡ããŸãã ãŠãŒã¶ãŒã®åå ã䌎ããã¹ãŠã®ãã¢
(follower, followed)
ãè¿ããªã¯ãšã¹ããåãå
¥ãã
(follower, followed)
ãããåã§ãããããã£ã«ã¿ãªã³ã°ããŸãã å€æŽããããªã¯ãšã¹ãã¯ããŸã å®äºããŠããªã
filter()
ããè¿ãã
filter()
ã ãããã£ãŠããã®ãªã¯ãšã¹ãã§
count()
ãåŒã³åºããšããã®ãªã¯ãšã¹ããå®è¡ãããèŠã€ãã£ãã¬ã³ãŒãã®æ°ãè¿ãããŸãã å°ãªããšã1ã€ååŸããã°ãæ¥ç¶ãããããšãããããŸãã äœãåŸãããªãå Žåãæ¥ç¶ããªãããšãããããŸãã
ãã¹ãäž
ã³ãŒãã®ãã¹ããäœæããŸãããïŒ
tests.py
ãã¡ã€ã«ïŒïŒ
class TestCase(unittest.TestCase):
ãã®ãã¹ãããã¹ããã¬ãŒã ã¯ãŒã¯ã«è¿œå ããåŸã次ã®ã³ãã³ãã§ãã¹ãã¹ã€ãŒããéå§ã§ããŸãã
./tests.py
ãããŠããã¹ãŠãæ©èœããå Žåããã¹ãŠã®ãã¹ãã«åæ ŒããŸãã
ããŒã¿ããŒã¹ã¯ãšãª
çŸåšã®ããŒã¿ããŒã¹ã¢ãã«ã¯ãæåã«ãªã¹ãããèŠä»¶ã®ã»ãšãã©ããµããŒãããŠããŸãã æ¬ ããŠããã®ã¯ãå®éã«å®çŸããã®ãæãé£ããããšã§ãã ãµã€ãã®ã¡ã€ã³ããŒãžã«ã¯ããã°ã€ã³ããŠãããŠãŒã¶ãŒããã©ããŒããŠãããã¹ãŠã®äººãæžããã¡ãã»ãŒãžã衚瀺ããããããããããã¹ãŠã®ã¡ãã»ãŒãžãè¿ããªã¯ãšã¹ããå¿
èŠã§ãã
æãæãããªè§£æ±ºçã¯ãæ¢ã«äœæã§ãã远跡察象ã®ãŠãŒã¶ãŒã®ãªã¹ããæäŸããã¯ãšãªã§ãã 次ã«ããããã®åãŠãŒã¶ãŒã«å¯ŸããŠããã®ã¡ãã»ãŒãžãåä¿¡ããããã«ãªã¯ãšã¹ããå®è¡ããŸãã ãã¹ãŠã®ã¡ãã»ãŒãžãæã£ããããããã1ã€ã®ãªã¹ãã«ãŸãšããŠãæéé ã«äžŠã¹æ¿ããããšãã§ããŸãã ããã¯ããã§ããïŒ ããã§ããªãã
ãã®ã¢ãããŒãã«ã¯ããã€ãã®åé¡ããããŸãã ãŠãŒã¶ãŒã1000人ã远跡ãããšã©ããªããŸããïŒ ã¡ãã»ãŒãžãåéããããã ãã«ãããŒã¿ããŒã¹ã«å¯ŸããŠ1000ã®ã¯ãšãªãå®è¡ããå¿
èŠããããŸãã ãããŠä»ãç§ãã¡ã¯ã¡ã¢ãªå
ã«äœåãã®ãªã¹ããæã£ãŠããŸãã ã¡ã€ã³ããŒãžã«ã¯ããŒãžçªå·ãå®è£
ãããŠããããã䜿çšå¯èœãªãã¹ãŠã®ã¡ãã»ãŒãžã¯è¡šç€ºãããŸããããæåã®50件ãšæ¬¡ã®50件ã衚瀺ã§ãããªã³ã¯ã®ã¿ã衚瀺ãããŸããæ¥ä»é ã«ã¡ãã»ãŒãžã衚瀺ããå Žåãã©ã®ã¡ãã»ãŒãžãæåŸã®50件ã§ããããç¥ãã«ã¯æåã«ãã¹ãŠã®ã¡ãã»ãŒãžãåä¿¡ããŠââãœãŒãããªãéãããã¹ãŠã®ãŠãŒã¶ãŒã
ããã¯å®éã«ã¯éåžžã«è²§åŒ±ãªèŠæš¡ã®ã²ã©ã解決çã§ãã åéãšãœãŒãã®ãã®æ¹æ³ã¯äœããã®åœ¢ã§æ©èœããŸãããååã«å¹æçã§ã¯ãããŸããã ããã¯ãŸãã«ããªã¬ãŒã·ã§ãã«ããŒã¿ããŒã¹ãæåããä»äºã§ãã ããŒã¿ããŒã¹ã«ã¯ã€ã³ããã¯ã¹ãå«ãŸããŠãããã¯ãšãªãå®è¡ããããœãŒããããããã®ã«ãèªåã§ã§ãããããã¯ããã«å¹ççã§ãã
åãåããããã®ãè¡šãã¯ãšãªãäœæããå¿
èŠããããããŒã¿ããŒã¹ã¯å¿
èŠãªæ
å ±ãããå¹æçã«æœåºããæ¹æ³ãèŠã€ãåºããŸãã
è¬ãææããããã«ãç§ãã¡ãå¿
èŠãšããããšããããªã¯ãšã¹ãããããŸãã æ®å¿µãªãããããã¯å¥ã®ãªãŒããŒããŒããããåäžè¡ã§ããããŠãŒã¶ãŒã¢ãã«ïŒ
app.models.py
ãã¡ã€ã«ïŒã«è¿œå ããŸãã
class User(db.Model):
ãã®èŠæ±ã段éçã«è§£èªããŠã¿ãŸãããã 3ã€ã®éšåããããŸãïŒjoinãfilterãorder_byã
åå ãã
çµåæäœã®æ©èœãç解ããããã«ãäŸãèŠãŠã¿ãŸãããã 次ã®å
容ã®
User
ããŒãã«ããããšããŸãïŒ
ãŠãŒã¶ãŒ |
---|
id | ããã¯ããŒã |
---|
1 | ãžã§ã³ |
2 | ã¹ãŒã¶ã³ |
3 | ã¡ã¢ãªãŒ |
4 | ãããã |
äŸãè€éã«ããªãããã«ãããŒãã«ã®ä»ã®ãã£ãŒã«ãã¯è¡šç€ºãããŸããã
ããããããŒãã«ã§ããŠãŒã¶ãŒãjohnãã¯ãsusanããšãdavidãã«ãµãã¹ã¯ã©ã€ãããããŠãŒã¶ãŒãsusanãã¯ãmaryãã«ãµãã¹ã¯ã©ã€ãããããmaryãã¯ãdavidãã«ãµãã¹ã¯ã©ã€ããããŠãããšä»®å®ããŸãã ããããããŒãã«ã¯æ¬¡ã®ããã«ãªããŸãã
ãã©ãã¯ãŒ |
---|
follower_id | followed_id |
---|
1 | 2 |
1 | 4 |
2 | 3 |
3 | 4 |
çµè«ãšããŠã
Post
ããŒãã«ã«ã¯åãŠãŒã¶ãŒããã®1ã€ã®æçš¿ãå«ãŸããŠããŸãã
æçš¿ |
---|
id | ããã¹ã | user_id |
---|
1 | ã¹ãŒã¶ã³ããã®æçš¿ | 2 |
2 | ã¡ã¢ãªãŒããã®æçš¿ | 3 |
3 | ããããããã®æçš¿ | 4 |
4 | ãžã§ã³ããã®æçš¿ | 1 |
ããã§ã¯ãäŸãè€éã«ããªãããã«ãããã€ãã®ãã£ãŒã«ããåé€ãããŠããŸãã
以äžã¯ãçµåãä»ã®éšåããåé¢ããããªã¯ãšã¹ãã®äžéšã§ãã
Post.query.join(followers, (followers.c.followed_id == Post.user_id))
join
æäœã¯ã
Post
ããŒãã«ã§åŒã³åºãããŸãã 2ã€ã®åŒæ°ããããŸããæåã®åŒæ°ã¯å¥ã®ããŒãã«ããã®å Žåã¯
followers
ã§ãã 2çªç®ã®åŒæ°ã¯ãããŒãã«ãçµåãããã£ãŒã«ãã瀺ããŸãã
join
æäœã¯ãæå®ãããæ¡ä»¶ã«åŸã£ãŠã
Post
ããã³
followers
ããŒã¿ãããŒãžãããäžæããŒãã«ãäœæããŸãã
ãã®äŸã§ã¯ã
followers
ããŒãã«ã®
user_id
ãã£ãŒã«ãã
user_id
ããŒãã«ã®
user_id
ãã£ãŒã«ããšäžèŽãã
user_id
ã
ãã®ããŒãžãå®è¡ããã«ã¯ã
Post
ããŒãã«ïŒçµåã®å·ŠéšåïŒããåã¬ã³ãŒããååŸããæ¡ä»¶ã«äžèŽãã
followers
ããŒãã«ïŒçµåã®å³éšåïŒã®ã¬ã³ãŒããããã£ãŒã«ããã¢ã¿ããããŸãã ã¬ã³ãŒããæ¡ä»¶ãæºãããªãå ŽåãããŒãã«ã«åé¡ãããŸããã
ãã®äžæããŒãã«ã®äŸã§çµåãå®è¡ããçµæïŒ
æçš¿ | ãã©ãã¯ãŒ |
---|
id | ããã¹ã | user_id | follower_id | followed_id |
---|
1 | ã¹ãŒã¶ã³ããã®æçš¿ | 2 | 1 | 2 |
2 | ã¡ã¢ãªãŒããã®æçš¿ | 3 | 2 | 3 |
3 | ããããããã®æçš¿ | 4 | 1 | 4 |
3 | ããããããã®æçš¿ | 4 | 3 | 4 |
subscribersããŒãã«ã«followed_id = 1ãååšãããšã³ããªããªããããuser_id = 1ã®ã¡ãã»ãŒãžãã©ã®ããã«åå ããåé€ããããã«æ³šç®ããŠãã ããã ãŸãããµãã¹ã¯ã©ã€ããŒããŒãã«ã«ã¯followed_id = 4ã®ãªã«ã¬ã³ã¹ã2ã€ãããããuser_id = 4ã®ã¡ãã»ãŒãžã2å衚瀺ãããããšã«æ³šæããŠãã ããã
ãã£ã«ã¿ãŒ
åå æäœã¯ããµãã¹ã¯ã©ã€ããŒã誰ã§ããããæå®ããã«ã誰ãããã©ããŒããŠãããŠãŒã¶ãŒããã®ã¡ãã»ãŒãžã®ãªã¹ããæäŸããŸããã ç¹å®ã®1人ã®ãŠãŒã¶ãŒã«ãã£ãŠè¿œè·¡ãããã¡ãã»ãŒãžã®ã¿ãå«ãŸãããã®ãªã¹ãã®ãµãã»ããã«é¢å¿ããããŸãã ãããã£ãŠããã®ããŒãã«ããµãã¹ã¯ã©ã€ããŒã§ãã£ã«ã¿ãŒåŠçããŸãã ãã£ã«ã¿ãŒèŠæ±ã®éšåã¯æ¬¡ã®ãšããã§ãã
filter(followers.c.follower_id == self.id)
ãªã¯ãšã¹ãã¯ã¿ãŒã²ãããŠãŒã¶ãŒã®ã³ã³ããã¹ãã§å®è¡ãããããããã®ã³ã³ããã¹ãã®Userã¯ã©ã¹ã®self.idã¡ãœããã¯ã察象ã®ãŠãŒã¶ãŒã®IDãè¿ããŸãã ãã®ãã£ã«ã¿ãŒã䜿çšããŠããŠãŒã¶ãŒããµãã¹ã¯ã©ã€ããŒãšããŠãªã¹ããããŠããjoinã䜿çšããŠäœæãããããŒãã«ã®ã¬ã³ãŒãã®ã¿ãæ®ãããããšãããŒã¿ããŒã¹ã«äŒããŸãã äŸãç¶ãããšãid = 1ã®ãŠãŒã¶ãŒããªã¯ãšã¹ããããšãå¥ã®äžæããŒãã«ã«ç§»åããŸãã
æçš¿ | ãã©ãã¯ãŒ |
---|
id | ããã¹ã | user_id | follower_id | followed_id |
---|
1 | ã¹ãŒã¶ã³ããã®æçš¿ | 2 | 1 | 2 |
3 | ããããããã®æçš¿ | 4 | 1 | 4 |
ãããŠããããã¯ãŸãã«ç§ãã¡ãå¿
èŠãšããæçš¿ã§ãïŒ
ã¯ãšãªã¯Postã¯ã©ã¹ã§å®è¡ããããããã©ã®ã¢ãã«ã«ãé¢ä¿ããªãäžæããŒãã«ã«ãªã£ããšããŠããçµæã¯ãã®äžæããŒãã«ã«å«ãŸããçµåæäœã«ãã£ãŠè¿œå ã®åãè¿œå ãããããšã¯ãããŸããã
ä»åã
ããã»ã¹ã®æåŸã®ã¹ãããã¯ãåºæºã«åŸã£ãŠçµæããœãŒãããããšã§ãã ãªã¯ãšã¹ãã®äžéšã¯æ¬¡ã®ããã«ãªããŸãã
order_by(Post.timestamp.desc())
ããã§ã¯ãçµæã¯éé ã§
timestamp
ã§ãœãŒããããã¹ãã§ãããããæåŸã®æçš¿ãæåã«ãªããŸãã
ãªã¯ãšã¹ããæ¹åããããã®è©³çŽ°ã¯1ã€ã ãã§ãã ãŠãŒã¶ãŒã賌èªããŠããæçš¿ãèªããšãããã£ãŒãã«èªåã®æçš¿ã衚瀺ãããå ŽåããããŸããã¯ãšãªçµæã«å«ãããšäŸ¿å©ã§ãã
ãããè¡ãç°¡åãªæ¹æ³ããããå€æŽã¯å¿
èŠãããŸããïŒ åãŠãŒã¶ãŒãèªåã®ãµãã¹ã¯ã©ã€ããŒãšããŠããŒã¿ããŒã¹ã«è¿œå ãããŠããããšã確èªããã ãã§ããã®å°ããªåé¡ã¯ããæ°ã«ããŸããã ã¯ãšãªã«é¢ããé·ãè°è«ãç· ããããããã«ãã¯ãšãªã®åäœãã¹ãïŒtests.pyãã¡ã€ã«ïŒãäœæããŸãããã
ãã®ãã¹ãã«ã¯å€ãã®ããªã»ããã³ãŒãããããŸããããã¹ãã³ãŒãèªäœã¯éåžžã«çããã®ã§ãã æåã«ãåãŠãŒã¶ãŒã«è¿ããã远跡ãããæçš¿ã®æ°ãäºæ³ãšçããããšã確èªããŸãã 次ã«ãåãŠãŒã¶ãŒã«å¯ŸããŠãæ£ããæçš¿ãè¿ãããæ£ããé åºã§å°çããããšã確èªããŸãïŒã¿ã€ã ã¹ã¿ã³ããåžžã«åãé åºãä¿èšŒããã¡ãã»ãŒãžãæ¿å
¥ããããšã«æ³šæããŠãã ããïŒã
followed_postïŒïŒã¡ãœããã®äœ¿çšã«æ³šæããŠãã ããã ãã®ã¡ãœããã¯ãçµæã§ã¯ãªãã¯ãšãªãªããžã§ã¯ããè¿ããŸãã é
延=ãåçãã¯ãDBé¢ä¿ã§ãæ©èœããŸãã
çµæã®ä»£ããã«ãªããžã§ã¯ããè¿ãããšã¯åžžã«è¯ãèãã§ãããªããªããåŒã³åºãå
ã«å®è¡åã«ã¯ãšãªãè£è¶³ããæ©äŒãäžããããã§ãã
ã¯ãšãªãå®è¡ããã«ã¯ãã¯ãšãªãªããžã§ã¯ãã«ããã€ãã®ã¡ãœããããããŸãã countïŒïŒãã¯ãšãªãå®è¡ããçµæã®æ°ãè¿ããããŒã¿èªäœãç Žæ£ããããšãããããŸããã ãŸããfirstïŒïŒã䜿çšããŠããªã¹ãã®æåã®çµæãè¿ããæ®ããç Žæ£ããŸããã ãã¹ãã§ã¯ãallïŒïŒã¡ãœããã䜿çšããŠããã¹ãŠã®çµæãå«ãé
åãååŸããŸããã
å¯èœãªæ¹å
å¿
èŠãªãã¹ãŠã®ãµãã¹ã¯ãªãã·ã§ã³æ©èœãå®è£
ããŸãããããã¶ã€ã³ãæ¹åããŠããæè»ã«ããããã®æ¹æ³ãããã€ããããŸãã ç§ãã¡ãå«ããªãœãŒã·ã£ã«ãããã¯ãŒã¯ã¯ãã¹ãŠããããããŠãŒã¶ãŒã®æ¥ç¶æ¹æ³ããµããŒãããŠããŸãããæ
å ±ã管çããããã®ãªãã·ã§ã³ã¯ä»ã«ããããŸãã ããšãã°ããµãã¹ã¯ã©ã€ããŒããããã¯ããæ¹æ³ã¯ãããŸããã
ããã¯ããŠãŒã¶ãŒãéžæããã ãã§ãªãããããã¯ãããŠãŒã¶ãŒã®æçš¿ãé€å€ããå¿
èŠãããããããªã¯ãšã¹ãã«å¥ã®è€éããè¿œå ããããšã§ãããããå®è£
ããæ¹æ³ã¯ïŒç°¡åãªæ¹æ³ã¯ã誰ãããããã¯ããŠãã人ãèšé²ããããã®å€å¯Ÿå€ã®é¢ä¿ãæã€å¥ã®èªå·±åç
§ããŒãã«ãšã远跡ãããæçš¿ãè¿ãã¯ãšãªã®å¥ã®çµå+ãã£ã«ã¿ã§ãããœãŒã·ã£ã«ãããã¯ãŒã¯ã®ãã1ã€ã®äžè¬çãªæ©èœã¯ããµãã¹ã¯ã©ã€ããŒããªã¹ãã«ã°ã«ãŒãåããæ©èœã§ããããã«ãããåŸã§åã°ã«ãŒããšæ
å ±ãå
±æã§ããŸãããŸããè¿œå ã®æ¥ç¶ãå¿
èŠã«ãªããã¯ãšãªãè€éã«ãªããŸãããã€ã¯ãããã°ã«ã¯ãããã®æ©èœã¯ãããŸãããããããååãªé¢å¿ãåŒãèµ·ããå Žåã¯ããã®ãããã¯ã«é¢ããèšäºãæžããŠããã ããã°å¹žãã§ããã³ã¡ã³ãã§æããŠãã ããïŒç©äºãæŽçãã
ä»æ¥ã¯éåžžã«é²æ©ããŠããŸããããããããŒã¿ããŒã¹ãšã¯ãšãªã®èšå®ã«é¢ããåé¡ã¯è§£æ±ºããŸããããã¢ããªã±ãŒã·ã§ã³ã«æ°ããæ©èœãå«ããããšã¯ããŸããã§ããã幞ããªããšã«ãããã«ã¯åé¡ã¯ãããŸãããå¿
èŠã«å¿ããŠããã¬ãŒã³ããŒã·ã§ã³ã¢ãã«ãšãã³ãã¬ãŒããä¿®æ£ããŠããŠãŒã¶ãŒã¢ãã«ã®æ°ããã¡ãœãããåŒã³åºãã ãã§ãããã£ãŠã¿ãŸããããç§ãã¡ã¯èªåèªèº«ãå å
¥è
ã«ããŸãããã£ãŒãã§èªåã®æçš¿ãèŠãããšãã§ããããã«ãèªåèªèº«ã«ç»é²ããŠãããã¹ãŠã®ãŠãŒã¶ãŒãããŒã¯ããããšã«ããŸãããOpenIDã®after_loginãã³ãã©ãŒïŒãã¡ã€ã« 'app / views.py'ïŒã®æåã®ã¢ã«ãŠã³ãèšå®ããŠãŒã¶ãŒã«å²ãåœãŠãããæç¹ã§ãããè¡ããŸãã @oid.after_login def after_login(resp): if resp.email is None or resp.email == "": flash('Invalid login. Please try again.') return redirect(url_for('login')) user = User.query.filter_by(email = resp.email).first() if user is None: nickname = resp.nickname if nickname is None or nickname == "": nickname = resp.email.split('@')[0] nickname = User.make_unique_nickname(nickname) user = User(nickname = nickname, email = resp.email, role = ROLE_USER) db.session.add(user) db.session.commit() # make the user follow him/herself db.session.add(user.follow(user)) db.session.commit() remember_me = False if 'remember_me' in session: remember_me = session['remember_me'] session.pop('remember_me', None) login_user(user, remember = remember_me) return redirect(request.args.get('next') or url_for('index'))
ãªã³ã¯ã®è³Œèªãšè³Œèªè§£é€
次ã«ããµãã¹ã¯ãªãã·ã§ã³ããã³ãµãã¹ã¯ãªãã·ã§ã³è§£é€ãã¬ãŒã³ããŒã·ã§ã³æ©èœïŒapp / views.pyãã¡ã€ã«ïŒãå®çŸ©ããŸãã @app.route('/follow/<nickname>') @login_required def follow(nickname): user = User.query.filter_by(nickname = nickname).first() if user == None: flash('User ' + nickname + ' not found.') return redirect(url_for('index')) if user == g.user: flash('You can\'t follow yourself!') return redirect(url_for('user', nickname = nickname)) u = g.user.follow(user) if u is None: flash('Cannot follow ' + nickname + '.') return redirect(url_for('user', nickname = nickname)) db.session.add(u) db.session.commit() flash('You are now following ' + nickname + '!') return redirect(url_for('user', nickname = nickname)) @app.route('/unfollow/<nickname>') @login_required def unfollow(nickname): user = User.query.filter_by(nickname = nickname).first() if user == None: flash('User ' + nickname + ' not found.') return redirect(url_for('index')) if user == g.user: flash('You can\'t unfollow yourself!') return redirect(url_for('user', nickname = nickname)) u = g.user.unfollow(user) if u is None: flash('Cannot unfollow ' + nickname + '.') return redirect(url_for('user', nickname = nickname)) db.session.add(u) db.session.commit() flash('You have stopped following ' + nickname + '.') return redirect(url_for('user', nickname = nickname))
ããã¯ç解ã§ããã¯ãã§ããããšã©ãŒãé²ããåé¡ããŸã çºçãããšãã«ãŠãŒã¶ãŒã«ã¡ãã»ãŒãžãæäŸããããšãããã§ãã¯ã«æ³šæãæã䟡å€ããããŸããããã§ãã¬ãŒã³ããŒã·ã§ã³æ©èœãã§ããã®ã§ãããããæ¥ç¶ã§ããŸãããµãã¹ã¯ã©ã€ããŸãã¯ãµãã¹ã¯ã©ã€ã解é€ãžã®ãªã³ã¯ã¯ãåãŠãŒã¶ãŒã®ãããã¡ã€ã«ããŒãžã§å©çšã§ããŸãïŒãã¡ã€ã«ã¢ããª/ãã³ãã¬ãŒã/ user.htmlïŒïŒ <!-- extend base layout --> {% extends "base.html" %} {% block content %} <table> <tr valign="top"> <td><img src=""></td> <td> <h1>User: {{user.nickname}}</h1> {% if user.about_me %}<p>{{user.about_me}}</p>{% endif %} {% if user.last_seen %}<p><i>Last seen on: {{user.last_seen}}</i></p>{% endif %} <p>{{user.followers.count()}} followers | {% if user.id == g.user.id %} <a href="{{url_for('edit')}}">Edit your profile</a> {% elif not g.user.is_following(user) %} <a href="{{url_for('follow', nickname = user.nickname)}}">Follow</a> {% else %} <a href="{{url_for('unfollow', nickname = user.nickname)}}">Unfollow</a> {% endif %} </p> </td> </tr> </table> <hr> {% for post in posts %} {% include 'post.html' %} {% endfor %} {% endblock %}
ãç·šéããªã³ã¯ããã£ãè¡ã«ã¯ããŠãŒã¶ãŒãæã£ãŠãããµãã¹ã¯ã©ã€ããŒã®æ°ãšã次ã®3ã€ã®ãªã³ã¯ã®ããããã衚瀺ãããŸãã- ãããã¡ã€ã«ããã°ã€ã³ããŠãããŠãŒã¶ãŒã«å±ããŠããå Žåããç·šéããã¿ã³ã衚瀺ãããŸã
- ãã以å€ã®å ŽåããŠãŒã¶ãŒããµãã¹ã¯ã©ã€ããã«ãµãã¹ã¯ã©ã€ãããŠããªãå Žå
- ãã以å€ã®å Žåã¯è³Œèªè§£é€ãªã³ã¯
ããã§ãã¢ããªã±ãŒã·ã§ã³ãèµ·åããããŸããŸãªOpenIDã¢ã«ãŠã³ããããã°ã€ã³ããŠè€æ°ã®ãŠãŒã¶ãŒãäœæããæ°ããæ©èœãè©Šãããšãã§ããŸããæ®ã£ãŠããã®ã¯ã远跡ããããŠãŒã¶ãŒã®æçš¿ãã¡ã€ã³ããŒãžã«è¡šç€ºããããšã ãã§ãããããºã«ã®éèŠãªéšåã¯ãŸã ãªãã®ã§ã次ã®ç« ãŸã§åŸ
ã€å¿
èŠããããŸããæåŸã®èšè
ä»æ¥ãã¢ããªã±ãŒã·ã§ã³ã®å€§éšåãå®è£
ããŸãããããŒã¿ããŒã¹æ¥ç¶ãšã¯ãšãªã®ãããã¯ã¯éåžžã«è€éãªã®ã§ã質åãããå Žåã¯ã以äžã®ã³ã¡ã³ãã§è³ªåãéä¿¡ã§ããŸãã次ã®èšäºã§ã¯ãããŒãžçªå·ä»ãã®çŽ æŽãããäžçãèŠãŠãæçµçã«ããŒã¿ããŒã¹ããæçš¿ãåãåããŸããïŒç§ãã¡ã®ãã€ã¯ãããã°ã®æŽæ°ãœãŒã¹ãžã®ãªã³ã¯ã®äžã®æ æ°kopipasterçšã®ããŠã³ããŒãmicroblog-0.8.zipããã€ãã®ããã«ãã¢ãŒã«ã€ãã«ã¯ãã©ã¹ã³ããŒã¿ããŒã¹ãä»®æ³ç°å¢ã¯å«ãŸããŠããŸããã以åã®èšäºã§ã¯ããããã®å±éæ¹æ³ã«ã€ããŠèª¬æããŸããããã¥ãŒããªã¢ã«ãèªãã§ãããŠããããšãããŸããïŒãã²ã«