database.rst 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. .. MediaGoblin Documentation
  2. Written in 2013 by MediaGoblin contributors
  3. To the extent possible under law, the author(s) have dedicated all
  4. copyright and related and neighboring rights to this software to
  5. the public domain worldwide. This software is distributed without
  6. any warranty.
  7. You should have received a copy of the CC0 Public Domain
  8. Dedication along with this software. If not, see
  9. <http://creativecommons.org/publicdomain/zero/1.0/>.
  10. .. _plugin-database-chapter:
  11. ===========================
  12. Database models for plugins
  13. ===========================
  14. Accessing Existing Data
  15. =======================
  16. If your plugin wants to access existing data, this is quite
  17. straight forward. Just import the appropiate models and use
  18. the full power of SQLAlchemy. Take a look at the (upcoming)
  19. database section in the Developer's Chapter.
  20. Creating new Tables
  21. ===================
  22. If your plugin needs some new space to store data, you
  23. should create a new table. Please do not modify core
  24. tables. Not doing so might seem inefficient and possibly
  25. is. It will help keep things sane and easier to upgrade
  26. versions later.
  27. So if you create a new plugin and need new tables, create a
  28. file named ``models.py`` in your plugin directory. You
  29. might take a look at the core's db.models for some ideas.
  30. Here's a simple one:
  31. .. code-block:: python
  32. from mediagoblin.db.base import Base
  33. from sqlalchemy import Column, Integer, Unicode, ForeignKey
  34. class MediaSecurity(Base):
  35. __tablename__ = "yourplugin__media_security"
  36. # The primary key *and* reference to the main media_entry
  37. media_entry = Column(Integer, ForeignKey('core__media_entries.id'),
  38. primary_key=True)
  39. get_media_entry = relationship("MediaEntry",
  40. backref=backref("security_rating", cascade="all, delete-orphan"))
  41. rating = Column(Unicode)
  42. MODELS = [MediaSecurity]
  43. Next, you need to make an initial migration. MediaGoblin uses
  44. `Alembic's branching model <http://alembic.readthedocs.org/en/latest/branches.html>`_
  45. to handle plugins adding their own content. As such, when you are
  46. adding a new plugin, you need to add an initial migration adding
  47. the existing models, and migrate from there.
  48. You'll need to make a `migrations` subdirectory for migrations and put
  49. your migrations there. If you want to look at some example
  50. migrations, look at `mediagoblin/media_types/image/migrations/`,
  51. especially the "initial" migration. (Plugin authors with plugins that
  52. existed prior to the alembic switchover: you might notice how it
  53. checks for the table and skips the migration if it already exists.
  54. Plugin authors writing brand new plugins, post-Alembic migration
  55. switchover, do not need to do this.)
  56. Unfortunately, these migrations are a bit tedious to write.
  57. Fortunately, Alembic can do much of the work for us! After adding the
  58. models.py file, run this command (switching out YOUR_PLUGIN_NAME of
  59. course)::
  60. ./bin/gmg alembic --with-plugins revision \
  61. --splice --autogenerate \
  62. --branch-label YOUR_PLUGIN_NAME_plugin \
  63. -m "YOUR_PLUGIN_NAME plugin initial migration"
  64. (Note that `--with-plugins` *must* come before any alembic subcommand...
  65. this is a quirk related to the way we handle alembic command dispatching
  66. with the gmg subcommand!)
  67. This will dump your migration into "the wrong place" (it'll dump it
  68. into the MediaGoblin core migrations directory), so you should move it
  69. to your plugin's migrations directory. Open the file and make adjustments
  70. accordingly!
  71. Some notes:
  72. * Make sure all your ``__tablename__`` start with your
  73. plugin's name so the tables of various plugins can't
  74. conflict in the database. (Conflicts in python naming are
  75. much easier to fix later).
  76. * Try to get your database design as good as possible in
  77. the first attempt. Changing the database design later,
  78. when people already have data using the old design, is
  79. possible (see next chapter), but it's not easy.
  80. Changing the Database Schema Later
  81. ==================================
  82. If your plugin is in use and instances use it to store some data,
  83. changing the database design is tricky and must be done with care,
  84. but is not impossible.
  85. Luckily, Alembic can once again help with autogenerating what is
  86. probably very close to the migration you want. First you will need to
  87. find out what the revision id of your plugin's most recent migrations
  88. is. There are two ways to do this: look in your plugin's migrations/
  89. directory and figure it out with the hope that it's "obvious" in some
  90. way. The second path: let Alembic give that info for you.
  91. Assuming you've already done the latest dbupdate with your plugin
  92. enabled, do the following:
  93. ./bin/gmg alembic --with-plugins heads
  94. You should see the latest migration id for your plugin's label.
  95. Make changes to your
  96. plugin's models.py and then run::
  97. ./bin/gmg alembic --with-plugins revision \
  98. --head REVISION_HERE \
  99. --autogenerate \
  100. -m "YOUR_PLUGIN_NAME: Change explaination here."
  101. Once again, this will dump the migration into the wrong place, so move
  102. to your plugin's migrations directory. Open the file, adjust
  103. accordingly, and read carefully! Now you should also test your
  104. migration with some real data. Be sure to test it both on sqlite
  105. *AND* on postgresql!
  106. One last *very critical* note: you must never, never modify core
  107. tables with your plugin. To do that is to put you and all your users
  108. in a dangerous situation. Add data to the database by adding new tables
  109. under the control of your plugin, but never ever modify anyone else's!
  110. Whew, you made it! Get yourself a cookie to celebrate!