美文网首页
基本框架(MVC)(19)

基本框架(MVC)(19)

作者: 马梦里 | 来源:发表于2018-01-01 18:26 被阅读0次

    MVC:

    • models:数据模型,和框架基本独立;
    • v:视图模板,templates
    • ccontroller,路由 + 视图函数

    web框架的核心是定义路由和处理数据(获取数据(POST / GET / JSON / 普通字典)和返回数据)

    jinja2:客户端渲染发生在服务端(html
    ajax:客户端渲染发生在客户端,拼接好了再发出请求;

    模板:
    https://istorm.cc/topic
    https://cnodejs.org/

    models

    论坛的数据结构:UserTopicReply

    Topic 用来定义文章:

    import time
    from models import Model
    from models.user import User
    from models.reply import Reply
    
    1. 同一个文件夹内模块的引用
      直接:from filename import xxx
      或者:from dirname.filename import xxx
      为了避免造成交叉引用(两个文件之间的相互引用:user - from models.topic import Topic / topic - from models.user import User),其中一个文件的引用格式应为:
      import dirname(models)
      使用方式为:
      models.user.User...
    class Topic(Model):
        @classmethod
        def get(cls, id):
            m = cls.find_by(id=id)
            m.views += 1
            m.save()
            return m
    
    1. 文章( topic )的浏览次数:
      每次调用 Topic 函数的 get()方法,属性值 views 就会增加一次;
      1. 通过参数 id 拿到具体的文章;
      2. 调用文章的 views 属性,自增一次
      3. 调用 Topicsave() 方法,保存这次更改 :
        基类的 Models.save() 函数:
        1. 通过 self.all() 方法,可以拿到所有的文章实例 models
        2. 对当前 id 值进行判断:
        - 如果 idNone ,则表示这是一条新数据,再通过判断 models 的长度,判断当前实例的有无,如果没有,则表示这将是第一条数据,那么 id 赋值为 1 ;如果有,将最后一个实例的 id 加 1,就是该文章的 id,最后将该实例增加进数据库;
        - 如果 id 不为 None,则表明数据库中已经存在这条数据,那么遍历实例获得相等的 id,更新数据即可;
      4. 最后将数据保存进数据库;
      def save(self):
          models = self.all()
          if self.id is None:
              if len(models) == 0:
                  self.id = 1
              else:
                  m = models[-1]
                  self.id = m.id + 1
              models.append(self)
          else:
              index = -1
              for i, m in enumerate(models):
                  if m.id == self.id:
                      index = i
                      break
              models[index] = self
          l = [m.__dict__ for m in models]
          path = self.db_path()
          save(l, path)
      
        def __init__(self, form):
            self.id = None
            self.views = 0
            self.title = form.get('title', '')
            self.content = form.get('content', '')
            self.ct = int(time.time())
            self.ut = self.ct
            self.user_id = form.get('user_id', '')
    
        def user(self):
            u = User.find(self.user_id)
            return u
    
        def replies(self):
            ms = Reply.find_all(topic_id=self.id)
            return ms
    
        def reply_count(self):
            count = len(self.replies())
            return count
    

    上述方法分别对应:

    • 属性:id、views、title、content、created_time、updated_time、user_id
    • 通过 user() 方法获得该文章的 user
    • replies()可以获得该篇文章下的所有评论;
      这相当于是一个外键连接(一对多),在类 Reply 里有属性 topic_id,等同于类 Topic 里的属性 user_id;通过 id 参数进行连接,可以拿到相同 id 的所有数据;
    • reply_count() 方法获得评论数;

    User

    from models import Model
    
    # 这样是为了避免交叉引用,因为在 topic 里面引用了 User:from models.user import User
    import models
    
    class User(Model):
        def __init__(self, form):
            self.id = form.get('id', None)
            self.username = form.get('username', '')
            self.password = form.get('password', '')
    ...
    
        # 用 类方法,不用实例化,可以直接调用
        @classmethod
        def topics(cls, id):
            topics = models.topic.Topic.find_all(user_id=id)
            return sorted(topics, key= lambda topic: topic.ct, reverse=True)
    
        @classmethod
        def replied_topics(cls, id):
            replies = models.reply.Reply.find_all(user_id=id)
            topic_ids = []
            replied_topics = []
            for reply in replies:
                topic_id = reply.topic_id
                topic_ids.append(topic_id)
            # 避免同一话题下多次回复,陈列多次相同主体
            for id in set(topic_ids):
                topic = models.topic.Topic.find(id=id)
                replied_topics.append(topic)
            return sorted(replied_topics, key= lambda topic: topic.ct, reverse=True)
    

    给类 User 增加两个类方法:

    • topic():获取 user 发表的文章
    • replied_topics():获取 user 评论过的文章
      1. 先获取该 id user 的所有评论,并拿到所有评论的 topic_id;
      2. 通过遍历 id 获得所有文章的列表
    • 两个知识点:
      1. 因为一个人可能在一篇文章下有多条评论,故通过 set() 方法去掉重复的 topic_id;

      2. 对恢复的文章列表按照时间进行逆向排序
        sorted()方法:
        第一个参数为列表,第二个参数为排序的参照属性,第三个参数为逆向排序;

    Reply

    class Reply(Model):
        def __init__(self, form):
            self.id = None
            self.content = form.get('content', '')
            self.ct = int(time.time())
            self.ut = self.ct
            self.topic_id = int(form.get('topic_id', -1))
            self.user_id = int(form.get('user_id', -1))
    
        def user(self):
            u = User.find(self.user_id)
            return u
    

    属性:id、content、ct、ut
    topic_id:一对多的关系,文章下的评论
    user_id:一对多的关系,用户的评论

    visual

    1. {% set u = topic.user() %}
      jinja2set 语法,相当于赋值于一个名称短的变量,方便书写。
    2. {{ topic.replies() | count }}
    3. {{ loop.index }}楼 / {{ loop.length }}楼
      loop 是 jinja2 的语法,在循环语句 {% for ... %} 内部使用:
      loop.index     :表示迭代到当前的索引,从1开始计算
      loop.index0    :迭代到当前的索引,从0开始计算
      loop.revindex  :相对于序列末尾的索引,从1开始计算
      loop.revindex0 :相对于序列末尾的索引,从0开始计算
      loop.first     :bool值,序列的第一个为True,其他为False
      loop.last      :和 loop.first 相反
      loop.length    :序列总长度
      
    4. 不同 css js 的功能还有待弄清楚

    control

    1. url 中传递数据
    • html中:
      href="{{ url_for('topic.detail', id=t.id) }}"
      url_for() 还是 flask 语法,传递的参数直接写在第二个参数的位置,有几个可以写几个,id 必须与 url 中的变量对应;

    • control

      @main.route('/<int:id>')
      def detail(id):
          m = Topic.get(id)
          return render_template("topic/detail.html", topic=m)
      
    • url 中的 变量 id 必须在视图函数的参数中,这样可以对操作数据;

    • 变量必须包裹在 < > 中,int 对变量进行额外操作,转换为整型;

    • 使用 Topic.get(id) 而不使用 Topic.find_by(id)
      每次查看文章,都会调用相应的视图函数 detail(id),每次调用 detail(id) 函数时,都会调用 Topic()get() 方法,每次调用 get() 方法,都会让该 topicviews 属性自增 1;所以需要将 find_by() 方法与 views+ 耦合起来。

    相关文章

      网友评论

          本文标题:基本框架(MVC)(19)

          本文链接:https://www.haomeiwen.com/subject/tigtnxtx.html