doc/book/en/tutorials/advanced/part03_bfss.rst
changeset 10491 c67bcee93248
parent 10490 76ab3c71aff2
child 10492 68c13e0c0fc5
equal deleted inserted replaced
10490:76ab3c71aff2 10491:c67bcee93248
     1 Storing images on the file-system
       
     2 ---------------------------------
       
     3 
       
     4 Step 1: configuring the BytesFileSystem storage
       
     5 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       
     6 
       
     7 To avoid cluttering my database, and to ease file manipulation, I don't want them
       
     8 to be stored in the database. I want to be able create File entities for some
       
     9 files on the server file system, where those file will be accessed to get
       
    10 entities data. To do so I've to set a custom :class:`BytesFileSystemStorage`
       
    11 storage for the File 'data' attribute, which hold the actual file's content.
       
    12 
       
    13 Since the function to register a custom storage needs to have a repository
       
    14 instance as first argument, we've to call it in a server startup hook. So I added
       
    15 in `cubes/sytweb/hooks.py` :
       
    16 
       
    17 .. sourcecode:: python
       
    18 
       
    19     from os import makedirs
       
    20     from os.path import join, exists
       
    21 
       
    22     from cubicweb.server import hook
       
    23     from cubicweb.server.sources import storages
       
    24 
       
    25     class ServerStartupHook(hook.Hook):
       
    26         __regid__ = 'sytweb.serverstartup'
       
    27         events = ('server_startup', 'server_maintenance')
       
    28 
       
    29         def __call__(self):
       
    30             bfssdir = join(self.repo.config.appdatahome, 'bfss')
       
    31             if not exists(bfssdir):
       
    32                 makedirs(bfssdir)
       
    33                 print 'created', bfssdir
       
    34             storage = storages.BytesFileSystemStorage(bfssdir)
       
    35             storages.set_attribute_storage(self.repo, 'File', 'data', storage)
       
    36 
       
    37 .. Note::
       
    38 
       
    39   * how we built the hook's registry identifier (`__regid__`): you can introduce
       
    40     'namespaces' by using there python module like naming identifiers. This is
       
    41     especially important for hooks where you usually want a new custom hook, not
       
    42     overriding / specializing an existant one, but the concept may be applied to
       
    43     any application objects
       
    44 
       
    45   * we catch two events here: "server_startup" and "server_maintenance". The first
       
    46     is called on regular repository startup (eg, as a server), the other for
       
    47     maintenance task such as shell or upgrade. In both cases, we need to have
       
    48     the storage set, else we'll be in trouble...
       
    49 
       
    50   * the path given to the storage is the place where file added through the ui
       
    51     (or in the database before migration) will be located
       
    52 
       
    53   * beware that by doing this, you can't anymore write queries that will try to
       
    54     restrict on File `data` attribute. Hopefuly we don't do that usually
       
    55     on file's content or more generally on attributes for the Bytes type
       
    56 
       
    57 Now, if you've already added some photos through the web ui, you'll have to
       
    58 migrate existing data so file's content will be stored on the file-system instead
       
    59 of the database. There is a migration command to do so, let's run it in the
       
    60 cubicweb shell (in real life, you would have to put it in a migration script as we
       
    61 have seen last time):
       
    62 
       
    63 ::
       
    64 
       
    65    $ cubicweb-ctl shell sytweb_instance
       
    66    entering the migration python shell
       
    67    just type migration commands or arbitrary python code and type ENTER to execute it
       
    68    type "exit" or Ctrl-D to quit the shell and resume operation
       
    69    >>> storage_changed('File', 'data')
       
    70    [........................]
       
    71 
       
    72 
       
    73 That's it. Now, files added through the web ui will have their content stored on
       
    74 the file-system, and you'll also be able to import files from the file-system as
       
    75 explained in the next part.
       
    76 
       
    77 Step 2: importing some data into the instance
       
    78 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       
    79 
       
    80 Hey, we start to have some nice features, let us give a try to this new web
       
    81 site. For instance if I have a 'photos/201005WePyrenees' containing pictures for
       
    82 a particular event, I can import it to my web site by typing ::
       
    83 
       
    84   $ cubicweb-ctl fsimport -F sytweb_instance photos/201005WePyrenees/
       
    85   ** importing directory /home/syt/photos/201005WePyrenees
       
    86   importing IMG_8314.JPG
       
    87   importing IMG_8274.JPG
       
    88   importing IMG_8286.JPG
       
    89   importing IMG_8308.JPG
       
    90   importing IMG_8304.JPG
       
    91 
       
    92 .. Note::
       
    93   The -F option means that folders should be mapped, hence my photos will be
       
    94   linked to a Folder entity corresponding to the file-system folder.
       
    95 
       
    96 Let's take a look at the web ui:
       
    97 
       
    98 .. image:: ../../images/tutos-photowebsite_ui1.png
       
    99 
       
   100 Nothing different, I can't see the new folder... But remember our security model!
       
   101 By default, files are only accessible to authenticated users, and I'm looking at
       
   102 the site as anonymous, e.g. not authenticated. If I login, I can now see:
       
   103 
       
   104 .. image:: ../../images/tutos-photowebsite_ui2.png
       
   105 
       
   106 Yeah, it's there! You will notice that I can see some entities as well as
       
   107 folders and images the anonymous user can't. It just works **everywhere in the
       
   108 ui** since it's handled at the repository level, thanks to our security model.
       
   109 
       
   110 Now if I click on the recently inserted folder, I can see
       
   111 
       
   112 .. image:: ../../images/tutos-photowebsite_ui3.png
       
   113 
       
   114 Great! There is even my pictures in the folder. I can know give to this folder a
       
   115 nicer name (provided I don't intend to import from it anymore, else already
       
   116 imported photos will be reimported), change permissions, title for some pictures,
       
   117 etc... Having a good content is much more difficult than having a good web site
       
   118 ;)
       
   119 
       
   120 
       
   121 Conclusion
       
   122 ~~~~~~~~~~
       
   123 
       
   124 We started to see here an advanced feature of our repository: the ability
       
   125 to store some parts of our data-model into a custom storage, outside the
       
   126 database. There is currently only the :class:`BytesFileSystemStorage` available,
       
   127 but you can expect to see more coming in a near future (or write your own!).
       
   128 
       
   129 Also, we can know start to feed our web-site with some nice pictures!
       
   130 The site isn't perfect (far from it actually) but it's usable, and we can
       
   131 now start using it and improve it on the way. The Incremental Cubic Way :)