|
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 |
|
8 them to be stored in the database. I want to be able create File/Image entities |
|
9 for some files on the server file system, where those file will be accessed to |
|
10 get entities data. To do so I've to set a custom :class:`BytesFileSystemStorage` storage |
|
11 for the File/Image '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 storage |
|
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 set_attribute_storage(self.repo, 'File', 'data', storage) |
|
36 set_attribute_storage(self.repo, 'Image', 'data', storage) |
|
37 |
|
38 .. Note:: |
|
39 |
|
40 * how we built the hook's registry identifier (_`_regid__`): you can introduce |
|
41 'namespaces' by using there python module like naming identifiers. This is |
|
42 especially import for hooks where you usually want a new custom hook, not |
|
43 overriding / specializing an existant one, but the concept may be applied to |
|
44 any application objects |
|
45 |
|
46 * we catch two events here: "server_startup" and "server_maintenance". The first |
|
47 is called on regular repository startup (eg, as a server), the other for |
|
48 maintenance task such as shell or upgrade. In both cases, we need to have |
|
49 the storage set, else we'll be in trouble... |
|
50 |
|
51 * the path given to the storage is the place where file added through the ui |
|
52 (or in the database before migration) will be located |
|
53 |
|
54 * be ware that by doing this, you can't anymore write queries that will try to |
|
55 restrict on File and Image `data` attribute. Hopefuly we don't do that usually |
|
56 on file's content or more generally on attributes for the Bytes type |
|
57 |
|
58 Now, if you've already added some photos through the web ui, you'll have to |
|
59 migrate existing data so file's content will be stored on the file-system instead |
|
60 of the database. There is a migration command to do so, let's run it in the |
|
61 cubicweb shell (in actual life, you'd have to put it in a migration script as we |
|
62 seen last time): |
|
63 |
|
64 :: |
|
65 |
|
66 $ cubicweb-ctl shell sytweb |
|
67 entering the migration python shell |
|
68 just type migration commands or arbitrary python code and type ENTER to execute it |
|
69 type "exit" or Ctrl-D to quit the shell and resume operation |
|
70 >>> storage_changed('File', 'data') |
|
71 [........................] |
|
72 >>> storage_changed('Image', 'data') |
|
73 [........................] |
|
74 |
|
75 |
|
76 That's it. Now, file added through the web ui will have their content stored on |
|
77 the file-system, and you'll also be able to import files from the file-system as |
|
78 explained in the next part. |
|
79 |
|
80 Step 2: importing some data into the instance |
|
81 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
82 |
|
83 Hey, we start to have some nice features, let give us a try on this new web |
|
84 site. For instance if I have a 'photos/201005WePyrenees' containing pictures for |
|
85 a particular event, I can import it to my web site by typing :: |
|
86 |
|
87 $ cubicweb-ctl fsimport -F sytweb photos/201005WePyrenees/ |
|
88 ** importing directory /home/syt/photos/201005WePyrenees |
|
89 importing IMG_8314.JPG |
|
90 importing IMG_8274.JPG |
|
91 importing IMG_8286.JPG |
|
92 importing IMG_8308.JPG |
|
93 importing IMG_8304.JPG |
|
94 |
|
95 .. Note:: |
|
96 The -F option tell that folders should be mapped, hence my photos will be |
|
97 all under a Folder entity corresponding to the file-system folder. |
|
98 |
|
99 Let's take a look at the web ui: |
|
100 |
|
101 .. image:: ../../images/tutos-photowebsite_ui1.png |
|
102 |
|
103 Nothing different, I can't see the new folder... But remember our security model! |
|
104 By default, files are only accessible to authenticated users, and I'm looking at |
|
105 the site as anonymous, e.g. not authenticated. If I login, I can now see: |
|
106 |
|
107 .. image:: ../../images/tutos-photowebsite_ui2.png |
|
108 |
|
109 Yeah, it's there! You can also notice that I can see some entities as well as |
|
110 folders and images the anonymous user can't. It just works **everywhere in the |
|
111 ui** since it's handled at the repository level, thanks to our security model. |
|
112 |
|
113 Now if I click on the newly inserted folder, I can see |
|
114 |
|
115 .. image:: ../../images/tutos-photowebsite_ui3.png |
|
116 |
|
117 Great! There is even my pictures in the folder. I can know give to this folder a |
|
118 nicer name (provided I don't intend to import from it anymore, else already |
|
119 imported photos will be reimported), change permissions, title for some pictures, |
|
120 etc... Having a good content is much more difficult than having a good web site |
|
121 ;) |
|
122 |
|
123 |
|
124 Conclusion |
|
125 ~~~~~~~~~~ |
|
126 |
|
127 We started to see here an advanced feature of our repository: the ability |
|
128 to store some parts of our data-model into a custom storage, outside the |
|
129 database. There is currently only the :class:`BytesFileSystemStorage` available, |
|
130 but you can expect to see more coming in a near future (our write your own!). |
|
131 |
|
132 Also, we can know start to feed our web-site with some nice pictures! |
|
133 The site isn't perfect (far from it actually) but it's usable, and we can |
|
134 now start using it and improve it on the way. The Incremental Cubic Way :) |