Ejemplo n.º 1
0
 def test_union(self):
     field = validators.Union([validators.String()])
     assert field.errors["union"] == '必须是{items}类型之一'
Ejemplo n.º 2
0
 class Example(Type):
     field = validators.Union(
         [validators.String(),
          validators.Integer()])
Ejemplo n.º 3
0
 def test_string(self):
     field = validators.String()
     assert len(field.errors) >= 9
Ejemplo n.º 4
0
 class Example(Type):
     a = validators.String()
Ejemplo n.º 5
0
 def test_Union(self):
     field = validators.Union([validators.String()])
     assert len(field.errors) >= 2
Ejemplo n.º 6
0
 def test_string(self):
     field = validators.String()
     assert field.errors["exact"] == '只能是{exact}'
Ejemplo n.º 7
0
class Article(PersistentType, SqliteDriverMixin):
    """
    文章模型
    :param title: 标题
    :ex `我的主页`
    :param id: 每篇文章的唯一id,日期字符串的形式表示
    :param tags: 关键字
    :ex tags:
    `["python", "apistellar"]`
    :param description: 描述信息
    :param author: 作者信息
    :param feature: 是否为精品
    :ex feature: True/False
    :param updated_at: 更新时间
    :param created_at: 创建时间
    :param show: 是否在文章列表中展示
    :ex show: True/False
    :param article: 文章正文
    """
    TABLE = "articles"

    title = validators.String()
    id = validators.String(default=lambda: datetime.datetime.now(
        pytz.timezone(settings["TIME_ZONE"])).strftime("%Y%m%d%H%M%S"))
    tags = Tags()
    description = validators.String(default="")
    author = validators.String(default=settings.get("AUTHOR"))
    feature = validators.Boolean(default=False)
    created_at = Timestamp(default=lambda: datetime.datetime.now().timestamp())
    updated_at = Timestamp(default=lambda: datetime.datetime.now().timestamp())
    show = validators.Boolean(default=True)
    article = validators.String(default=str)

    @classmethod
    def right_code(cls, code, code_gen=None):
        """
        code是否正确
        :param code:
        :param code_gen:
        :return:
        """
        if code_gen is None:
            code_gen = code_generator(settings.get_int("CODE_EXPIRE_INTERVAL"))

        if settings.get_bool("NEED_CODE"):
            return next(code_gen) == code
        else:
            return True

    @classmethod
    async def load(cls, **kwargs):
        """
        查找一篇文章
        :param kwargs:
        :return:
        """
        vals, sql = cls._build_select_sql(kwargs)
        cls.store.execute(sql, vals)
        data = cls.store.fetchone()

        if data:
            return cls(
                dict(zip((col[0] for col in cls.store.description), data)))
        else:
            return Article()

    @classmethod
    async def load_list(cls,
                        _from=None,
                        size=None,
                        sub=None,
                        vals=None,
                        projection=None,
                        **kwargs):
        """
        查询文章列表
        :param _from:
        :param size:
        :param sub:
        :param vals:
        :param kwargs:
        :param projection:
        :return:
        """
        vals, sql = cls._build_select_sql(kwargs, _from, size, projection,
                                          [("updated_at", "desc")], sub, vals)
        cls.store.execute(sql, vals)
        data_list = cls.store.fetchall()
        desc = [col[0] for col in cls.store.description]
        return [Article(dict(zip(desc, data))) for data in data_list]

    @classmethod
    async def get_total_tags(cls):
        """
        获取全部文章数量及每个tag的数量
        :return:
        """
        count = 0
        group_tags = defaultdict(int)
        for article in await cls.load_list(projection=["tags"], show=True):
            for tag in article.tags.split(","):
                group_tags[tag] += 1
            count += 1
        return count, group_tags

    async def save(self):
        """
        保存文章
        :return:
        """
        self.format(allow_coerce=True)
        self.store.execute(
            f"INSERT INTO {self.TABLE} VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?);",
            (
                self.id,
                self.description,
                # 通过下标获取,可以调用其formatter的to_string方法返回
                self["tags"],
                self.article,
                self.author,
                self.title,
                self.feature,
                self.created_at,
                self.updated_at,
                self.show))

    async def remove(self):
        """
        删除文章
        :return:
        """
        self.store.execute(f"DELETE FROM {self.TABLE} WHERE show=1 and id=?;",
                           (self.id, ))

    async def update(self):
        """
        更新文章
        :return:
        """
        self.store.execute(*self._build_update_sql(self))

    @classmethod
    def _build_update_sql(cls, article):
        sql = f"UPDATE {cls.TABLE} SET "
        args = list()

        for name in article:
            # 在调用update之前使用了format,目前format会创建字符串时间
            # 无法使用,在这里进行一次排除
            if name not in ("id", "updated_at", "created_at", "show"):
                article.reformat(name, allow_coerce=True)
                sql += f"{name}=?, "
                args.append(article[name])

        sql += f"updated_at=? WHERE id=?;"
        args.append(int(datetime.datetime.now().timestamp()))
        args.append(article.id)
        return sql, args

    @classmethod
    @conn_ignore
    async def search(cls, search_field, _from, size, fulltext=False, **kwargs):
        """
        搜索文章
        :param search_field:
        :param _from:
        :param size:
        :param fulltext:
        :param kwargs:
        :return:
        """
        sub, vals = cls._fuzzy_search_sub_sql(search_field, fulltext)
        return await cls.load_list(_from=_from,
                                   size=size,
                                   sub=sub,
                                   vals=vals,
                                   **kwargs)

    @staticmethod
    def _fuzzy_search_sub_sql(search_field, fulltext):
        """
        获取模糊搜索where子句
        :param search_field: 搜索词
        :param fulltext: 是否是全文搜索,如果是的话,则从article和tags中搜索
        :return:
        """
        sub, vals = None, None
        if search_field:
            vals = list()
            if fulltext:
                sub = f" AND (article LIKE ? OR tags LIKE ?)"
                vals.append(f"%{search_field}%")
            else:
                sub = " AND tags LIKE ?"
            vals.append(f"%{search_field}%")
        return sub, vals

    @classmethod
    def _build_select_sql(cls,
                          kwargs: dict = None,
                          _from: int = None,
                          size: int = None,
                          projection: list = None,
                          order_fields: typing.List[typing.Tuple[str,
                                                                 str]] = None,
                          sub: str = None,
                          vals: list = None):
        """
        创建查询sql
        :param kwargs: 查询参数
        :param _from: 从哪一个开始查
        :param size: 查几个
        :param projection: 需要查哪
        :param order_fields: 按哪个字段排序
        :ex order_fields: `[("id", "desc)..]`
        :param sub: where子句
        :param vals: 占位符实参
        :return:
        """
        if vals is None:
            vals = list()

        if sub is None:
            sub = ""

        for k, v in (kwargs or dict()).items():
            if isinstance(v, (MutableSequence, MutableSet, tuple)):
                sub += f' AND {k} IN ({", ".join(repeat("?", len(v)))})'
                vals.extend(v)
            else:
                sub += " AND {}=?".format(k)
                vals.append(v)

        if order_fields:
            sub += f" order by {''.join(f + ' ' + o for f, o in order_fields)}"

        if size is not None:
            assert _from is not None, "Both of size and _from cannot be None!"
            sub += f" limit {size} offset {_from}"

        if projection:
            fields = ", ".join(projection)
        else:
            fields = "*"
        return vals, f"SELECT {fields} FROM {cls.TABLE} WHERE 1=1{sub};"
