├── .gitignore ├── Makefile ├── conf.py ├── index.rst ├── make.bat └── readme.rst /.gitignore: -------------------------------------------------------------------------------- 1 | _build/ 2 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # Internal variables. 11 | PAPEROPT_a4 = -D latex_paper_size=a4 12 | PAPEROPT_letter = -D latex_paper_size=letter 13 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 14 | # the i18n builder cannot share the environment and doctrees with the others 15 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 16 | 17 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext 18 | 19 | help: 20 | @echo "Please use \`make ' where is one of" 21 | @echo " html to make standalone HTML files" 22 | @echo " dirhtml to make HTML files named index.html in directories" 23 | @echo " singlehtml to make a single large HTML file" 24 | @echo " pickle to make pickle files" 25 | @echo " json to make JSON files" 26 | @echo " htmlhelp to make HTML files and a HTML help project" 27 | @echo " qthelp to make HTML files and a qthelp project" 28 | @echo " devhelp to make HTML files and a Devhelp project" 29 | @echo " epub to make an epub" 30 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 31 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 32 | @echo " text to make text files" 33 | @echo " man to make manual pages" 34 | @echo " texinfo to make Texinfo files" 35 | @echo " info to make Texinfo files and run them through makeinfo" 36 | @echo " gettext to make PO message catalogs" 37 | @echo " changes to make an overview of all changed/added/deprecated items" 38 | @echo " linkcheck to check all external links for integrity" 39 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 40 | 41 | clean: 42 | -rm -rf $(BUILDDIR)/* 43 | 44 | html: 45 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 46 | @echo 47 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 48 | 49 | dirhtml: 50 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 51 | @echo 52 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 53 | 54 | singlehtml: 55 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 56 | @echo 57 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 58 | 59 | pickle: 60 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 61 | @echo 62 | @echo "Build finished; now you can process the pickle files." 63 | 64 | json: 65 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 66 | @echo 67 | @echo "Build finished; now you can process the JSON files." 68 | 69 | htmlhelp: 70 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 71 | @echo 72 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 73 | ".hhp project file in $(BUILDDIR)/htmlhelp." 74 | 75 | qthelp: 76 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 77 | @echo 78 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 79 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 80 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/StormORM.qhcp" 81 | @echo "To view the help file:" 82 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/StormORM.qhc" 83 | 84 | devhelp: 85 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 86 | @echo 87 | @echo "Build finished." 88 | @echo "To view the help file:" 89 | @echo "# mkdir -p $$HOME/.local/share/devhelp/StormORM" 90 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/StormORM" 91 | @echo "# devhelp" 92 | 93 | epub: 94 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 95 | @echo 96 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 97 | 98 | latex: 99 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 100 | @echo 101 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 102 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 103 | "(use \`make latexpdf' here to do that automatically)." 104 | 105 | latexpdf: 106 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 107 | @echo "Running LaTeX files through pdflatex..." 108 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 109 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 110 | 111 | text: 112 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 113 | @echo 114 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 115 | 116 | man: 117 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 118 | @echo 119 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 120 | 121 | texinfo: 122 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 123 | @echo 124 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 125 | @echo "Run \`make' in that directory to run these through makeinfo" \ 126 | "(use \`make info' here to do that automatically)." 127 | 128 | info: 129 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 130 | @echo "Running Texinfo files through makeinfo..." 131 | make -C $(BUILDDIR)/texinfo info 132 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 133 | 134 | gettext: 135 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 136 | @echo 137 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 138 | 139 | changes: 140 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 141 | @echo 142 | @echo "The overview file is in $(BUILDDIR)/changes." 143 | 144 | linkcheck: 145 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 146 | @echo 147 | @echo "Link check complete; look for any errors in the above output " \ 148 | "or in $(BUILDDIR)/linkcheck/output.txt." 149 | 150 | doctest: 151 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 152 | @echo "Testing of doctests in the sources finished, look at the " \ 153 | "results in $(BUILDDIR)/doctest/output.txt." 154 | -------------------------------------------------------------------------------- /conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Storm ORM 中文教程 documentation build configuration file, created by 4 | # sphinx-quickstart on Fri May 25 15:16:39 2012. 5 | # 6 | # This file is execfile()d with the current directory set to its containing dir. 7 | # 8 | # Note that not all possible configuration values are present in this 9 | # autogenerated file. 10 | # 11 | # All configuration values have a default; values that are commented out 12 | # serve to show the default. 13 | 14 | import sys, os 15 | 16 | # If extensions (or modules to document with autodoc) are in another directory, 17 | # add these directories to sys.path here. If the directory is relative to the 18 | # documentation root, use os.path.abspath to make it absolute, like shown here. 19 | #sys.path.insert(0, os.path.abspath('.')) 20 | 21 | # -- General configuration ----------------------------------------------------- 22 | 23 | # If your documentation needs a minimal Sphinx version, state it here. 24 | #needs_sphinx = '1.0' 25 | 26 | # Add any Sphinx extension module names here, as strings. They can be extensions 27 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 28 | extensions = [] 29 | 30 | # Add any paths that contain templates here, relative to this directory. 31 | templates_path = ['_templates'] 32 | 33 | # The suffix of source filenames. 34 | source_suffix = '.rst' 35 | 36 | # The encoding of source files. 37 | #source_encoding = 'utf-8-sig' 38 | 39 | # The master toctree document. 40 | master_doc = 'index' 41 | 42 | # General information about the project. 43 | project = u'Storm Tutorial 中文版' 44 | copyright = u'2012, storm.canonical.com & huangz1990' 45 | 46 | # The version info for the project you're documenting, acts as replacement for 47 | # |version| and |release|, also used in various other places throughout the 48 | # built documents. 49 | # 50 | # The short X.Y version. 51 | version = '1.0' 52 | # The full version, including alpha/beta/rc tags. 53 | release = '1.0' 54 | 55 | # The language for content autogenerated by Sphinx. Refer to documentation 56 | # for a list of supported languages. 57 | #language = None 58 | 59 | # There are two options for replacing |today|: either, you set today to some 60 | # non-false value, then it is used: 61 | #today = '' 62 | # Else, today_fmt is used as the format for a strftime call. 63 | #today_fmt = '%B %d, %Y' 64 | 65 | # List of patterns, relative to source directory, that match files and 66 | # directories to ignore when looking for source files. 67 | exclude_patterns = ['_build'] 68 | 69 | # The reST default role (used for this markup: `text`) to use for all documents. 70 | #default_role = None 71 | 72 | # If true, '()' will be appended to :func: etc. cross-reference text. 73 | #add_function_parentheses = True 74 | 75 | # If true, the current module name will be prepended to all description 76 | # unit titles (such as .. function::). 77 | #add_module_names = True 78 | 79 | # If true, sectionauthor and moduleauthor directives will be shown in the 80 | # output. They are ignored by default. 81 | #show_authors = False 82 | 83 | # The name of the Pygments (syntax highlighting) style to use. 84 | pygments_style = 'sphinx' 85 | 86 | # A list of ignored prefixes for module index sorting. 87 | #modindex_common_prefix = [] 88 | 89 | 90 | # -- Options for HTML output --------------------------------------------------- 91 | 92 | # The theme to use for HTML and HTML Help pages. See the documentation for 93 | # a list of builtin themes. 94 | html_theme = 'nature' 95 | 96 | # Theme options are theme-specific and customize the look and feel of a theme 97 | # further. For a list of options available for each theme, see the 98 | # documentation. 99 | #html_theme_options = {} 100 | 101 | # Add any paths that contain custom themes here, relative to this directory. 102 | #html_theme_path = [] 103 | 104 | # The name for this set of Sphinx documents. If None, it defaults to 105 | # " v documentation". 106 | html_title = u'Storm Tutorial 中文版' 107 | 108 | # A shorter title for the navigation bar. Default is the same as html_title. 109 | #html_short_title = None 110 | 111 | # The name of an image file (relative to this directory) to place at the top 112 | # of the sidebar. 113 | #html_logo = None 114 | 115 | # The name of an image file (within the static path) to use as favicon of the 116 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 117 | # pixels large. 118 | #html_favicon = None 119 | 120 | # Add any paths that contain custom static files (such as style sheets) here, 121 | # relative to this directory. They are copied after the builtin static files, 122 | # so a file named "default.css" will overwrite the builtin "default.css". 123 | html_static_path = ['_static'] 124 | 125 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 126 | # using the given strftime format. 127 | #html_last_updated_fmt = '%b %d, %Y' 128 | 129 | # If true, SmartyPants will be used to convert quotes and dashes to 130 | # typographically correct entities. 131 | #html_use_smartypants = True 132 | 133 | # Custom sidebar templates, maps document names to template names. 134 | #html_sidebars = {} 135 | 136 | # Additional templates that should be rendered to pages, maps page names to 137 | # template names. 138 | #html_additional_pages = {} 139 | 140 | # If false, no module index is generated. 141 | #html_domain_indices = True 142 | 143 | # If false, no index is generated. 144 | #html_use_index = True 145 | 146 | # If true, the index is split into individual pages for each letter. 147 | #html_split_index = False 148 | 149 | # If true, links to the reST sources are added to the pages. 150 | #html_show_sourcelink = True 151 | 152 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 153 | #html_show_sphinx = True 154 | 155 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 156 | #html_show_copyright = True 157 | 158 | # If true, an OpenSearch description file will be output, and all pages will 159 | # contain a tag referring to it. The value of this option must be the 160 | # base URL from which the finished HTML is served. 161 | #html_use_opensearch = '' 162 | 163 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 164 | #html_file_suffix = None 165 | 166 | # Output file base name for HTML help builder. 167 | htmlhelp_basename = 'StormORMdoc' 168 | 169 | 170 | # -- Options for LaTeX output -------------------------------------------------- 171 | 172 | latex_elements = { 173 | # The paper size ('letterpaper' or 'a4paper'). 174 | #'papersize': 'letterpaper', 175 | 176 | # The font size ('10pt', '11pt' or '12pt'). 177 | #'pointsize': '10pt', 178 | 179 | # Additional stuff for the LaTeX preamble. 180 | #'preamble': '', 181 | } 182 | 183 | # Grouping the document tree into LaTeX files. List of tuples 184 | # (source start file, target name, title, author, documentclass [howto/manual]). 185 | latex_documents = [ 186 | ('index', 'StormORM.tex', u'Storm ORM 中文教程 Documentation', 187 | u'huangz1990', 'manual'), 188 | ] 189 | 190 | # The name of an image file (relative to this directory) to place at the top of 191 | # the title page. 192 | #latex_logo = None 193 | 194 | # For "manual" documents, if this is true, then toplevel headings are parts, 195 | # not chapters. 196 | #latex_use_parts = False 197 | 198 | # If true, show page references after internal links. 199 | #latex_show_pagerefs = False 200 | 201 | # If true, show URL addresses after external links. 202 | #latex_show_urls = False 203 | 204 | # Documents to append as an appendix to all manuals. 205 | #latex_appendices = [] 206 | 207 | # If false, no module index is generated. 208 | #latex_domain_indices = True 209 | 210 | 211 | # -- Options for manual page output -------------------------------------------- 212 | 213 | # One entry per manual page. List of tuples 214 | # (source start file, name, description, authors, manual section). 215 | man_pages = [ 216 | ('index', 'stormorm', u'Storm ORM 中文教程 Documentation', 217 | [u'huangz1990'], 1) 218 | ] 219 | 220 | # If true, show URL addresses after external links. 221 | #man_show_urls = False 222 | 223 | 224 | # -- Options for Texinfo output ------------------------------------------------ 225 | 226 | # Grouping the document tree into Texinfo files. List of tuples 227 | # (source start file, target name, title, author, 228 | # dir menu entry, description, category) 229 | texinfo_documents = [ 230 | ('index', 'StormORM', u'Storm ORM 中文教程 Documentation', 231 | u'huangz1990', 'StormORM', 'One line description of project.', 232 | 'Miscellaneous'), 233 | ] 234 | 235 | # Documents to append as an appendix to all manuals. 236 | #texinfo_appendices = [] 237 | 238 | # If false, no module index is generated. 239 | #texinfo_domain_indices = True 240 | 241 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 242 | #texinfo_show_urls = 'footnote' 243 | -------------------------------------------------------------------------------- /index.rst: -------------------------------------------------------------------------------- 1 | .. Storm ORM 中文教程 documentation master file, created by 2 | sphinx-quickstart on Fri May 25 15:16:39 2012. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Storm Tutorial 中文版 7 | ========================================== 8 | 9 | `Storm `_ 是一个 Python ORM 库,本文是 `Storm 官方教程 `_\ 的简体中文翻译版。 10 | 11 | 项目 Github 库: `https://github.com/huangz1990/storm_orm_tutorial_cn `_ 。 12 | 13 | 14 | 跑起来再说! 15 | --------------- 16 | 17 | 这份 Storm 教程包含在源代码 ``tests/tutorial.txt`` 当中,因此它会被测试并保持更新。 18 | 19 | Ubuntu 的 Storm 包由 Storm 团队提供: 20 | 21 | :: 22 | 23 | 24 | sudo apt-add-repository ppa:storm/ppa 25 | sudo apt-get update 26 | sudo apt-get install python-storm 27 | 28 | 29 | 载入 30 | ------- 31 | 32 | 让我们从往命名空间(namespace)载入一些名字(names)开始。 33 | 34 | 35 | :: 36 | 37 | >>> from storm.locals import * 38 | >>> 39 | 40 | 41 | 基本定义 42 | ---------- 43 | 44 | 现在,我们定义一种用几项属性来描述信息的类型(type),用它来作映射。 45 | 46 | 47 | >>> class Person(object): 48 | ... __storm_table__ = "person" 49 | ... id = Int(primary=True) 50 | ... name = Unicode() 51 | 52 | 53 | 注意,这个定义没有使用任何 Storm 定义的 ``base`` 类或构造函数。 54 | 55 | 56 | 创建一个数据库以及仓库(store) 57 | -------------------------------- 58 | 59 | 我们还是什么都没讲到,因此,让我们来定义一个储存在内存中的 SQLite 数据库,以及使用该数据库的仓库来玩玩。 60 | 61 | :: 62 | 63 | >>> database = create_database("sqlite:") 64 | >>> store = Store(database) 65 | >>> 66 | 67 | 目前,有三种数据库被支持: SQLite , MySQL 以及 PostgreSQL 。 ``create_database`` 函数接受 URI 作为参数,就像这样: 68 | 69 | :: 70 | 71 | database = create_database("scheme://username:password@hostname:port/database_name") 72 | 73 | 其中的 ``scheme`` 可以是 ``sqlite`` , ``postgres`` ,或 ``mysql`` 。 74 | 75 | 现在我们要创建一个表,将该表用来保存我们类中的数据。 76 | 77 | :: 78 | 79 | >>> store.execute("CREATE TABLE person " 80 | ... "(id INTEGER PRIMARY KEY, name VARCHAR)") 81 | > 82 | 83 | 我们得到了一个结果(result),不过现在不必关心它。通过使用 ``noresult=True`` ,我们也可以省略所有结果。 84 | 85 | 86 | 创建对象 87 | ----------- 88 | 89 | 让我们通过前面定义的类来创建对象。 90 | 91 | 92 | :: 93 | 94 | >>> joe = Person() 95 | >>> joe.name = u"Joe Johnes" 96 | >>> 97 | >>> print "%r, %r" % (joe.id, joe.name) 98 | 5 None, u'Joe Johnes' 99 | 100 | 到目前为止,这个对象都还没有连接到数据库。现在,让我们将它加入到前面创建的仓库当中。 101 | 102 | :: 103 | 104 | >>> store.add(joe) 105 | 106 | 107 | >>> print "%r, %r" % (joe.id, joe.name) 108 | None, u'Joe Johnes' 109 | 110 | 请注意,这个对象并没有任何改变,即便是被加入到仓库之后 —— 这是因为它还没有刷新呢。 111 | 112 | 113 | 对象的仓库 114 | -------------- 115 | 116 | 一旦对象被加入到仓库,或从仓库中被检索,它和仓库的关系就明了了。我们也可以很容易地验证对象绑定到了哪一个仓库。 117 | 118 | :: 119 | 120 | >>> Store.of(joe) is store 121 | True 122 | 123 | >>> Store.of(Person()) is None 124 | True 125 | 126 | 127 | 对象的查找 128 | ------------ 129 | 130 | 现在,如果我们向仓库查询名为 Joe Johnes 的人,会发生什么事? 131 | 132 | :: 133 | 134 | >>> person = store.find(Person, Person.name == u"Joe Johnes").one() 135 | 136 | >>> print "%r, %r" % (person.id, person.name) 137 | 1, u'Joe Johnes' 138 | 139 | Joe Johnes 已经被仓库记录了!是的,就正如你所期待的一样。 140 | 141 | 我们还可以通过主键(primary key)来检索对象。 142 | 143 | :: 144 | 145 | >>> store.get(Person, 1).name 146 | u'Joe Johnes 147 | 148 | 149 | 缓存特性 150 | ----------- 151 | 152 | 有趣的是, ``person`` 变量实际上就是 ``joe`` ,是吧?我们才刚刚添加了一个对象,所以应该只有一个 Joe ,为什么会有两个不同的对象呢?答案是,这两个变量指向的是同一个 Joe : 153 | 154 | :: 155 | 156 | >>> person is joe 157 | True 158 | 159 | 事实上,每个仓库都一个对象缓存(cache)。当一个对象加入到仓库之后,在它被其他地方引用(reference)期间,仓库会尽可能地缓存它,直到该对象被污染(dirty,即有更改未被刷新)。 160 | 161 | Storm 保证至少有一定数目的最近使用对象被保存到内存中用以取代查询,因此频繁使用的对象就不必事无大小都检索数据库了。 162 | 163 | 164 | 刷新 165 | ------- 166 | 167 | 当第一次试图在数据库中查找 Joe 的时候,我们神奇地发现属性 ``id`` 已经被赋值了。这是因为对象已经被隐含地(implicitly)刷新了,也就是说,某些行为也会导致之前的改动操作(changes)生效。 168 | 169 | 刷新也可以强制地(explicitly)发生: 170 | 171 | :: 172 | 173 | >>> mary = Person() 174 | >>> mary.name = u"Mary Margaret" 175 | >>> store.add(mary) 176 | 177 | >>> 178 | >>> print "%r, %r" % (mary.id, mary.name) 179 | None, u'Mary Margaret' 180 | >>> 181 | >>> store.flush() 182 | >>> print "%r, %r" % (mary.id, mary.name) 183 | 2, u'Mary Margaret' 184 | 185 | 186 | 改变仓库中的对象 187 | --------------------- 188 | 189 | 正如往常修改对象一样,我们也可以通过使用表达式修改绑定了数据库的对象,并因此收益。 190 | 191 | :: 192 | 193 | >>> store.find(Person, Person.name == u"Mary Margaret").set(name=u"Mary Maggie") 194 | >>> mary.name 195 | u'Mary Maggie' 196 | 197 | 此操作会修改数据库及内存中所有匹配对象。 198 | 199 | 200 | 提交 201 | ----- 202 | 203 | 至今为止我们所做的一切都只是事务(transaction)。在这个点上,我们既可以通过提交(committing)操作,将之前未提交的改动操作都执行,又或者,我们可以通过回滚(rolling)操作来取消它们。 204 | 205 | 让我们来提交它,这很简单: 206 | 207 | :: 208 | 209 | >>> store.commit() 210 | >>> 211 | 212 | 一目了然。一切还是像以前一样,但现在改动操作已经是板上钉钉了。 213 | 214 | 215 | 回滚 216 | ------ 217 | 218 | 想要终止改动操作也是同样直观的。 219 | 220 | :: 221 | 222 | >>> joe.name = u"Tom Thomas" 223 | >>> 224 | 225 | 让我们在 Storm 的数据库中看看这种改动将会是什么样子。 226 | 227 | :: 228 | 229 | >>> person = store.find(Person, Person.name == u"Tom Thomas").one() 230 | >>> person is joe 231 | True 232 | 233 | 一切如常,现在,魔术开始(音乐,起!)。 234 | 235 | :: 236 | 237 | >>> store.rollback() 238 | >>> 239 | 240 | 呃。。。啥事都没发生? 241 | 242 | 其实不然。 Joe ,他回来了! 243 | 244 | :: 245 | 246 | >>> print "%r, %r" % (joe.id, joe.name) 247 | 1, u'Joe Johnes' 248 | 249 | 250 | 构造函数 251 | ----------- 252 | 253 | 我们研究人(``Person`` 类)已经够久了。现在,让我们在模型中增加一种新数据:公司(``Company`` 类)。我们将在 ``Company`` 类中使用构造函数,因为这会比较好玩。这将是你所见过的最简单的公司类: 254 | 255 | :: 256 | 257 | >>> class Company(object): 258 | ... __storm_table__ = "company" 259 | ... id = Int(primary=True) 260 | ... name = Unicode() 261 | ... 262 | ... def __init__(self, name): 263 | ... self.name = name 264 | 265 | 注意,构造函数的参数并非是可选的。如果你愿意,它也可以是可选的,但公司总得有个名字吧。 266 | 267 | 让我们为它添加表: 268 | 269 | :: 270 | 271 | >>> store.execute("CREATE TABLE company " 272 | ... "(id INTEGER PRIMARY KEY, name VARCHAR)", noresult=True) 273 | 274 | 然后,创建一个新公司: 275 | 276 | :: 277 | 278 | >>> circus = Company(u"Circus Inc.") 279 | 280 | >>> print "%r, %r" % (circus.id, circus.name) 281 | None, u'Circus Inc.' 282 | 283 | 284 | 因为我们还没刷新,所以 ``id`` 仍然是未定义的。事实上,我们甚至还没有把新创建的公司加入到仓库中。我们稍候再来做这事。 285 | 286 | 287 | 引用和继承 288 | ------------ 289 | 290 | 现在,我们希望指派一些雇员到我们的公司。与其重定义 ``Person`` 类,我们不如让其维持原状,因为它足够一般,我们创建一个它的子类作为雇员类,其中雇员类还有一个新加入的字段:公司的 ``id`` 。 291 | 292 | :: 293 | 294 | >>> class Employee(Person): 295 | ... __storm_table__ = "employee" 296 | ... company_id = Int() 297 | ... company = Reference(company_id, Company.id) 298 | ... 299 | ... def __init__(self, name): 300 | ... self.name = name 301 | 302 | 303 | 注意上面的定义,它没有改写 ``Person`` 类原有的东西,而是引入了引用到其他类的两个属性: ``company_id`` 和 ``company`` 。它也有构造函数,但里面并没有任何关于 ``company`` 的定义。 304 | 305 | 像往常一样,我们需要一个表。 SQLite 对外键(foreign key)没有太多想法, 所以我们也懒得去定义它。 306 | 307 | :: 308 | 309 | >>> store.execute("CREATE TABLE employee " 310 | ... "(id INTEGER PRIMARY KEY, name VARCHAR, company_id INTEGER)", 311 | ... noresult=True) 312 | 313 | 是时候让 Ben 闪亮登场了: 314 | 315 | :: 316 | 317 | >>> ben = store.add(Employee(u"Ben Bill")) 318 | >>> 319 | >>> print "%r, %r, %r" % (ben.id, ben.name, ben.company_id) 320 | None, u'Ben Bill', None 321 | 322 | 323 | 我们可以看到,以上内容还没有被刷新。即便如此,我们也可以断言 Bill 在马戏团(Circus)工作。 324 | 325 | :: 326 | 327 | >>> ben.company = circus 328 | >>> 329 | >>> print "%r, %r" % (ben.company_id, ben.company.name) 330 | None, u'Circus Inc.' 331 | 332 | 当然,在数据库刷新之前,我们仍然不知道公司 ``id`` ,也不显式地给他指定一个。即便如此, Storm 还是能保持它们之间的关系。 333 | 334 | 如果有任何正在等待的操作被刷新到数据库中(无论是隐式或强制),对象会获取它们的 ``id`` ,并保证在刷新之前,所有引用关系 都可以顺利被更新。 335 | 336 | :: 337 | 338 | >>> store.flush() 339 | >>> 340 | >>> print "%r, %r" % (ben.company_id, ben.company.name) 341 | 1, u'Circus Inc.' 342 | 343 | 它们都被刷新到数据库里面了。现在,请注意马戏团公司并没有强制地被加入到仓库。Storm 会自动为引用和被引用对象双方完成该任务。 344 | 345 | 让我们创建另一家公司来检查一下。这一次,我们会在加入新公司之后立刻刷新: 346 | 347 | :: 348 | 349 | >>> sweets = store.add(Company(u"Sweets Inc.")) 350 | >>> store.flush() 351 | >>> sweets.id 352 | 2 353 | 354 | 不错,我们已经得到了新公司的 ``id`` 。那么,如果我们改变 Ben 的 ``company_id`` ,会怎么样? 355 | 356 | :: 357 | 358 | >>> ben.company_id = 2 359 | >>> ben.company.name 360 | u'Sweets Inc.' 361 | >>> ben.company is sweets 362 | True 363 | 364 | 哈哈!没有料到吧? 365 | 366 | 让我们将所有改动都提交了吧。 367 | 368 | :: 369 | 370 | >>> store.commit() 371 | >>> 372 | 373 | 374 | 多对一引用集合 375 | ------------------- 376 | 377 | 我们的模型表示,员工们只在一间公司工作(我们这里只设计平常人),而公司当然可以有多个员工。在 Storm 中我们用引用集合(reference sets)表示它们。 378 | 379 | 我们不重新定义 ``Company`` 类,而是将一个新特性(attribute)加给它: 380 | 381 | :: 382 | 383 | >>> Company.employees = ReferenceSet(Company.id, Employee.company_id) 384 | 385 | 仅次而已,我们已经可以查看哪些员工在给定的公司工作。 386 | 387 | :: 388 | 389 | >>> sweets.employees.count() 390 | 1 391 | 392 | >>> for employee in sweets.employees: 393 | ... print "%r, %r" % (employee.id, employee.name) 394 | ... print employee is ben 395 | ... 396 | 1, u'Ben Bill' 397 | True 398 | 399 | 让我们创建另一名雇员,并将他加入到公司当中: 400 | 401 | :: 402 | 403 | >>> mike = store.add(Employee(u"Mike Mayer")) 404 | >>> sweets.employees.add(mike) 405 | 406 | 毋庸置疑,Mike 现在已经是公司的职员了,这一情况也应该被反映在其他地方。 407 | 408 | :: 409 | 410 | >>> mike.company_id 411 | 2 412 | 413 | >>> mike.company is sweets 414 | True 415 | 416 | 417 | 多对多引用集合以及组合键(composed keys) 418 | ---------------------------------------------- 419 | 420 | 我们还打算在模型中表示会计师。公司都有会计师,但会计师通常可以为多间公司服务,因此我们用多对多关系来表示它们。 421 | 422 | 让我们创建简单的类,用来表示会计师及其关系。 423 | 424 | :: 425 | 426 | >>> class Accountant(Person): 427 | ... __storm_table__ = "accountant" 428 | ... def __init__(self, name): 429 | ... self.name = name 430 | 431 | >>> class CompanyAccountant(object): 432 | ... __storm_table__ = "company_accountant" 433 | ... __storm_primary__ = "company_id", "accountant_id" 434 | ... company_id = Int() 435 | ... accountant_id = Int() 436 | 437 | 438 | 嘿,我们刚刚定义了带组合键的类! 439 | 440 | 现在,让我们使用它在 ``Company`` 类中定义多对多关系。再一次,我们将新属性塞进已有的对象当中。在编写类的时候定义这些属性也很简单。稍候我们会看到如何用别的方法做这事。 441 | 442 | :: 443 | 444 | >>> Company.accountants = ReferenceSet(Company.id, 445 | ... CompanyAccountant.company_id, 446 | ... CompanyAccountant.accountant_id, 447 | ... Accountant.id) 448 | 449 | 搞定!属性排列的先后顺序事关重大,但这里面的逻辑应该是一目了然的。 450 | 451 | 在这个点上,我们还缺一些表。 452 | 453 | :: 454 | 455 | >>> store.execute("CREATE TABLE accountant " 456 | ... "(id INTEGER PRIMARY KEY, name VARCHAR)", noresult=True) 457 | ... 458 | 459 | >>> store.execute("CREATE TABLE company_accountant " 460 | ... "(company_id INTEGER, accountant_id INTEGER," 461 | ... " PRIMARY KEY (company_id, accountant_id))", noresult=True) 462 | 463 | 我们将一对会计夫妇登记到两个公司。 464 | 465 | :: 466 | 467 | >>> karl = Accountant(u"Karl Kent") 468 | >>> frank = Accountant(u"Frank Fourt") 469 | 470 | >>> sweets.accountants.add(karl) 471 | >>> sweets.accountants.add(frank) 472 | 473 | >>> circus.accountants.add(frank) 474 | >>> 475 | 476 | 大功告成!真的!请注意,我们甚至不必将它们添加到仓库,当它们链接到其他已经在仓库内的对象时,这已经被隐式地执行了,我们也无须宣告对象间的关系,因为那已经在引用对象集合中明晰了。 477 | 478 | 现在,让我们来验证一下。 479 | 480 | :: 481 | 482 | >>> sweets.accountants.count() 483 | 2 484 | 485 | >>> circus.accountants.count() 486 | 1 487 | 488 | 我们还没有显式地使用过 ``CompanyAccountant`` 对象,假如你好奇的话,也可以验证一下它。 489 | 490 | :: 491 | 492 | >>> store.get(CompanyAccountant, (sweets.id, frank.id)) 493 | > 494 | 495 | 496 | 请注意,因为组合键的关系,我们往 ``get`` 方法传递了一个元组(tuple)。 497 | 498 | 如果我们想知道会计师为哪些公司工作, 我们可以很容易地定义一个反向(reversed)关系: 499 | 500 | :: 501 | 502 | >>> Accountant.companies = ReferenceSet(Accountant.id, 503 | ... CompanyAccountant.accountant_id, 504 | ... CompanyAccountant.company_id, 505 | ... Company.id) 506 | 507 | >>> [company.name for company in frank.companies] 508 | [u'Circus Inc.', u'Sweets Inc.'] 509 | 510 | >>> [company.name for company in karl.companies] 511 | [u'Sweets Inc.'] 512 | 513 | 514 | 联接(Joins) 515 | ------------- 516 | 517 | 既然已经有了一些不错的数据,让我们尝试做一些有趣的查询(queries)玩玩看。 518 | 519 | 先来检查看看哪些公司至少有一名叫 Ben 的员工。我们至少有两种方法可以做到这一点。 520 | 521 | 首先,使用隐式联接。 522 | 523 | :: 524 | 525 | >>> result = store.find(Company, 526 | ... Employee.company_id == Company.id, 527 | ... Employee.name.like(u"Ben %")) 528 | ... 529 | 530 | >>> [company.name for company in result] 531 | [u'Sweets Inc.'] 532 | 533 | 然后,我们也可以做一个显式联接。这是 Storm 查询当中,映射复杂 SQL 联接的有趣之处。 534 | 535 | :: 536 | 537 | >>> origin = [Company, Join(Employee, Employee.company_id == Company.id)] 538 | >>> result = store.using(*origin).find(Company, Employee.name.like(u"Ben %")) 539 | 540 | >>> [company.name for company in result] 541 | [u'Sweets Inc.'] 542 | 543 | 如果我们已经定义过公司,并且想知道公司内哪个员工名叫 Ben ,这再容易不过了。 544 | 545 | :: 546 | 547 | >>> result = sweets.employees.find(Employee.name.like(u"Ben %")) 548 | 549 | >>> [employee.name for employee in result] 550 | [u'Ben Bill'] 551 | 552 | 553 | 子查询 554 | -------- 555 | 556 | 假设我们想找出所有不属于公司的会计,可以使用子查询。 557 | 558 | :: 559 | 560 | >>> laura = Accountant(u"Laura Montgomery") 561 | >>> store.add(laura) 562 | 563 | 564 | >>> subselect = Select(CompanyAccountant.accountant_id, distinct=True) 565 | >>> result = store.find(Accountant, Not(Accountant.id.is_in(subselect))) 566 | >>> result.one() is laura 567 | True 568 | 569 | 570 | 排序以及限制(limiting)结果 571 | ---------------------------- 572 | 573 | 排序和限制结果通常是这样那样工具的最简单而又最迫切的功能,所以我们希望它们能够既简单又易用,这是当然的了。 574 | 575 | 一行代码胜过千言万语,这里有几个例子,说明它是如何工作的: 576 | 577 | :: 578 | 579 | >>> garry = store.add(Employee(u"Garry Glare")) 580 | 581 | >>> result = store.find(Employee) 582 | 583 | >>> [employee.name for employee in result.order_by(Employee.name)] 584 | [u'Ben Bill', u'Garry Glare', u'Mike Mayer'] 585 | 586 | >>> [employee.name for employee in result.order_by(Desc(Employee.name))] 587 | [u'Mike Mayer', u'Garry Glare', u'Ben Bill'] 588 | 589 | >>> [employee.name for employee in result.order_by(Employee.name)[:2]] 590 | [u'Ben Bill', u'Garry Glare'] 591 | 592 | 593 | 多类型查询 594 | ------------ 595 | 596 | 有时候,用一个查询检索多于一个对象也是蛮有趣的。想象一下,例如除了想知道哪个公司有名叫 Ben 的员工外,我们也想知道这名员工到底是何许人也。这可以用类似如下的查询来完成: 597 | 598 | :: 599 | 600 | >>> result = store.find((Company, Employee), 601 | ... Employee.company_id == Company.id, 602 | ... Employee.name.like(u"Ben %")) 603 | 604 | >>> [(company.name, employee.name) for company, employee in result] 605 | [(u'Sweets Inc.', u'Ben Bill')] 606 | 607 | 608 | Storm 基类 609 | ------------- 610 | 611 | 到目前为止,我们已经用类和类的属性定义好了引用关系及引用集合。这一做法有一定优势,比如更易于调试,但也有一定缺点,比如因为类需要在本地范围(local scope)内被表示(be present),可能会导致循环引用(circular import)情况。 612 | 613 | 为了避免那样的状况,Storm 支持使用字符串化的方式,为类和属性名字(names)定义引用关系。这样做的唯一不便是,所有相关的类都必须继承 Storm 类。 614 | 615 | 让我们定义一些新的类来演示一下。为了揭示要点,我们将在类实际定义引用关系之前引用它们。 616 | 617 | :: 618 | 619 | >>> class Country(Storm): 620 | ... __storm_table__ = "country" 621 | ... id = Int(primary=True) 622 | ... name = Unicode() 623 | ... currency_id = Int() 624 | ... currency = Reference(currency_id, "Currency.id") 625 | 626 | >>> class Currency(Storm): 627 | ... __storm_table__ = "currency" 628 | ... id = Int(primary=True) 629 | ... symbol = Unicode() 630 | 631 | >>> store.execute("CREATE TABLE country " 632 | ... "(id INTEGER PRIMARY KEY, name VARCHAR, currency_id INTEGER)", 633 | ... noresult=True) 634 | 635 | >>> store.execute("CREATE TABLE currency " 636 | ... "(id INTEGER PRIMARY KEY, symbol VARCHAR)", noresult=True) 637 | 638 | 639 | 现在,让我们看看它是否工作: 640 | 641 | :: 642 | 643 | >>> real = store.add(Currency()) 644 | >>> real.id = 1 645 | >>> real.symbol = u"BRL" 646 | 647 | >>> brazil = store.add(Country()) 648 | >>> brazil.name = u"Brazil" 649 | >>> brazil.currency_id = 1 650 | 651 | >>> brazil.currency.symbol 652 | u'BRL' 653 | 654 | 655 | 载入钩子 656 | ------------- 657 | 658 | Storm 允许类定义几个不同的钩子,当某些事情发生时,它们就会采取行动。这里就有一个有趣的钩子: ``__storm_loaded__`` 。 659 | 660 | 让我们定义 ``Person`` 的一个临时的子类,然后来测试一下它。 661 | 662 | :: 663 | 664 | >>> class PersonWithHook(Person): 665 | ... def __init__(self, name): 666 | ... print "Creating %s" % name 667 | ... self.name = name 668 | ... 669 | ... def __storm_loaded__(self): 670 | ... print "Loaded %s" % self.name 671 | 672 | >>> earl = store.add(PersonWithHook(u"Earl Easton")) 673 | Creating Earl Easton 674 | 675 | >>> earl = store.find(PersonWithHook, name=u"Earl Easton").one() 676 | 677 | >>> store.invalidate(earl) 678 | >>> del earl 679 | >>> import gc 680 | >>> collected = gc.collect() 681 | 682 | >>> earl = store.find(PersonWithHook, name=u"Earl Easton").one() 683 | Loaded Earl Easton 684 | 685 | 686 | 请注意,在第一次查找(find)的时候,没有返回结果,因为当时对象还只存在于内存和缓存中。然后,我们从 Storm 缓存中无效化(invalidated)对象,并触发垃圾回收以确保对象不在内存当中。在此之后,对象必须通过数据库被再次检索,钩子(不是构造函数!)也因此被调用。 687 | 688 | 689 | 执行表达式 690 | ------------- 691 | 692 | Storm 还提供了一种非数据库式(database-agnostic way)的方式来执行表达式,以备不时之需。 693 | 例如: 694 | 695 | :: 696 | 697 | >>> result = store.execute(Select(Person.name, Person.id == 1)) 698 | >>> result.get_one() 699 | 3 (u'Joe Johnes',) 700 | 701 | 这一机制被 Storm 自身内部用以实现更高级功能。 702 | 703 | 704 | 自动重载(reloading)值 705 | ------------------------ 706 | 707 | Storm 提供了一些在它控制之下的特殊值,可以将它们赋给属性。其中一个特殊值就是 ``AutoReload`` 。启用它后,每次接触(touched)数据库,对象的值都将被自动重载。这对主键可能有用,就如下面的例子所示。 708 | 709 | :: 710 | 711 | >>> from storm.locals import AutoReload 712 | 713 | >>> ruy = store.add(Person()) 714 | >>> ruy.name = u"Ruy" 715 | >>> print ruy.id 716 | None 717 | 718 | >>> ruy.id = AutoReload 719 | >>> print ruy.id 720 | 4 721 | 722 | 当有需要时,可以将属性的默认值设为 ``AutoReload`` ,让对象实行自动刷新。 723 | 724 | 725 | 表达式的值 726 | ----------------- 727 | 728 | 可以赋给属性的除了自动重载之外,还有“惰性表达式”。这种表达式只在属性被访问、或者当对象被刷新到数据库(插入/更新)时,才会被刷新到数据库。 729 | 730 | 例如: 731 | 732 | :: 733 | 734 | from storm.locals import SQL 735 | 736 | >>> ruy.name = SQL("(SELECT name || ? FROM person WHERE id=4)", (" Ritcher",)) 737 | >>> ruy.name 738 | u'Ruy Ritcher' 739 | 740 | 741 | 请注意,这只是一个关于“可以做什么”的例子,并不是说非要这样写 SQL 语句不可。你可以用 Storm 提供的基于类的 SQL 表达式,把惰性表达式忘到九霄云外。 742 | 743 | 744 | 别名(aliase) 745 | ------------------ 746 | 747 | 现在,我们想要找出所有在同一家公司工作的人——我不知道到底是谁想这么干,但这是一个使用别名的好机会。 748 | 749 | 首先,我们要将 ``ClassAlias`` 引入到本地命名空间当中(友情提示: ``storm.local`` 也应该被载入),并且创建一个引用指向它。 750 | 751 | :: 752 | 753 | >>> from storm.info import ClassAlias 754 | >>> AnotherEmployee = ClassAlias(Employee) 755 | 756 | 它看上去不错,不是嘛? 757 | 758 | 现在,我们可以用一种简单直接的方式来查询: 759 | 760 | :: 761 | 762 | >>> result = store.find((Employee, AnotherEmployee), 763 | ... Employee.company_id == AnotherEmployee.company_id, 764 | ... Employee.id > AnotherEmployee.id) 765 | 766 | >>> for employee1, employee2 in result: 767 | ... print (employee1.name, employee2.name) 768 | (u'Mike Mayer', u'Ben Bill') 769 | 770 | 771 | 哇! Mike 和 Ben 为同一家公司工作! 772 | 773 | (考考你:为什么上面的查询里要使用大于号?) 774 | 775 | 776 | 调试 777 | -------- 778 | 779 | 某些时候,你需查看 Storm 正在执行的语句。一个建立在 Storm 跟踪系统之上的调试跟踪器可以用来查看引擎盖下到底发生了什么事。跟踪器是一个对象,当有趣的事情发生——比如当 Storm 执行一个语句时,它会收到通知。提供了一个函数来开启和关闭语句跟踪语句。语句默认记录在 ``sys.stderr`` 之下,也可以自己指定一个流。 780 | 781 | :: 782 | 783 | >>> import sys 784 | >>> from storm.tracer import debug 785 | 786 | >>> debug(True, stream=sys.stdout) 787 | >>> result = store.find((Employee, AnotherEmployee), 788 | ... Employee.company_id == AnotherEmployee.company_id, 789 | ... Employee.id > AnotherEmployee.id) 790 | >>> list(result) 791 | EXECUTE: 'SELECT employee.company_id, employee.id, employee.name, "...".company_id, "...".id, "...".name FROM employee, employee AS "..." WHERE employee.company_id = "...".company_id AND employee.id > "...".id', () 792 | [(, )] 793 | 794 | >>> debug(False) 795 | >>> list(result) 796 | [(, )] 797 | 798 | 799 | 更多! 800 | --------- 801 | 802 | 关于 Storm 还有很多值得谈谈。这个教程只提供了一些入门概念。如果你的问题在别的地方找不到答案,欢迎你到邮件列表里发问。 803 | -------------------------------------------------------------------------------- /make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=_build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . 10 | set I18NSPHINXOPTS=%SPHINXOPTS% . 11 | if NOT "%PAPER%" == "" ( 12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% 14 | ) 15 | 16 | if "%1" == "" goto help 17 | 18 | if "%1" == "help" ( 19 | :help 20 | echo.Please use `make ^` where ^ is one of 21 | echo. html to make standalone HTML files 22 | echo. dirhtml to make HTML files named index.html in directories 23 | echo. singlehtml to make a single large HTML file 24 | echo. pickle to make pickle files 25 | echo. json to make JSON files 26 | echo. htmlhelp to make HTML files and a HTML help project 27 | echo. qthelp to make HTML files and a qthelp project 28 | echo. devhelp to make HTML files and a Devhelp project 29 | echo. epub to make an epub 30 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 31 | echo. text to make text files 32 | echo. man to make manual pages 33 | echo. texinfo to make Texinfo files 34 | echo. gettext to make PO message catalogs 35 | echo. changes to make an overview over all changed/added/deprecated items 36 | echo. linkcheck to check all external links for integrity 37 | echo. doctest to run all doctests embedded in the documentation if enabled 38 | goto end 39 | ) 40 | 41 | if "%1" == "clean" ( 42 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 43 | del /q /s %BUILDDIR%\* 44 | goto end 45 | ) 46 | 47 | if "%1" == "html" ( 48 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 49 | if errorlevel 1 exit /b 1 50 | echo. 51 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 52 | goto end 53 | ) 54 | 55 | if "%1" == "dirhtml" ( 56 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 57 | if errorlevel 1 exit /b 1 58 | echo. 59 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 60 | goto end 61 | ) 62 | 63 | if "%1" == "singlehtml" ( 64 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 65 | if errorlevel 1 exit /b 1 66 | echo. 67 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 68 | goto end 69 | ) 70 | 71 | if "%1" == "pickle" ( 72 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 73 | if errorlevel 1 exit /b 1 74 | echo. 75 | echo.Build finished; now you can process the pickle files. 76 | goto end 77 | ) 78 | 79 | if "%1" == "json" ( 80 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 81 | if errorlevel 1 exit /b 1 82 | echo. 83 | echo.Build finished; now you can process the JSON files. 84 | goto end 85 | ) 86 | 87 | if "%1" == "htmlhelp" ( 88 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 89 | if errorlevel 1 exit /b 1 90 | echo. 91 | echo.Build finished; now you can run HTML Help Workshop with the ^ 92 | .hhp project file in %BUILDDIR%/htmlhelp. 93 | goto end 94 | ) 95 | 96 | if "%1" == "qthelp" ( 97 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 98 | if errorlevel 1 exit /b 1 99 | echo. 100 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 101 | .qhcp project file in %BUILDDIR%/qthelp, like this: 102 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\StormORM.qhcp 103 | echo.To view the help file: 104 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\StormORM.ghc 105 | goto end 106 | ) 107 | 108 | if "%1" == "devhelp" ( 109 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 110 | if errorlevel 1 exit /b 1 111 | echo. 112 | echo.Build finished. 113 | goto end 114 | ) 115 | 116 | if "%1" == "epub" ( 117 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 118 | if errorlevel 1 exit /b 1 119 | echo. 120 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 121 | goto end 122 | ) 123 | 124 | if "%1" == "latex" ( 125 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 126 | if errorlevel 1 exit /b 1 127 | echo. 128 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 129 | goto end 130 | ) 131 | 132 | if "%1" == "text" ( 133 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 134 | if errorlevel 1 exit /b 1 135 | echo. 136 | echo.Build finished. The text files are in %BUILDDIR%/text. 137 | goto end 138 | ) 139 | 140 | if "%1" == "man" ( 141 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 142 | if errorlevel 1 exit /b 1 143 | echo. 144 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 145 | goto end 146 | ) 147 | 148 | if "%1" == "texinfo" ( 149 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo 150 | if errorlevel 1 exit /b 1 151 | echo. 152 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. 153 | goto end 154 | ) 155 | 156 | if "%1" == "gettext" ( 157 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale 158 | if errorlevel 1 exit /b 1 159 | echo. 160 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale. 161 | goto end 162 | ) 163 | 164 | if "%1" == "changes" ( 165 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 166 | if errorlevel 1 exit /b 1 167 | echo. 168 | echo.The overview file is in %BUILDDIR%/changes. 169 | goto end 170 | ) 171 | 172 | if "%1" == "linkcheck" ( 173 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 174 | if errorlevel 1 exit /b 1 175 | echo. 176 | echo.Link check complete; look for any errors in the above output ^ 177 | or in %BUILDDIR%/linkcheck/output.txt. 178 | goto end 179 | ) 180 | 181 | if "%1" == "doctest" ( 182 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 183 | if errorlevel 1 exit /b 1 184 | echo. 185 | echo.Testing of doctests in the sources finished, look at the ^ 186 | results in %BUILDDIR%/doctest/output.txt. 187 | goto end 188 | ) 189 | 190 | :end 191 | -------------------------------------------------------------------------------- /readme.rst: -------------------------------------------------------------------------------- 1 | 关于 2 | -------- 3 | 4 | 本文是 Python Storm ORM 库官方教程的中文翻译版本,可以在 http://python-storm-tutorial.readthedocs.org/ 在线阅读。 5 | --------------------------------------------------------------------------------