root / elixir / trunk / docs / tutorial.rst @ 59

Revision 59, 8.4 kB (checked in by ged, 8 years ago)

updated website now that we are easy installable

Line 
1========
2Tutorial
3========
4
5.. CHECKME: this is not rendered?
6
7---------
8Diving in
9---------
10
111. Installation
12---------------
13       
14In this tutorial, we will show you how to create a small and simple model.
15Before we start please make sure that you already have the Elixir package
16installed. If not, do so by typing [#]_:
17 
18 ::
19 
20     easy_install Elixir
21 
22 .. [#] If you don't even have "``easy_install``" yet, please visit the
23        `EasyInstall website
24        <http://peak.telecommunity.com/DevCenter/EasyInstall>`_ first and find
25        out how to use it (it's pretty easy, like the name promises).
26
272. A very simple model
28----------------------
29
30Now fire up your favorite text editor and create a file "``model.py``"
31containing the following lines:
32
33::
34
35    from elixir import *
36
37    metadata.connect("sqlite:///movies.sqlite")
38
39    class Movie(Entity):
40        with_fields(
41            title = Field(Unicode(30)),
42            year = Field(Integer),
43            description = Field(Unicode)
44        )
45       
46        def __repr__(self):
47            return '<Movie "%s" (%d)>' % (self.title, self.year)
48
49
50What does this snippet do? First of all it connects to an SQLite-database
51[#]_. Then it declares a ``Movie``-entity (ie. a class, that inherits Elixir's
52``Entity``-baseclass). This entity will hold three fields:
53
54- ``title``: holds up to 30 unicode chars, which represent the movie's title
55- ``year``:  an integer containing the year the movie was released
56- ``description``: this could be a plot summary, a review, or any long string
57  of text that you like.
58
59The ``__repr__()``-method below is totally unrelated to Elixir, it just tells
60the python interpreter to print objects in a human-readable way. It's nice to
61have, but fully optional.  We have put this into our model so that we can
62easily trace what is happening in an interactive python interpreter.
63
64Also, please note that elixir currently provide two different ways to declare
65the fields on your entities. We have not decided yet on which one we like best,
66or if we will always keep both. The other way to declare your fields is using
67the ``has_field`` statement, rather than the ``with_fields`` statement.  The
68``Movie`` example above can be declared using the ``has_field`` statement like
69so:
70
71::
72
73    from elixir import *
74
75    metadata.connect("sqlite:///movies.sqlite")
76
77    class Movie(Entity):
78        has_field('title', Unicode(30))
79        has_field('year', Integer)
80        has_field('description', Unicode)
81       
82        def __repr__(self):
83            return '<Movie "%s" (%d)>' % (self.title, self.year)
84
85
86If you have a strong preference for one syntax over the other, please let us
87know so that we can make a good decision before our final stable release!
88
89
90.. [#] This assumes you have `pysqlite <http://pysqlite.org/>`_
91       installed. You may use any other database instead, as long as it's
92       `supported by SQLAlchemy <http://www.sqlalchemy.org/features.myt>`_.
93
94
953. Action!
96----------
97
98What time is it? It's database-table-creation-time! Fire up your python
99interpreter of choice (preferably `IPython <http://ipython.scipy.org/>`_) and
100hack in the lines below [#]_ (only lines starting with "``>>>``", of course):
101
102::
103
104    >>> from model import *
105    >>> create_all()
106    >>> Movie(title="Blade Runner", year=1982)
107    <Movie "Blade Runner" (1982)>
108   
109You've created all necessary tables by executing ``create_all()`` and then
110instantiated a first movie-object. You could add more movies here, but so far
111"Blade Runner" does the job.
112
113Because SQLAlchemy tries to do as many operations as possible in one single
114operation (a so called `Unit of Work`), which is very efficient, the data has
115not been written to the database table yet. You can tell SQLAlchemy to do so
116by typing:
117
118::
119
120    >>> objectstore.flush()
121
122This will tell SQLAlchemy to generate all of the SQL to insert the Movie into
123the database, and then execute that SQL. Now, to see a list of all the movies
124in our database, simply type:
125
126::
127
128    >>> Movie.select()
129    [<Movie "Blade Runner" (1982)>]
130
131Not many, but exactly what we expected. Close the interpreter now and delete
132[#]_ the database file (``movies.sqlite``), we will recreate and populate it
133in the next step.
134   
135.. [#] Make sure, you're running your interpreter from the directory where you
136       saved the ``model.py`` file.
137.. [#] If you're using any other DBMS than SQLite, just drop the created table
138       (most probably something like ``DROP TABLE model_movie;``).
139
1404. Relationships
141----------------
142
143So far you've seen how to declare simple entities, create objects, store them
144to the database and retrieve them again. Not too much magic, but a lot more
145pleasant to the eye compared to calling lowlevel SQL-statements.
146
147Now we will do something more advanced. Movies need genres, so we'll add a new
148entity "``Genre``" to our ``model.py``:
149
150::
151
152    class Genre(Entity):
153        with_fields(
154            name = Field(Unicode(15), unique=True)
155        )
156       
157        def __repr__(self):
158            return '<Genre "%s">' % self.name
159
160The ``__repr__()``-method is totally optional, again. We're limiting the
161length of our genres to 15 characters and demand that those names are
162unique. There's no use in having two genres with the same name, right?
163
164We could start the interpreter again and instantiate some genres, but before
165we do that, we want to tell Elixir how to relate movies and genres to add more
166excitement. Add two lines to your ``model.py``, so it reads:
167
168::
169
170    class Movie(Entity):
171        with_fields(
172            title = Field(Unicode(30)),
173            year = Field(Integer),
174            description = Field(Unicode)
175        )
176       
177        belongs_to('genre', of_kind='Genre')                # add this line
178   
179        def __repr__(self):
180            return '<Movie "%s" (%d)>' % (self.title, self.year)
181   
182   
183    class Genre(Entity):
184        with_fields(
185            name = Field(Unicode(15))
186        )
187       
188        has_many('movies', of_kind='Movie')                 # and this one
189       
190        def __repr__(self):
191            return '<Genre "%s">' % self.name
192
193A movie belongs to a genre and a genre may have many movies, that's what it
194says. We could let movies have multiple genres by changing the ``belongs_to``-
195and ``has_many``-statements in both lines to ``has_and_belongs_to_many``, but
196one genre per movie is enough for our example.
197
198Again, start your python interpreter, ensure that the old database table has
199been deleted, and then create your new model's tables:
200
201::
202   
203    >>> from model import *
204    >>> create_all()
205
206Create a genre and a couple of titles:
207
208::
209
210    >>> scifi = Genre(name="Science-Fiction")
211    >>> alien = Movie(title="Alien", year=1979)
212    >>> starwars = Movie(title="Star Wars", year=1977)
213    >>> brunner = Movie(title="Blade Runner", year=1982)
214
215Now add the movies to the genre (just like you'd do if it was a plain old
216python list), and flush the objectstore:
217
218::
219
220    >>> scifi.movies.append(alien)
221    >>> scifi.movies.append(starwars)
222    >>> scifi.movies.append(brunner)
223    >>> objectstore.flush()
224
225Let's demonstrate some magic now, enter these two lines:
226
227::
228
229    >>> m = Movie.get_by(title="Alien")
230    >>> m.title, m.genre
231    ('Alien', <Genre "Science-Fiction">)
232   
233As you can see, all the dirty work has been done for you - automatically and
234out of your way. Primary [#]_ and foreign keys have been generated
235automatically, and if you'd used ``has_and_belongs_to_many``, even the
236necessary secondary tables.
237
238.. [#] If you don't specify any primary keys by passing ``primary_key=True``
239       as a keyword-argument to the ``Field()``-construct, Elixir will
240       automatically create one for you, which will then be accessible under
241       the name ``id``.
242
243
2445. Where to go from here?
245-------------------------
246
247You have created a simple model with some entities and set up some
248relationships between them. Now that you've seen how it basically works, take
249a closer look at Elixir's `API-docs <module-index.html>`_, `examples
250<examples.html>`_ and `testcases
251<http://elixir.ematia.de/svn/elixir/trunk/tests/>`_, which come with the
252source distribution, and see how to create other types of relationships and
253fine tweak Elixir's options to your liking.
254
255To learn more about the available datatypes, how to retrieve and modify data
256and about lower level features please consult `SQLAlchemy's detailed
257documentation <http://www.sqlalchemy.org/docs/>`_.
258
259Enjoy database development the easy way and let us know when you created
260something cool!
261
262
Note: See TracBrowser for help on using the browser.