Ejemplo n.º 8
0
class A(Type):
    a = validators.String()
Ejemplo n.º 9
0
 class Union(Type):
     field = (validators.Array(validators.String()) | validators.String()) \
             << {"allow_null": True}
Ejemplo n.º 10
0
class ModelTest(Type):
    a = validators.String()
    b = validators.Integer()
    c = validators.String(default="test")
Ejemplo n.º 11
0
 class Union(Type):
     field = (validators.Array(validators.String()) | validators.String()) \
             << {"default": list}
Ejemplo n.º 12
0
class Article(PersistentType, SqliteDriverMixin):
    TABLE = "articles"

    title = validators.String()
    id = validators.String(default=get_id)
    tags = Tags()
    description = validators.String()
    author = validators.String()
    feature = Boolean(default=False)
    created_at = Timestamp(default=datetime.datetime.now().timestamp)
    updated_at = Timestamp(default=datetime.datetime.now().timestamp)
    show = Boolean(default=True)
    article = validators.String(default=str)

    async def load(self, **kwargs):
        if not kwargs:
            kwargs["id"] = self.id
        sub, args = self.build_sub_sql(kwargs)
        self.store.execute(f"SELECT * FROM {self.TABLE} WHERE 1=1 {sub}", args)
        data = self.store.fetchone()

        if data:
            new = Article(dict(zip(
                (col[0] for col in self.store.description), data)))
        else:
            new = Article()
        super(Article, self).update(**new)
        return new

    @classmethod
    async def load_list(cls, ids, projection=None,
                        _from=None, size=None, sub="",
                        args=None, **kwargs):
        sub, args = cls.build_sub_sql(kwargs, sub, args)
        if ids:
            sub += 'and id in ({})'.format(", ".join(repeat("?", len(ids))))
            args.extend(ids)
        sub += " order by updated_at desc"
        if size:
            sub += f" limit {size} offset {_from}"
        sub += ";"
        if projection:
            fields = ", ".join(projection)
        else:
            fields = "*"
        sql = f"SELECT {fields} FROM {cls.TABLE} WHERE 1=1 {sub}"
        cls.store.execute(sql, args)
        data_list = cls.store.fetchall()
        return [Article(dict(zip(
            (col[0] for col in cls.store.description), data)))
            for data in data_list]

    @staticmethod
    def build_sub_sql(kwargs, sub="", args=None):
        if args is None:
            args = list()
        for k, v in kwargs.items():
            sub += "and {}=?".format(k)
            args.append(v)
        return sub, args

    async def save(self):
        self.format()
        self.store.execute(
            f"INSERT INTO {self.TABLE} "
            f"VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?);", (
            self.id,
            self.description,
            # 通过下标获取,可以调用其formatter的to_string方法返回
            self["tags"],
            self.article,
            self.author,
            self.title,
            self.feature,
            self.created_at,
            self.updated_at,
            self.show))

    async def remove(self):
        self.store.execute(
            f"DELETE FROM {self.TABLE} WHERE show=1 and id=?;", (self.id, ))

    async def update(self):
        sql = f"UPDATE {self.TABLE} SET "
        args = []
        for name, value in self.items():
            if name != "id":
                sql += f"{name}=?, "
                args.append(value)

        sql += f"updated_at=? WHERE id=?;"
        args.append(int(datetime.datetime.now().timestamp()))
        args.append(self.id)

        self.store.execute(sql, args)

    @classmethod
    @conn_ignore
    async def search(cls, search_field, _from, size, fulltext=False, **kwargs):
        sub, args = "", []
        if fulltext:
            if search_field:
                sub = f"AND (article LIKE ? OR tags LIKE ?)"
                args.append(f"%{search_field}%")
                args.append(f"%{search_field}%")
        else:
            if search_field:
                sub = "AND tags LIKE ?"
                args.append(f"%{search_field}%")

        return await cls.load_list(None, None, _from, size, sub, args, **kwargs)
Ejemplo n.º 13
0
class Student(Type):
    name = validators.String()
    subject = validators.Proxy(Subject, allow_null=True)
Ejemplo n.º 14
0
class Subject(Type):
    id = validators.String(allow_null=True)
Ejemplo n.º 15
0
class Teacher(Type):
    name = validators.String()
    subject = validators.Proxy(Subject, default=dict)