Peter Justin 7 лет назад
Родитель
Сommit
6cfc1830d1

+ 38 - 28
flaskbb/forum/models.py

@@ -27,30 +27,33 @@ logger = logging.getLogger(__name__)
 
 moderators = db.Table(
     'moderators',
-    db.Column('user_id', db.Integer(), db.ForeignKey('users.id'),
+    db.Column('user_id', db.Integer(),
+              db.ForeignKey('users.id', ondelete="CASCADE"),
               nullable=False),
     db.Column('forum_id', db.Integer(),
-              db.ForeignKey('forums.id', use_alter=True,
+              db.ForeignKey('forums.id', use_alter=True, ondelete="CASCADE",
                             name="fk_mods_forum_id"),
               nullable=False))
 
 
 topictracker = db.Table(
     'topictracker',
-    db.Column('user_id', db.Integer(), db.ForeignKey('users.id'),
+    db.Column('user_id', db.Integer(),
+              db.ForeignKey('users.id', ondelete="CASCADE"),
               nullable=False),
     db.Column('topic_id', db.Integer(),
-              db.ForeignKey('topics.id', use_alter=True,
+              db.ForeignKey('topics.id', use_alter=True, ondelete="CASCADE",
                             name="fk_tracker_topic_id"),
               nullable=False))
 
 
 forumgroups = db.Table(
     'forumgroups',
-    db.Column('group_id', db.Integer(), db.ForeignKey('groups.id'),
+    db.Column('group_id', db.Integer(),
+              db.ForeignKey('groups.id', ondelete="CASCADE"),
               nullable=False),
     db.Column('forum_id', db.Integer(),
-              db.ForeignKey('forums.id', use_alter=True,
+              db.ForeignKey('forums.id', use_alter=True, ondelete="CASCADE",
                             name="fk_fg_forum_id"),
               nullable=False))
 
@@ -58,17 +61,20 @@ forumgroups = db.Table(
 class TopicsRead(db.Model, CRUDMixin):
     __tablename__ = "topicsread"
 
-    user_id = db.Column(db.Integer, db.ForeignKey("users.id"),
+    user_id = db.Column(db.Integer,
+                        db.ForeignKey("users.id", ondelete="CASCADE"),
                         primary_key=True)
     user = db.relationship('User', uselist=False, foreign_keys=[user_id])
     topic_id = db.Column(db.Integer,
                          db.ForeignKey("topics.id", use_alter=True,
-                                       name="fk_tr_topic_id"),
+                                       name="fk_tr_topic_id",
+                                       ondelete="CASCADE"),
                          primary_key=True)
     topic = db.relationship('Topic', uselist=False, foreign_keys=[topic_id])
     forum_id = db.Column(db.Integer,
                          db.ForeignKey("forums.id", use_alter=True,
-                                       name="fk_tr_forum_id"),
+                                       name="fk_tr_forum_id",
+                                       ondelete="CASCADE"),
                          primary_key=True)
     forum = db.relationship('Forum', uselist=False, foreign_keys=[forum_id])
     last_read = db.Column(UTCDateTime(timezone=True), default=time_utcnow,
@@ -78,12 +84,14 @@ class TopicsRead(db.Model, CRUDMixin):
 class ForumsRead(db.Model, CRUDMixin):
     __tablename__ = "forumsread"
 
-    user_id = db.Column(db.Integer, db.ForeignKey("users.id"),
+    user_id = db.Column(db.Integer,
+                        db.ForeignKey("users.id", ondelete="CASCADE"),
                         primary_key=True)
     user = db.relationship('User', uselist=False, foreign_keys=[user_id])
     forum_id = db.Column(db.Integer,
                          db.ForeignKey("forums.id", use_alter=True,
-                                       name="fk_fr_forum_id"),
+                                       name="fk_fr_forum_id",
+                                       ondelete="CASCADE"),
                          primary_key=True)
     forum = db.relationship('Forum', uselist=False, foreign_keys=[forum_id])
     last_read = db.Column(UTCDateTime(timezone=True), default=time_utcnow,
@@ -390,7 +398,7 @@ class Topic(HideableCRUDMixin, db.Model):
     id = db.Column(db.Integer, primary_key=True)
     forum_id = db.Column(db.Integer,
                          db.ForeignKey("forums.id",
-                                       use_alter=True,
+                                       use_alter=True, ondelete="CASCADE",
                                        name="fk_topic_forum_id"),
                          nullable=False)
     title = db.Column(db.String(255), nullable=False)
@@ -667,6 +675,12 @@ class Topic(HideableCRUDMixin, db.Model):
         db.session.delete(self)
         self._fix_user_post_counts(users or self.involved_users().all())
         self._fix_post_counts(forum)
+
+        # forum.last_post_id shouldn't usually be none
+        if forum.last_post_id is None or \
+                self.last_post_id == forum.last_post_id:
+            forum.update_last_post(commit=False)
+
         db.session.commit()
         return self
 
@@ -723,8 +737,6 @@ class Topic(HideableCRUDMixin, db.Model):
             self.forum.last_post_username = None
             self.forum.last_post_created = None
 
-        TopicsRead.query.filter_by(topic_id=self.id).delete()
-
     def _fix_user_post_counts(self, users=None):
         # Update the post counts
         if users:
@@ -789,7 +801,8 @@ class Forum(db.Model, CRUDMixin):
     __tablename__ = "forums"
 
     id = db.Column(db.Integer, primary_key=True)
-    category_id = db.Column(db.Integer, db.ForeignKey("categories.id"),
+    category_id = db.Column(db.Integer,
+                            db.ForeignKey("categories.id", ondelete="CASCADE"),
                             nullable=False)
     title = db.Column(db.String(255), nullable=False)
     description = db.Column(db.Text, nullable=True)
@@ -803,11 +816,14 @@ class Forum(db.Model, CRUDMixin):
 
     # One-to-one
     last_post_id = db.Column(db.Integer, db.ForeignKey("posts.id"),
-                             nullable=True)
+                             nullable=True)  # we handle this case ourselfs
     last_post = db.relationship("Post", backref="last_post_forum",
                                 uselist=False, foreign_keys=[last_post_id])
 
-    last_post_user_id = db.Column(db.Integer, db.ForeignKey("users.id"),
+    # set to null if the user got deleted
+    last_post_user_id = db.Column(db.Integer,
+                                  db.ForeignKey("users.id",
+                                                ondelete="SET NULL"),
                                   nullable=True)
 
     last_post_user = db.relationship(
@@ -827,8 +843,7 @@ class Forum(db.Model, CRUDMixin):
     topics = db.relationship(
         "Topic",
         backref="forum",
-        lazy="dynamic",
-        cascade="all, delete-orphan"
+        lazy="dynamic"
     )
 
     # Many-to-many
@@ -872,7 +887,7 @@ class Forum(db.Model, CRUDMixin):
         """
         return "<{} {}>".format(self.__class__.__name__, self.id)
 
-    def update_last_post(self):
+    def update_last_post(self, commit=True):
         """Updates the last post in the forum."""
         last_post = Post.query.\
             filter(Post.topic_id == Topic.id,
@@ -900,7 +915,8 @@ class Forum(db.Model, CRUDMixin):
             self.last_post_username = None
             self.last_post_created = None
 
-        db.session.commit()
+        if commit:
+            db.session.commit()
 
     def update_read(self, user, forumsread, topicsread):
         """Updates the ForumsRead status for the user. In order to work
@@ -1021,11 +1037,6 @@ class Forum(db.Model, CRUDMixin):
         db.session.delete(self)
         db.session.commit()
 
-        # Delete the entries for the forum in the ForumsRead and TopicsRead
-        # relation
-        ForumsRead.query.filter_by(forum_id=self.id).delete()
-        TopicsRead.query.filter_by(forum_id=self.id).delete()
-
         # Update the users post count
         if users:
             users_list = []
@@ -1113,8 +1124,7 @@ class Category(db.Model, CRUDMixin):
     # One-to-many
     forums = db.relationship("Forum", backref="category", lazy="dynamic",
                              primaryjoin='Forum.category_id == Category.id',
-                             order_by='asc(Forum.position)',
-                             cascade="all, delete-orphan")
+                             order_by='asc(Forum.position)')
 
     # Properties
     @property

+ 3 - 7
flaskbb/management/models.py

@@ -10,13 +10,10 @@
 """
 import logging
 
-from flask_wtf import FlaskForm
-from flaskbb._compat import iteritems, text_type
+from flaskbb._compat import iteritems
 from flaskbb.extensions import cache, db
 from flaskbb.utils.database import CRUDMixin
 from flaskbb.utils.forms import SettingValueType, generate_settings_form
-from wtforms import (BooleanField, FloatField, IntegerField, SelectField,
-                     SelectMultipleField, TextField, validators)
 
 logger = logging.getLogger(__name__)
 
@@ -27,8 +24,7 @@ class SettingsGroup(db.Model, CRUDMixin):
     key = db.Column(db.String(255), primary_key=True)
     name = db.Column(db.String(255), nullable=False)
     description = db.Column(db.Text, nullable=False)
-    settings = db.relationship("Setting", lazy="dynamic", backref="group",
-                               cascade="all, delete-orphan")
+    settings = db.relationship("Setting", lazy="dynamic", backref="group")
 
     def __repr__(self):
         return "<{} {}>".format(self.__class__.__name__, self.key)
@@ -41,7 +37,7 @@ class Setting(db.Model, CRUDMixin):
     value = db.Column(db.PickleType, nullable=False)
     settingsgroup = db.Column(db.String(255),
                               db.ForeignKey('settingsgroup.key',
-                                            use_alter=True,
+                                            use_alter=True, ondelete="CASCADE",
                                             name="fk_settingsgroup"),
                               nullable=False)
 

+ 10 - 5
flaskbb/message/models.py

@@ -23,7 +23,9 @@ class Conversation(db.Model, CRUDMixin):
     __tablename__ = "conversations"
 
     id = db.Column(db.Integer, primary_key=True)
-    user_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=False)
+    user_id = db.Column(db.Integer,
+                        db.ForeignKey("users.id", ondelete="CASCADE"),
+                        nullable=False)
     from_user_id = db.Column(db.Integer, db.ForeignKey("users.id"),
                              nullable=True)
     to_user_id = db.Column(db.Integer, db.ForeignKey("users.id"),
@@ -41,8 +43,7 @@ class Conversation(db.Model, CRUDMixin):
     messages = db.relationship(
         "Message", lazy="joined", backref="conversation",
         primaryjoin="Message.conversation_id == Conversation.id",
-        order_by="asc(Message.id)",
-        cascade="all, delete-orphan"
+        order_by="asc(Message.id)"
     )
 
     # this is actually the users message box
@@ -89,11 +90,15 @@ class Message(db.Model, CRUDMixin):
     __tablename__ = "messages"
 
     id = db.Column(db.Integer, primary_key=True)
-    conversation_id = db.Column(db.Integer, db.ForeignKey("conversations.id"),
+    conversation_id = db.Column(db.Integer,
+                                db.ForeignKey("conversations.id",
+                                              ondelete="CASCADE"),
                                 nullable=False)
 
     # the user who wrote the message
-    user_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=False)
+    user_id = db.Column(db.Integer,
+                        db.ForeignKey("users.id", ondelete="CASCADE"),
+                        nullable=False)
     message = db.Column(db.Text, nullable=False)
     date_created = db.Column(UTCDateTime(timezone=True), default=time_utcnow,
                              nullable=False)

+ 3 - 2
flaskbb/plugins/models.py

@@ -28,7 +28,9 @@ class PluginStore(CRUDMixin, db.Model):
     # Extra attributes like, validation things (min, max length...)
     # For Select*Fields required: choices
     extra = db.Column(db.PickleType, nullable=True)
-    plugin_id = db.Column(db.Integer, db.ForeignKey('plugin_registry.id'))
+    plugin_id = db.Column(db.Integer,
+                          db.ForeignKey("plugin_registry.id",
+                                        ondelete="CASCADE"))
 
     # Display stuff
     name = db.Column(db.Unicode(255), nullable=False)
@@ -62,7 +64,6 @@ class PluginRegistry(CRUDMixin, db.Model):
     values = db.relationship(
         'PluginStore',
         collection_class=attribute_mapped_collection('key'),
-        cascade='all, delete-orphan',
         backref='plugin'
     )
 

+ 14 - 18
flaskbb/user/models.py

@@ -28,9 +28,11 @@ logger = logging.getLogger(__name__)
 
 groups_users = db.Table(
     'groups_users',
-    db.Column('user_id', db.Integer, db.ForeignKey('users.id'),
+    db.Column('user_id', db.Integer,
+              db.ForeignKey('users.id', ondelete="CASCADE"),
               nullable=False),
-    db.Column('group_id', db.Integer, db.ForeignKey('groups.id'),
+    db.Column('group_id', db.Integer,
+              db.ForeignKey('groups.id', ondelete="CASCADE"),
               nullable=False)
 )
 
@@ -115,8 +117,10 @@ class User(db.Model, UserMixin, CRUDMixin):
     theme = db.Column(db.String(15), nullable=True)
     language = db.Column(db.String(15), default="en", nullable=True)
 
-    posts = db.relationship("Post", backref="user", lazy="dynamic", primaryjoin="User.id == Post.user_id")
-    topics = db.relationship("Topic", backref="user", lazy="dynamic", primaryjoin="User.id == Topic.user_id")
+    posts = db.relationship("Post", backref="user", lazy="dynamic",
+                            primaryjoin="User.id == Post.user_id")
+    topics = db.relationship("Topic", backref="user", lazy="dynamic",
+                             primaryjoin="User.id == Topic.user_id")
 
     post_count = db.Column(db.Integer, default=0)
 
@@ -194,7 +198,6 @@ class User(db.Model, UserMixin, CRUDMixin):
             Conversation.id == Message.conversation_id
         ).count()
 
-
     @property
     def days_registered(self):
         """Returns the amount of days the user is registered."""
@@ -480,22 +483,15 @@ class User(db.Model, UserMixin, CRUDMixin):
 
     def delete(self):
         """Deletes the User."""
-        # This isn't done automatically...
-        Conversation.query.filter_by(user_id=self.id).delete()
-        ForumsRead.query.filter_by(user_id=self.id).delete()
-        TopicsRead.query.filter_by(user_id=self.id).delete()
 
         # This should actually be handeld by the dbms.. but dunno why it doesnt
         # work here
-        from flaskbb.forum.models import Forum
-
-        last_post_forums = Forum.query.\
-            filter_by(last_post_user_id=self.id).all()
-
-        for forum in last_post_forums:
-            forum.last_post_user_id = None
-            forum.save()
-
+        #from flaskbb.forum.models import Forum
+        #last_post_forums = Forum.query.\
+        #    filter_by(last_post_user_id=self.id).all()
+        #for forum in last_post_forums:
+        #    forum.last_post_user_id = None
+        #    forum.save()
         db.session.delete(self)
         db.session.commit()
 

+ 174 - 0
migrations/201802012053_ec39ababe957_add_ondelete_cascades.py

@@ -0,0 +1,174 @@
+"""Add ondelete cascades
+
+Revision ID: ec39ababe957
+Revises: 7c3fcf8a3335
+Create Date: 2018-02-01 20:53:08.146277
+
+"""
+from alembic import op
+import sqlalchemy as sa
+
+
+# revision identifiers, used by Alembic.
+revision = 'ec39ababe957'
+down_revision = '7c3fcf8a3335'
+branch_labels = ()
+depends_on = None
+
+
+def upgrade():
+    # ### commands auto generated by Alembic - please adjust! ###
+    with op.batch_alter_table('conversations', schema=None) as batch_op:
+        batch_op.drop_constraint(None, type_='foreignkey')
+        batch_op.create_foreign_key("fk_conversations_user_id", 'users', ['user_id'], ['id'], ondelete='CASCADE')
+
+    with op.batch_alter_table('forumgroups', schema=None) as batch_op:
+        batch_op.drop_constraint('fk_forum_id', type_='foreignkey')
+        batch_op.drop_constraint(None, type_='foreignkey')
+        batch_op.create_foreign_key(None, 'groups', ['group_id'], ['id'], ondelete='CASCADE')
+        batch_op.create_foreign_key('fk_fg_forum_id', 'forums', ['forum_id'], ['id'], ondelete='CASCADE', use_alter=True)
+
+    with op.batch_alter_table('forums', schema=None) as batch_op:
+        batch_op.drop_constraint(None, type_='foreignkey')
+        batch_op.drop_constraint(None, type_='foreignkey')
+        batch_op.create_foreign_key(None, 'categories', ['category_id'], ['id'], ondelete='CASCADE')
+        batch_op.create_foreign_key(None, 'users', ['last_post_user_id'], ['id'], ondelete='SET NULL')
+
+    with op.batch_alter_table('forumsread', schema=None) as batch_op:
+        batch_op.drop_constraint(None, type_='foreignkey')
+        batch_op.drop_constraint('fk_fr_forum_id', type_='foreignkey')
+        batch_op.create_foreign_key('fk_fr_forum_id', 'forums', ['forum_id'], ['id'], ondelete='CASCADE', use_alter=True)
+        batch_op.create_foreign_key(None, 'users', ['user_id'], ['id'], ondelete='CASCADE')
+
+    with op.batch_alter_table('groups_users', schema=None) as batch_op:
+        batch_op.drop_constraint(None, type_='foreignkey')
+        batch_op.drop_constraint(None, type_='foreignkey')
+        batch_op.create_foreign_key(None, 'users', ['user_id'], ['id'], ondelete='CASCADE')
+        batch_op.create_foreign_key(None, 'groups', ['group_id'], ['id'], ondelete='CASCADE')
+
+    with op.batch_alter_table('messages', schema=None) as batch_op:
+        batch_op.drop_constraint(None, type_='foreignkey')
+        batch_op.drop_constraint(None, type_='foreignkey')
+        batch_op.create_foreign_key(None, 'users', ['user_id'], ['id'], ondelete='CASCADE')
+        batch_op.create_foreign_key(None, 'conversations', ['conversation_id'], ['id'], ondelete='CASCADE')
+
+    with op.batch_alter_table('moderators', schema=None) as batch_op:
+        batch_op.drop_constraint(None, type_='foreignkey')
+        batch_op.drop_constraint('fk_forum_id', type_='foreignkey')
+        batch_op.create_foreign_key('fk_mods_forum_id', 'forums', ['forum_id'], ['id'], ondelete='CASCADE', use_alter=True)
+        batch_op.create_foreign_key(None, 'users', ['user_id'], ['id'], ondelete='CASCADE')
+
+    with op.batch_alter_table('plugin_store', schema=None) as batch_op:
+        batch_op.drop_constraint(None, type_='foreignkey')
+        batch_op.create_foreign_key(None, 'plugin_registry', ['plugin_id'], ['id'], ondelete='CASCADE')
+
+    with op.batch_alter_table('posts', schema=None) as batch_op:
+        batch_op.alter_column('hidden',
+               existing_type=sa.BOOLEAN(),
+               nullable=True)
+
+    with op.batch_alter_table('settings', schema=None) as batch_op:
+        batch_op.drop_constraint('fk_settingsgroup', type_='foreignkey')
+        batch_op.create_foreign_key('fk_settingsgroup', 'settingsgroup', ['settingsgroup'], ['key'], ondelete='CASCADE', use_alter=True)
+
+    with op.batch_alter_table('topics', schema=None) as batch_op:
+        batch_op.alter_column('hidden',
+               existing_type=sa.BOOLEAN(),
+               nullable=True)
+        batch_op.drop_constraint('fk_topic_forum_id', type_='foreignkey')
+        batch_op.create_foreign_key('fk_topic_forum_id', 'forums', ['forum_id'], ['id'], ondelete='CASCADE', use_alter=True)
+
+    with op.batch_alter_table('topicsread', schema=None) as batch_op:
+        batch_op.drop_constraint(None, type_='foreignkey')
+        batch_op.drop_constraint('fk_tr_forum_id', type_='foreignkey')
+        batch_op.drop_constraint('fk_tr_topic_id', type_='foreignkey')
+        batch_op.create_foreign_key('fk_tr_topic_id', 'topics', ['topic_id'], ['id'], ondelete='CASCADE', use_alter=True)
+        batch_op.create_foreign_key('fk_tr_forum_id', 'forums', ['forum_id'], ['id'], ondelete='CASCADE', use_alter=True)
+        batch_op.create_foreign_key(None, 'users', ['user_id'], ['id'], ondelete='CASCADE')
+
+    with op.batch_alter_table('topictracker', schema=None) as batch_op:
+        batch_op.drop_constraint('fk_tracker_topic_id', type_='foreignkey')
+        batch_op.drop_constraint(None, type_='foreignkey')
+        batch_op.create_foreign_key(None, 'users', ['user_id'], ['id'], ondelete='CASCADE')
+        batch_op.create_foreign_key('fk_tracker_topic_id', 'topics', ['topic_id'], ['id'], ondelete='CASCADE', use_alter=True)
+
+    # ### end Alembic commands ###
+
+
+def downgrade():
+    # ### commands auto generated by Alembic - please adjust! ###
+    with op.batch_alter_table('topictracker', schema=None) as batch_op:
+        batch_op.drop_constraint('fk_tracker_topic_id', type_='foreignkey')
+        batch_op.drop_constraint(None, type_='foreignkey')
+        batch_op.create_foreign_key(None, 'users', ['user_id'], ['id'])
+        batch_op.create_foreign_key('fk_tracker_topic_id', 'topics', ['topic_id'], ['id'])
+
+    with op.batch_alter_table('topicsread', schema=None) as batch_op:
+        batch_op.drop_constraint(None, type_='foreignkey')
+        batch_op.drop_constraint('fk_tr_forum_id', type_='foreignkey')
+        batch_op.drop_constraint('fk_tr_topic_id', type_='foreignkey')
+        batch_op.create_foreign_key('fk_tr_topic_id', 'topics', ['topic_id'], ['id'])
+        batch_op.create_foreign_key('fk_tr_forum_id', 'forums', ['forum_id'], ['id'])
+        batch_op.create_foreign_key(None, 'users', ['user_id'], ['id'])
+
+    with op.batch_alter_table('topics', schema=None) as batch_op:
+        batch_op.drop_constraint('fk_topic_forum_id', type_='foreignkey')
+        batch_op.create_foreign_key('fk_topic_forum_id', 'forums', ['forum_id'], ['id'])
+        batch_op.alter_column('hidden',
+               existing_type=sa.BOOLEAN(),
+               nullable=False)
+
+    with op.batch_alter_table('settings', schema=None) as batch_op:
+        batch_op.drop_constraint('fk_settingsgroup', type_='foreignkey')
+        batch_op.create_foreign_key('fk_settingsgroup', 'settingsgroup', ['settingsgroup'], ['key'])
+
+    with op.batch_alter_table('posts', schema=None) as batch_op:
+        batch_op.alter_column('hidden',
+               existing_type=sa.BOOLEAN(),
+               nullable=False)
+
+    with op.batch_alter_table('plugin_store', schema=None) as batch_op:
+        batch_op.drop_constraint(None, type_='foreignkey')
+        batch_op.create_foreign_key(None, 'plugin_registry', ['plugin_id'], ['id'])
+
+    with op.batch_alter_table('moderators', schema=None) as batch_op:
+        batch_op.drop_constraint(None, type_='foreignkey')
+        batch_op.drop_constraint('fk_mods_forum_id', type_='foreignkey')
+        batch_op.create_foreign_key('fk_forum_id', 'forums', ['forum_id'], ['id'])
+        batch_op.create_foreign_key(None, 'users', ['user_id'], ['id'])
+
+    with op.batch_alter_table('messages', schema=None) as batch_op:
+        batch_op.drop_constraint(None, type_='foreignkey')
+        batch_op.drop_constraint(None, type_='foreignkey')
+        batch_op.create_foreign_key(None, 'users', ['user_id'], ['id'])
+        batch_op.create_foreign_key(None, 'conversations', ['conversation_id'], ['id'])
+
+    with op.batch_alter_table('groups_users', schema=None) as batch_op:
+        batch_op.drop_constraint(None, type_='foreignkey')
+        batch_op.drop_constraint(None, type_='foreignkey')
+        batch_op.create_foreign_key(None, 'users', ['user_id'], ['id'])
+        batch_op.create_foreign_key(None, 'groups', ['group_id'], ['id'])
+
+    with op.batch_alter_table('forumsread', schema=None) as batch_op:
+        batch_op.drop_constraint(None, type_='foreignkey')
+        batch_op.drop_constraint('fk_fr_forum_id', type_='foreignkey')
+        batch_op.create_foreign_key('fk_fr_forum_id', 'forums', ['forum_id'], ['id'])
+        batch_op.create_foreign_key(None, 'users', ['user_id'], ['id'])
+
+    with op.batch_alter_table('forums', schema=None) as batch_op:
+        batch_op.drop_constraint(None, type_='foreignkey')
+        batch_op.drop_constraint(None, type_='foreignkey')
+        batch_op.create_foreign_key(None, 'categories', ['category_id'], ['id'])
+        batch_op.create_foreign_key(None, 'users', ['last_post_user_id'], ['id'])
+
+    with op.batch_alter_table('forumgroups', schema=None) as batch_op:
+        batch_op.drop_constraint('fk_fg_forum_id', type_='foreignkey')
+        batch_op.drop_constraint(None, type_='foreignkey')
+        batch_op.create_foreign_key(None, 'groups', ['group_id'], ['id'])
+        batch_op.create_foreign_key('fk_forum_id', 'forums', ['forum_id'], ['id'])
+
+    with op.batch_alter_table('conversations', schema=None) as batch_op:
+        batch_op.drop_constraint(None, type_='foreignkey')
+        batch_op.create_foreign_key(None, 'users', ['user_id'], ['id'])
+
+    # ### end Alembic commands ###