Django

Code

DjangoSpecifications/Docs/ConvertingRestToOtherFormats: build_htmldocs-links_work-with_docs.diff

File build_htmldocs-links_work-with_docs.diff, 22.1 kB (added by mrts, 2 months ago)
  • django/core/management/commands/htmldocs.py

    old new  
     1""" 
     2Command that converts Django documentation from ReST to HTML. 
     3 
     4Based on django_website/apps/docs/builder.py. 
     5""" 
     6 
     7# TODO: 
     8# 1. fix inter-page links 
     9# 2. fetch external images and place them to img directory, fix image links 
     10# 3. add images used in CSS (in notes etc) 
     11# 4. add PDF support, take inspiration from http://code.google.com/p/rst2pdf/ 
     12 
     13import os 
     14import shutil 
     15from optparse import make_option 
     16from django.core.management import BaseCommand, CommandError 
     17 
     18CSS_FILE = "docs.css" 
     19 
     20class Command(BaseCommand): 
     21    option_list = BaseCommand.option_list + ( 
     22            make_option('--single', action='store_true', dest='single', 
     23                default=False, help = "Write a single combined HTML file. " 
     24                "Not recommended, produces output that is harder to navigate."), 
     25    ) 
     26    help = ("Converts Django documentation to HTML. Uses the given Django " 
     27            "documentation directory for reading documentation source and " 
     28            "output directory for writing HTML files. Creates the output " 
     29            "directory if it does not exist.") 
     30    args = "[Django documentation directory] [output directory]" 
     31 
     32    requires_model_validation = False 
     33    can_import_settings = False 
     34 
     35    def handle(self, *paths, **options): 
     36        try: 
     37            from docutils.core import publish_parts 
     38        except ImportError: 
     39            raise CommandError("The docutils module is required to run " 
     40                    "this command.") 
     41 
     42        if len(paths) != 2: 
     43            raise CommandError("Please provide exactly two arguments in the " 
     44                    "following order: %s." % self.args) 
     45 
     46        source, dest = paths 
     47        if not os.path.exists(dest): 
     48            try: 
     49                os.mkdir(dest) 
     50            except OSError, e: 
     51                raise CommandError("Failed to create directory '%s'. " 
     52                        "The error was '%s'." % (dest, e)) 
     53        for p in source, dest: 
     54            if not os.path.isdir(p): 
     55                raise CommandError("'%s' is not a directory." % p) 
     56 
     57        css_path = os.path.join(source, "css", CSS_FILE) 
     58        if not os.path.exists(css_path): 
     59            raise CommandError("'%s' does not appear to be a Django " 
     60                    "documentation directory (stylesheet not found)" % source) 
     61        try: 
     62            shutil.copy(css_path, dest) 
     63        except IOError, e: 
     64            raise CommandError("Unable to write to directory '%s'. " 
     65                    "The error was '%s'." % (dest, e)) 
     66 
     67        opt_single = options.get("single", False) 
     68 
     69        files = [f for f in os.listdir(source) if f.endswith('.txt')] 
     70        files.sort() 
     71 
     72        if opt_single: 
     73            docs = [] 
     74        index = [] 
     75        for file in files: 
     76            out = file[:-4] + ".html" 
     77            print "Converting '%s'... " % out, 
     78            doc = publish_parts(open(os.path.join(source, file)).read(), 
     79                    writer=get_django_html_writer(opt_single), 
     80                    settings_overrides={'initial_header_level': 2}) 
     81            print "done" 
     82            try: 
     83                index.append([out, doc['title']]) 
     84            except KeyError: 
     85                index.append([out, 'UNKNOWN (%s)' % file]) 
     86         
     87            if opt_single: 
     88                doc['id'] = out 
     89                docs.append(doc) 
     90            else: 
     91                out_path = os.path.join(dest, out) 
     92                print "Writing '%s'... " % out_path, 
     93                open(out_path, 'w').write(render_doc(doc)) 
     94                print "done" 
     95         
     96        # write out either index or the single combined page 
     97        doc = None 
     98        if opt_single: 
     99            doc = { 
     100                'title' : "Documentation", 
     101                'toc' : get_single_toc(index), 
     102                'body' : get_single_body(docs) 
     103            } 
     104        else: 
     105            doc = { 
     106                'title' : "Documentation index", 
     107                'toc' : "<p>This is the automatically genrated documentation " 
     108                            "index. The automatic documentation is a basic " 
     109                            "reference, more resources are available on the " 
     110                            '<a href="http://www.djangoproject.com/documentation/">' 
     111                            "Django website</a>.</p>", 
     112                'body' : '<ul>%s</ul>' % \ 
     113                        '\n'.join(['<li><a href="%s">%s</a></li>' \ 
     114                            % (href, title) for href, title in index ]) 
     115            } 
     116        print "Writing index... ", 
     117        open(os.path.join(dest, "index.html"), 'w').write(render_doc(doc)) 
     118        print "done" 
     119        print "All done" 
     120 
     121def get_single_toc(index): 
     122    """ 
     123    Creates the table of contents for single-document output. 
     124    """ 
     125    toc = '<ul class="toc">%s</ul>' 
     126    line = '<li><a class="reference internal" href="#%s">%s</a></li>' 
     127    return toc % '\n'.join([ line % (name, title) for name, title in index]) 
     128     
     129def get_single_body(docs): 
     130    """ 
     131    Joins individual documents into a single document. 
     132    """ 
     133    chunk = '<h1 id="%(id)s">%(title)s</h1>\n%(body)s' 
     134    return '\n'.join([chunk % doc for doc in docs]) 
     135 
     136def render_doc(doc): 
     137    """ 
     138    Renders the document with a HTML template. 
     139    """ 
     140    return ("""<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
     141        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
     142<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> 
     143        <head> 
     144                <meta http-equiv="Content-type" content="text/html; charset=utf-8" /> 
     145                <meta http-equiv="Content-Language" content="en-us" /> 
     146                <title>%(title)s | Django Documentation</title> 
     147                <link href="docs.css" rel="stylesheet" type="text/css" media="screen" /> 
     148    </head> 
     149    <body id="documentation" class="default"> 
     150    <div id="container"> 
     151        <div id="header"> 
     152            <ul id="nav-global"> 
     153                <li id="nav-homepage"><a href="index.html">Documentation index</a></li> 
     154            </ul> 
     155        </div> 
     156        <div id="billboard"><h2><a href="index.html" style="color: white; height:40px; padding-top:20px; text-indent:22px;">Django documentation</a></h2></div> 
     157        <div id="columnwrap"> 
     158            <div id="content-main"> 
     159                <h1>%(title)s</h1> 
     160                %(body)s 
     161            </div> 
     162            <div id="content-related" class="sidebar"> 
     163                <h2>Contents</h2> 
     164                %(toc)s 
     165            </div> 
     166        </div> 
     167        <div id="footer"> 
     168            <p><a href="index.html"><< Back to documentation index</a></p> 
     169        </div> 
     170    </div> 
     171    </body> 
     172</html>""" % doc).encode('utf-8') 
     173 
     174def get_django_html_writer(is_single): 
     175    """ 
     176    Returns the Django HTML writer instance. Note that we need to define the 
     177    classes inside a function to avoid triggering an import error when 
     178    docutils is unavailable. 
     179    """ 
     180    from docutils import nodes 
     181    from docutils.writers import html4css1 
     182    import re 
     183 
     184    class DjangoHTMLTranslator(html4css1.HTMLTranslator): 
     185        """ 
     186        reST -> HTML translator subclass that outputs Django-specific markup. 
     187        """ 
     188         
     189        # Prevent name attributes from being generated 
     190        named_tags = [] 
     191         
     192        def __init__(self, document): 
     193            html4css1.HTMLTranslator.__init__(self, document) 
     194            self._in_literal = 0 
     195         
     196        # Remove the default border=1 from <table> 
     197        def visit_table(self, node): 
     198            self.body.append(self.starttag(node, 'table', CLASS='docutils')) 
     199 
     200        # No smartypants conversion 
     201 
     202        # Avoid <blockquote>s around merely indented nodes. 
     203        # Adapted from 
     204        # http://thread.gmane.org/gmane.text.docutils.user/742/focus=804 
     205         
     206        _suppress_blockquote_child_nodes = ( 
     207            nodes.bullet_list, nodes.enumerated_list, nodes.definition_list, 
     208            nodes.literal_block, nodes.doctest_block, nodes.line_block, 
     209            nodes.table 
     210        ) 
     211        def _bq_is_valid(self, node): 
     212            return len(node.children) != 1 \ 
     213                    or not isinstance(node.children[0], 
     214                            self._suppress_blockquote_child_nodes) 
     215                                             
     216        def visit_block_quote(self, node): 
     217            if self._bq_is_valid(node): 
     218                html4css1.HTMLTranslator.visit_block_quote(self, node) 
     219 
     220        def depart_block_quote(self, node): 
     221            if self._bq_is_valid(node): 
     222                html4css1.HTMLTranslator.depart_block_quote(self, node) 
     223 
     224    # Fix inter-page links 
     225 
     226    class MultiPageTranslator(DjangoHTMLTranslator): 
     227        def visit_reference(self, node, regex=re.compile(r'^../([-\w]+)/')): 
     228            if node.has_key('refuri') and regex.match(node['refuri']): 
     229                node['refuri'] = regex.sub(r'\1.html', node['refuri']) 
     230            html4css1.HTMLTranslator.visit_reference(self, node) 
     231 
     232    class SinglePageTranslator(DjangoHTMLTranslator): 
     233        # Destroys ../foo/#bar style anchors (replacing them with #foo), 
     234        # but we can live with that 
     235        def visit_reference(self, node, regex=re.compile(r'^../([-\w]+)/.*')): 
     236            if node.has_key('refuri') and regex.match(node['refuri']): 
     237                node['refuri'] = regex.sub(r'#\1.html', node['refuri']) 
     238            html4css1.HTMLTranslator.visit_reference(self, node) 
     239 
     240    class DjangoHTMLWriter(html4css1.Writer): 
     241        """ 
     242        HTML writer that adds a "toc" key to the set of doc parts. 
     243        """ 
     244        def __init__(self): 
     245            html4css1.Writer.__init__(self) 
     246            if is_single: 
     247                self.translator_class = SinglePageTranslator 
     248            else: 
     249                self.translator_class = MultiPageTranslator 
     250 
     251        def translate(self): 
     252            # build the document 
     253            html4css1.Writer.translate(self) 
     254 
     255            # build the contents 
     256            contents = self.build_contents(self.document) 
     257            contents_doc = self.document.copy() 
     258            contents_doc.children = contents 
     259            contents_visitor = self.translator_class(contents_doc) 
     260            contents_doc.walkabout(contents_visitor) 
     261            self.parts['toc'] = "<ul class='toc'>%s</ul>" \ 
     262                    % ''.join(contents_visitor.fragment) 
     263 
     264        def build_contents(self, node, level=0): 
     265            level += 1 
     266            sections = [] 
     267            i = len(node) - 1 
     268            while i >= 0 and isinstance(node[i], nodes.section): 
     269                sections.append(node[i]) 
     270                i -= 1 
     271            sections.reverse() 
     272            entries = [] 
     273            autonum = 0 
     274            depth = 4   # XXX FIXME 
     275            for section in sections: 
     276                title = section[0] 
     277                entrytext = title 
     278                try: 
     279                    reference = nodes.reference('', '', 
     280                            refid=section['ids'][0], *entrytext) 
     281                except IndexError: 
     282                    continue 
     283                ref_id = self.document.set_id(reference) 
     284                entry = nodes.paragraph('', '', reference) 
     285                item = nodes.list_item('', entry) 
     286                if level < depth: 
     287                    subsects = self.build_contents(section, level) 
     288                    item += subsects 
     289                entries.append(item) 
     290            if entries: 
     291                contents = nodes.bullet_list('', *entries) 
     292                return contents 
     293            else: 
     294                return [] 
     295 
     296    return DjangoHTMLWriter() 
  • docs/css/docs.css

    old new  
     1/*  
     2djangoproject.com by Wilson Miner (wilson@lawrence.com) 
     3Copyright (c) 2005 Lawrence Journal-World. Please don't steal. 
     4*/ 
     5 
     6 
     7/* SETUP */ 
     8 
     9body { margin:0; padding:0; background:#092e20; color:white; } 
     10body, th, td { font:12px/1.4em Verdana,sans-serif; } 
     11#container { position:relative; min-width:55em; max-width:100em; } 
     12#homepage #container { max-width:100em; } 
     13 
     14/* LINKS */ 
     15 
     16a {text-decoration: none;} 
     17a img {border: none;} 
     18a:link, a:visited { color:#ffc757; } 
     19#content-main a:link, #content-main a:visited { color:#ab5603; text-decoration:underline; } 
     20#content-secondary a:link, #content-secondary a:visited { color:#ffc757; text-decoration:none; } 
     21a:hover { color:#ffe761; } 
     22#content-main a:hover { background-color:#E0FFB8; color:#234f32; text-decoration:none; } 
     23#content-secondary a:hover { color:#ffe761; background:none; } 
     24#content-main h2 a, #content-main h3 a { text-decoration:none !important; } 
     25 
     26/* HEADER */ 
     27 
     28#header { position:relative; height:6.5em; background:#092e20; } 
     29#header h1#logo { margin:0; width:111px; height:41px; position:absolute; bottom:10px; left:25px; } 
     30 
     31/* NAV */ 
     32 
     33#nav-global { position:absolute; margin:0; bottom:0; right:0; font-family:"Trebuchet MS",sans-serif; white-space:nowrap; } 
     34#nav-global li { display:block; float:left; list-style-type:none; margin:0; padding:0; } 
     35#nav-global a { display:block; float:left; padding:5em 16px 10px 16px; background:#092e20; } 
     36#nav-global a:hover { color:white; background:#234f32; } 
     37#homepage #nav-homepage a, #overview #nav-overview a, #download #nav-download a, #documentation #nav-documentation a, #weblog #nav-weblog a, #community #nav-community a, #blogroll #nav-blogroll a, #code #nav-code a { color:white; background:#092e20 url(../img/site/nav_bg.gif) bottom repeat-x; } 
     38 
     39/* COLUMNS */ 
     40 
     41#columnwrap { background:#234f32; padding-bottom:10px; } 
     42#subwrap { background:#326342; width:73%; float:left; padding-bottom:10px; } 
     43#content-main { float:left; width:70%; background:white; color:black; padding-bottom:10px; } 
     44#generic #content-main, #code #content-main { width:100%; } 
     45#content-main * { margin-left:22px; margin-right:24px; } 
     46#content-main * * { margin-left:0; margin-right:0; } 
     47.sidebar { font-size:92%; } 
     48.sidebar * { margin-left:14px; margin-right:14px; } 
     49.sidebar * * { margin-left:0; margin-right:0; } 
     50#content-extra { float:right; width:27%; } 
     51#content-related { float:right; width:30%;} 
     52#content-secondary { clear:both; background:#487858; margin-left:0; margin-right:0; margin-top:15px; margin-bottom:-10px; padding:10px 24px; color:white; } 
     53.subcol-primary, .subcol-secondary { width:40%; float:left; padding-bottom:1.2em; } 
     54.subcol-primary { margin-right:1%; } 
     55 
     56/* CONTENT */ 
     57 
     58h1,h2,h3 { margin-top:.8em; font-family:"Trebuchet MS",sans-serif; font-weight:normal; } 
     59h1 { font-size:218%; margin-top:.6em; margin-bottom:.6em; color:#092e20; line-height:1.1em; } 
     60h2 { font-size:150%; margin-top:1em; margin-bottom:.2em; line-height:1.2em; color:#092e20; } 
     61#homepage h2 { font-size:140%; } 
     62h3 { font-size:125%; font-weight:bold; margin-bottom:.2em; color:#487858; } 
     63h4 { font-size:100%; font-weight:bold; margin-bottom:-3px; margin-top:1.2em; text-transform:uppercase; letter-spacing:1px; } 
     64h4 pre, h4 tt, h4 .literal { text-transform:none; } 
     65h5 { font-size:1em; font-weight:bold; margin-top:1.5em; margin-bottom:3px; } 
     66p, ul, dl { margin-top:.6em; margin-bottom:.8em; } 
     67hr { color:#ccc; background-color:#ccc; height:1px; border:0; } 
     68p.date { color:#487858; margin-top:-.2em; } 
     69p.more { margin-top:-.4em; } 
     70.sidebar p.date { color:#90ba9e; } 
     71#content-secondary h2, .sidebar h2 { color:white; } 
     72#content-secondary h3, .sidebar h3 { color:#9aef3f; } 
     73#content-secondary h2:first-child { margin-top:.6em; } 
     74.sidebar h2:first-child { margin-top:.8em; } 
     75#content-main h2, #content-main h3 { margin-top:1.2em; } 
     76h2.deck { margin-top:-.5em !important; margin-bottom:.6em; color:#487858; } 
     77ins { text-decoration: none; } 
     78ins a { text-decoration: none; } 
     79 
     80/* LISTS */ 
     81 
     82ul { padding-left:2em; } 
     83ol { padding-left:30px; } 
     84ul li { list-style-type:square; margin-bottom:.4em; } 
     85ul ul { padding-left:1.2em; } 
     86ul ul ul { padding-left:1em; } 
     87ul.linklist, ul.toc { padding-left:0; } 
     88ul.toc ul { margin-left:.6em; } 
     89ul.toc ul li { list-style-type:square; } 
     90ul.toc ul ul li { list-style-type:disc; } 
     91ul.linklist li, ul.toc li { list-style-type:none; } 
     92dt { font-weight:bold; margin-top:.5em; font-size:1.1em; } 
     93dd { margin-bottom:.8em; } 
     94 
     95/*  RSS  */ 
     96 
     97a.rss { font:bold 10px Verdana, sans-serif; padding:0 .2em; border: 1px solid; text-decoration:none; background:#f60;color: #fff; border-color:#ffc8a4 #7d3302 #3f1a01 #ff9a57; margin:0 3px; vertical-align:middle; } 
     98#content-main a.rss { color:#fff; text-decoration:none; } 
     99a.rss:hover, a.rss:link, a.rss:visited { color:#fff; text-decoration:none; } 
     100 
     101/* BLOCKQUOTES */ 
     102 
     103#weblog blockquote { padding-left:0.8em; padding-right:1em; font:125%/1.2em "Trebuchet MS", sans-serif; color:#234f32; border-left:2px solid #94da3a; } 
     104.sidebar blockquote { margin-top:1.5em; margin-bottom:1.5em; } 
     105.sidebar blockquote p { font:italic 175%/1.2em "Trebuchet MS",sans-serif; color:#94da3a; } 
     106.sidebar blockquote cite { display:block; font-style:normal; line-height:1.2em; margin-top:-.8em; color:#94da3a; } 
     107.sidebar cite strong { font-weight:normal; color:white; } 
     108 
     109/* CODE BLOCKS */ 
     110 
     111.literal { white-space:nowrap; } 
     112.literal, .literal-block { color:#234f32; } 
     113.sidebar .literal { color:white; background:transparent; font-size:11px; } 
     114pre, .literal-block { font-size:medium; background:#E0FFB8; border:1px solid #94da3a; border-width:1px 0; margin: 1em 0; padding: .3em .4em; overflow: auto; } 
     115dt .literal, table .literal { background:none; } 
     116textarea.codedump { font-size:10px; color:#234f32; width:100%; background:#E0FFB8; border:1px solid #94da3a; border-width:1px 0; padding: .3em .4em; } 
     117 
     118/* NOTES & ADMONITIONS */ 
     119 
     120.note, .admonition, .caution { padding:.8em 1em .8em; margin: 1em 0; border:1px solid #94da3a; } 
     121.admonition-title { font-weight:bold; margin-top:0 !important; margin-bottom:0 !important;} 
     122.admonition .last { margin-bottom:0 !important; } 
     123.admonition-philosophy { padding-left:65px; background:url(../img/doc/icons/docicons-philosophy.gif) .8em .8em no-repeat;} 
     124.admonition-note, .caution { padding-left:65px; background:url(../img/doc/icons/docicons-note.gif) .8em .8em no-repeat;} 
     125.admonition-behind-the-scenes { padding-left:65px; background:url(../img/doc/icons/docicons-behindscenes.gif) .8em .8em no-repeat;} 
     126 
     127/* DOCS */ 
     128 
     129#documentation h2, #documentation h3, #documentation h4 { margin-top:1.4em; } 
     130#documentation dd { margin-left:1em; } 
     131#content-main table { color:#000; } 
     132table.docutils { border-collapse:collapse; } 
     133table.docutils thead th { border-bottom:2px solid #dfdfdf; text-align:left; } 
     134table.docutils td, table.docutils th { border-bottom:1px solid #dfdfdf; padding:4px 2px;} 
     135table.docutils td p { margin-top:0; margin-bottom:.5em; } 
     136#documentation #content-related .literal { background:transparent !important; } 
     137 
     138/* BILLBOARDS */ 
     139 
     140#billboard { background:#94da3a url(../img/site/bbdsm_bg.gif) repeat-x; border-bottom:6px solid #092e20; } 
     141#billboard h2 { margin:0; } 
     142#generic #billboard { display:none; } 
     143#homepage #billboard { background-image: url(../img/site/bbd_bg.gif); } 
     144#homepage #billboard h2 { margin:0; text-indent:-5000px; height:80px; width:633px; background:url(../img/site/bbd_homepage.gif) no-repeat; } 
     145#overview #billboard h2 { margin:0; text-indent:-5000px; height:60px; width:203px; background:url(../img/site/bbd_overview.gif) no-repeat; } 
     146#download #billboard h2 { margin:0; text-indent:-5000px; height:60px; width:203px; background:url(../img/site/bbd_download.gif) no-repeat; } 
     147#documentation #billboard h2 a { display:block; margin:0; text-indent:-5000px; height:60px; width:226px; background:url(../img/site/bbd_documentation.gif) no-repeat; } 
     148#weblog #billboard h2 a { display:block; margin:0; text-indent:-5000px; height:60px; width:226px; background:url(../img/site/bbd_weblog.gif) no-repeat; } 
     149#community #billboard h2 { display:block; margin:0; text-indent:-5000px; height:60px; width:226px; background:url(../img/site/bbd_community.gif) no-repeat; } 
     150#blogroll #billboard h2 { display:block; margin:0; text-indent:-5000px; height:60px; width:168px; background:url(../img/site/bbd_blogroll.gif) no-repeat; } 
     151#code #billboard h2 a { display:block; margin:0; text-indent:-5000px; height:60px; width:184px; background:url(../img/site/bbd_code.gif) no-repeat; } 
     152 
     153/* FOOTER */ 
     154 
     155#footer { clear:both; color:#487858; padding:10px 20px; font-size:90%; } 
     156 
     157/* COMMENTS */ 
     158 
     159.comment { margin:15px 0; } 
     160div.comment p { margin-left:1em; } 
     161#weblog div.comment p.date { margin-bottom:.2em; color:#94da3a; } 
     162 
     163/* MISC */ 
     164 
     165.small { font-size:90%; } 
     166h3 .small { font-size:80%; } 
     167.quiet { font-weight:normal; } 
     168.clear { clear:both; } 
     169#content-main .quiet { color:#487858; } 
     170#content-secondary .quiet { color:#90ba9e; } 
     171 
     172/*  CLEARFIX KLUDGE */ 
     173 
     174#columnwrap:after { 
     175    content: ".";  
     176    display: block;  
     177    height: 0;  
     178    clear: both;  
     179    visibility: hidden; 
     180} 
     181#columnwrap { display: inline-block; } 
     182 
     183/* Hides from IE-mac \*/ 
     184* html #columnwrap { height: 1%; } 
     185#columnwrap { display: block; } 
     186/* End hide from IE-mac */ 
     187 
     188#subwrap:after { 
     189    content: ".";  
     190    display: block;  
     191    height: 0;  
     192    clear: both;  
     193    visibility: hidden; 
     194} 
     195#subwrap { display: inline-block; } 
     196 
     197/* Hides from IE-mac \*/ 
     198* html #subwrap { height: 1%; } 
     199#subwrap { display: block; } 
     200/* End hide from IE-mac */om IE-mac */ 
  • docs/django-admin.txt

    old new  
    199199 
    200200    django-admin.py flush --verbosity=2 
    201201 
     202htmldocs docdir outdir 
     203---------------------- 
     204 
     205Converts Django documentation to HTML. Uses the given Django documentation 
     206directory ``docdir`` for reading documentation source and output directory 
     207``outdir`` (creating it if necessary) for writing HTML files. Writes multiple 
     208HTML files, i.e. one HTML file per documentation file by default. 
     209 
     210--single 
     211~~~~~~~~~~~ 
     212 
     213Creates a single combined HTML file. Not recommended, produces output that is 
     214harder to navigate and more than 1.8 MB large. 
     215 
     216Example usage:: 
     217 
     218    django-admin.py htmldocs trunk/docs django_docs --single 
     219 
    202220inspectdb 
    203221--------- 
    204222