Browse Source

Be more explicit about nullable columns

Peter Justin 8 years ago
parent
commit
ad3090d61f

+ 60 - 57
flaskbb/forum/models.py

@@ -34,27 +34,18 @@ topictracker = db.Table(
     db.Column('user_id', db.Integer(), db.ForeignKey('users.id'),
               nullable=False),
     db.Column('topic_id', db.Integer(),
-              db.ForeignKey('topics.id',
-                            use_alter=True, name="fk_tracker_topic_id"),
+              db.ForeignKey('topics.id', use_alter=True,
+                            name="fk_tracker_topic_id"),
               nullable=False))
 
 
-# m2m table for group-forum permission mapping
 forumgroups = db.Table(
     'forumgroups',
-    db.Column(
-        'group_id',
-        db.Integer(),
-        db.ForeignKey('groups.id'),
-        nullable=False
-    ),
-    db.Column(
-        'forum_id',
-        db.Integer(),
-        db.ForeignKey('forums.id', use_alter=True, name="fk_forum_id"),
-        nullable=False
-    )
-)
+    db.Column('group_id', db.Integer(), db.ForeignKey('groups.id'),
+              nullable=False),
+    db.Column('forum_id', db.Integer(),
+              db.ForeignKey('forums.id', use_alter=True, name="fk_forum_id"),
+              nullable=False))
 
 
 class TopicsRead(db.Model, CRUDMixin):
@@ -70,7 +61,8 @@ class TopicsRead(db.Model, CRUDMixin):
                          db.ForeignKey("forums.id", use_alter=True,
                                        name="fk_tr_forum_id"),
                          primary_key=True)
-    last_read = db.Column(UTCDateTime(timezone=True), default=time_utcnow)
+    last_read = db.Column(UTCDateTime(timezone=True), default=time_utcnow,
+                          nullable=False)
 
 
 class ForumsRead(db.Model, CRUDMixin):
@@ -82,21 +74,27 @@ class ForumsRead(db.Model, CRUDMixin):
                          db.ForeignKey("forums.id", use_alter=True,
                                        name="fk_fr_forum_id"),
                          primary_key=True)
-    last_read = db.Column(UTCDateTime(timezone=True), default=time_utcnow)
-    cleared = db.Column(UTCDateTime(timezone=True))
+    last_read = db.Column(UTCDateTime(timezone=True), default=time_utcnow,
+                          nullable=False)
+    cleared = db.Column(UTCDateTime(timezone=True), nullable=True)
 
 
 class Report(db.Model, CRUDMixin):
     __tablename__ = "reports"
 
+    # TODO: Store in addition to the info below topic title and username
+    # as well. So that in case a user or post gets deleted, we can
+    # still view the report
+
     id = db.Column(db.Integer, primary_key=True)
     reporter_id = db.Column(db.Integer, db.ForeignKey("users.id"),
-                            nullable=False)
-    reported = db.Column(UTCDateTime(timezone=True), default=time_utcnow)
-    post_id = db.Column(db.Integer, db.ForeignKey("posts.id"), nullable=False)
-    zapped = db.Column(UTCDateTime(timezone=True))
-    zapped_by = db.Column(db.Integer, db.ForeignKey("users.id"))
-    reason = db.Column(db.Text)
+                            nullable=True)
+    reported = db.Column(UTCDateTime(timezone=True), default=time_utcnow,
+                         nullable=False)
+    post_id = db.Column(db.Integer, db.ForeignKey("posts.id"), nullable=True)
+    zapped = db.Column(UTCDateTime(timezone=True), nullable=True)
+    zapped_by = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=True)
+    reason = db.Column(db.Text, nullable=True)
 
     post = db.relationship(
         "Post", lazy="joined",
@@ -140,13 +138,15 @@ class Post(db.Model, CRUDMixin):
                          db.ForeignKey("topics.id",
                                        use_alter=True,
                                        name="fk_post_topic_id",
-                                       ondelete="CASCADE"))
+                                       ondelete="CASCADE"),
+                         nullable=True)
     user_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=True)
     username = db.Column(db.String(200), nullable=False)
     content = db.Column(db.Text, nullable=False)
-    date_created = db.Column(UTCDateTime(timezone=True), default=time_utcnow)
-    date_modified = db.Column(UTCDateTime(timezone=True))
-    modified_by = db.Column(db.String(200))
+    date_created = db.Column(UTCDateTime(timezone=True), default=time_utcnow,
+                             nullable=False)
+    date_modified = db.Column(UTCDateTime(timezone=True), nullable=True)
+    modified_by = db.Column(db.String(200), nullable=True)
 
     # Properties
     @property
@@ -287,23 +287,27 @@ class Topic(db.Model, CRUDMixin):
                                        name="fk_topic_forum_id"),
                          nullable=False)
     title = db.Column(db.String(255), nullable=False)
-    user_id = db.Column(db.Integer, db.ForeignKey("users.id"))
+    user_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=True)
     username = db.Column(db.String(200), nullable=False)
-    date_created = db.Column(UTCDateTime(timezone=True), default=time_utcnow)
-    last_updated = db.Column(UTCDateTime(timezone=True), default=time_utcnow)
-    locked = db.Column(db.Boolean, default=False)
-    important = db.Column(db.Boolean, default=False)
-    views = db.Column(db.Integer, default=0)
-    post_count = db.Column(db.Integer, default=0)
+    date_created = db.Column(UTCDateTime(timezone=True), default=time_utcnow,
+                             nullable=False)
+    last_updated = db.Column(UTCDateTime(timezone=True), default=time_utcnow,
+                             nullable=False)
+    locked = db.Column(db.Boolean, default=False, nullable=False)
+    important = db.Column(db.Boolean, default=False, nullable=False)
+    views = db.Column(db.Integer, default=0, nullable=False)
+    post_count = db.Column(db.Integer, default=0, nullable=False)
 
     # One-to-one (uselist=False) relationship between first_post and topic
-    first_post_id = db.Column(db.Integer, db.ForeignKey("posts.id",
-                                                        ondelete="CASCADE"))
+    first_post_id = db.Column(db.Integer,
+                              db.ForeignKey("posts.id", ondelete="CASCADE"),
+                              nullable=True)
     first_post = db.relationship("Post", backref="first_post", uselist=False,
                                  foreign_keys=[first_post_id])
 
     # One-to-one
-    last_post_id = db.Column(db.Integer, db.ForeignKey("posts.id"))
+    last_post_id = db.Column(db.Integer, db.ForeignKey("posts.id"),
+                             nullable=True)
 
     last_post = db.relationship("Post", backref="last_post", uselist=False,
                                 foreign_keys=[last_post_id])
@@ -330,20 +334,17 @@ class Topic(db.Model, CRUDMixin):
         return url_for("forum.view_topic", topic_id=self.id, slug=self.slug)
 
     def first_unread(self, topicsread, user, forumsread=None):
-        """Returns the url to the first unread post if any else to the topic
-        itself.
+        """Returns the url to the first unread post. If no unread posts exist
+        it will return the url to the topic.
 
         :param topicsread: The topicsread object for the topic
-
         :param user: The user who should be checked if he has read the
                      last post in the topic
-
         :param forumsread: The forumsread object in which the topic is. If you
                         also want to check if the user has marked the forum as
                         read, than you will also need to pass an forumsread
                         object.
         """
-
         # If the topic is unread try to get the first unread post
         if topic_is_unread(self, topicsread, user, forumsread):
             query = Post.query.filter(Post.topic_id == self.id)
@@ -526,8 +527,7 @@ class Topic(db.Model, CRUDMixin):
         self.username = user.username
 
         # Set the last_updated time. Needed for the readstracker
-        created = time_utcnow()
-        self.date_created = self.last_updated = created
+        self.date_created = self.last_updated = time_utcnow()
 
         # Insert and commit the topic
         db.session.add(self)
@@ -536,8 +536,8 @@ class Topic(db.Model, CRUDMixin):
         # Create the topic post
         post.save(user, self)
 
-        # Update the first post id
-        self.first_post_id = post.id
+        # Update the first and last post id
+        self.last_post_id = self.first_post_id = post.id
 
         # Update the topic count
         forum.topic_count += 1
@@ -611,26 +611,29 @@ class Forum(db.Model, CRUDMixin):
     category_id = db.Column(db.Integer, db.ForeignKey("categories.id"),
                             nullable=False)
     title = db.Column(db.String(255), nullable=False)
-    description = db.Column(db.Text)
+    description = db.Column(db.Text, nullable=True)
     position = db.Column(db.Integer, default=1, nullable=False)
     locked = db.Column(db.Boolean, default=False, nullable=False)
     show_moderators = db.Column(db.Boolean, default=False, nullable=False)
-    external = db.Column(db.String(200))
+    external = db.Column(db.String(200), nullable=True)
 
     post_count = db.Column(db.Integer, default=0, nullable=False)
     topic_count = db.Column(db.Integer, default=0, nullable=False)
 
     # One-to-one
-    last_post_id = db.Column(db.Integer, db.ForeignKey("posts.id"))
+    last_post_id = db.Column(db.Integer, db.ForeignKey("posts.id"),
+                             nullable=True)
     last_post = db.relationship("Post", backref="last_post_forum",
                                 uselist=False, foreign_keys=[last_post_id])
 
-    # Not nice, but needed to improve the performance
-    last_post_title = db.Column(db.String(255))
-    last_post_user_id = db.Column(db.Integer, db.ForeignKey("users.id"))
-    last_post_username = db.Column(db.String(255))
+    # Not nice, but needed to improve the performance; can be set to NULL
+    # if the forum has no posts
+    last_post_title = db.Column(db.String(255), nullable=True)
+    last_post_user_id = db.Column(db.Integer, db.ForeignKey("users.id"),
+                                  nullable=True)
+    last_post_username = db.Column(db.String(255), nullable=True)
     last_post_created = db.Column(UTCDateTime(timezone=True),
-                                  default=time_utcnow)
+                                  default=time_utcnow, nullable=True)
 
     # One-to-many
     topics = db.relationship(
@@ -912,7 +915,7 @@ class Category(db.Model, CRUDMixin):
 
     id = db.Column(db.Integer, primary_key=True)
     title = db.Column(db.String(255), nullable=False)
-    description = db.Column(db.Text)
+    description = db.Column(db.Text, nullable=True)
     position = db.Column(db.Integer, default=1, nullable=False)
 
     # One-to-many

+ 12 - 8
flaskbb/message/models.py

@@ -20,14 +20,17 @@ class Conversation(db.Model, CRUDMixin):
 
     id = db.Column(db.Integer, primary_key=True)
     user_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=False)
-    from_user_id = db.Column(db.Integer, db.ForeignKey("users.id"))
-    to_user_id = db.Column(db.Integer, db.ForeignKey("users.id"))
+    from_user_id = db.Column(db.Integer, db.ForeignKey("users.id"),
+                             nullable=True)
+    to_user_id = db.Column(db.Integer, db.ForeignKey("users.id"),
+                           nullable=True)
     shared_id = db.Column(UUIDType, nullable=False)
-    subject = db.Column(db.String(255))
-    date_created = db.Column(UTCDateTime(timezone=True), default=time_utcnow)
-    trash = db.Column(db.Boolean, nullable=False, default=False)
-    draft = db.Column(db.Boolean, nullable=False, default=False)
-    unread = db.Column(db.Boolean, nullable=False, default=True)
+    subject = db.Column(db.String(255), nullable=True)
+    date_created = db.Column(UTCDateTime(timezone=True), default=time_utcnow,
+                             nullable=False)
+    trash = db.Column(db.Boolean, default=False, nullable=False)
+    draft = db.Column(db.Boolean, default=False, nullable=False)
+    unread = db.Column(db.Boolean, default=False, nullable=False)
 
     messages = db.relationship(
         "Message", lazy="joined", backref="conversation",
@@ -85,7 +88,8 @@ class Message(db.Model, CRUDMixin):
     # the user who wrote the message
     user_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=False)
     message = db.Column(db.Text, nullable=False)
-    date_created = db.Column(UTCDateTime(timezone=True), default=time_utcnow)
+    date_created = db.Column(UTCDateTime(timezone=True), default=time_utcnow,
+                             nullable=False)
 
     user = db.relationship("User", lazy="joined")
 

+ 24 - 19
flaskbb/user/models.py

@@ -24,8 +24,11 @@ from flaskbb.message.models import Conversation
 
 groups_users = db.Table(
     'groups_users',
-    db.Column('user_id', db.Integer(), db.ForeignKey('users.id')),
-    db.Column('group_id', db.Integer(), db.ForeignKey('groups.id')))
+    db.Column('user_id', db.Integer, db.ForeignKey('users.id'),
+              nullable=False),
+    db.Column('group_id', db.Integer, db.ForeignKey('groups.id'),
+              nullable=False)
+)
 
 
 class Group(db.Model, CRUDMixin):
@@ -33,7 +36,7 @@ class Group(db.Model, CRUDMixin):
 
     id = db.Column(db.Integer, primary_key=True)
     name = db.Column(db.String(255), unique=True, nullable=False)
-    description = db.Column(db.Text)
+    description = db.Column(db.Text, nullable=True)
 
     # Group types
     admin = db.Column(db.Boolean, default=False, nullable=False)
@@ -86,22 +89,24 @@ class User(db.Model, UserMixin, CRUDMixin):
     username = db.Column(db.String(200), unique=True, nullable=False)
     email = db.Column(db.String(200), unique=True, nullable=False)
     _password = db.Column('password', db.String(120), nullable=False)
-    date_joined = db.Column(UTCDateTime(timezone=True), default=time_utcnow)
-    lastseen = db.Column(UTCDateTime(timezone=True), default=time_utcnow)
-    birthday = db.Column(db.DateTime)
-    gender = db.Column(db.String(10))
-    website = db.Column(db.String(200))
-    location = db.Column(db.String(100))
-    signature = db.Column(db.Text)
-    avatar = db.Column(db.String(200))
-    notes = db.Column(db.Text)
-
-    last_failed_login = db.Column(UTCDateTime(timezone=True))
-    login_attempts = db.Column(db.Integer, default=0)
-    activated = db.Column(db.Boolean, default=False)
-
-    theme = db.Column(db.String(15))
-    language = db.Column(db.String(15), default="en")
+    date_joined = db.Column(UTCDateTime(timezone=True), default=time_utcnow,
+                            nullable=False)
+    lastseen = db.Column(UTCDateTime(timezone=True), default=time_utcnow,
+                         nullable=True)
+    birthday = db.Column(db.DateTime, nullable=True)
+    gender = db.Column(db.String(10), nullable=True)
+    website = db.Column(db.String(200), nullable=True)
+    location = db.Column(db.String(100), nullable=True)
+    signature = db.Column(db.Text, nullable=True)
+    avatar = db.Column(db.String(200), nullable=True)
+    notes = db.Column(db.Text, nullable=True)
+
+    last_failed_login = db.Column(UTCDateTime(timezone=True), nullable=True)
+    login_attempts = db.Column(db.Integer, default=0, nullable=False)
+    activated = db.Column(db.Boolean, default=False, nullable=False)
+
+    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")
     topics = db.relationship("Topic", backref="user", lazy="dynamic")

+ 176 - 0
migrations/933bd7d807c4_add_more_non_nullables.py

@@ -0,0 +1,176 @@
+"""Add more non nullables
+
+Revision ID: 933bd7d807c4
+Revises: d87cea4e995d
+Create Date: 2017-05-04 11:44:16.146471
+
+"""
+from alembic import op
+import sqlalchemy as sa
+import flaskbb
+
+# revision identifiers, used by Alembic.
+revision = '933bd7d807c4'
+down_revision = 'd87cea4e995d'
+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.alter_column('date_created',
+               existing_type=flaskbb.utils.database.UTCDateTime(timezone=True),
+               nullable=False)
+
+    with op.batch_alter_table('forumsread', schema=None) as batch_op:
+        batch_op.alter_column('last_read',
+               existing_type=flaskbb.utils.database.UTCDateTime(timezone=True),
+               nullable=False)
+
+    with op.batch_alter_table('groups_users', schema=None) as batch_op:
+        batch_op.alter_column('group_id',
+               existing_type=sa.INTEGER(),
+               nullable=False)
+        batch_op.alter_column('user_id',
+               existing_type=sa.INTEGER(),
+               nullable=False)
+
+    with op.batch_alter_table('messages', schema=None) as batch_op:
+        batch_op.alter_column('date_created',
+               existing_type=flaskbb.utils.database.UTCDateTime(timezone=True),
+               nullable=False)
+
+    with op.batch_alter_table('posts', schema=None) as batch_op:
+        batch_op.alter_column('date_created',
+               existing_type=flaskbb.utils.database.UTCDateTime(timezone=True),
+               nullable=False)
+
+    with op.batch_alter_table('reports', schema=None) as batch_op:
+        batch_op.alter_column('post_id',
+               existing_type=sa.INTEGER(),
+               nullable=True)
+        batch_op.alter_column('reported',
+               existing_type=flaskbb.utils.database.UTCDateTime(timezone=True),
+               nullable=False)
+        batch_op.alter_column('reporter_id',
+               existing_type=sa.INTEGER(),
+               nullable=True)
+
+    with op.batch_alter_table('topics', schema=None) as batch_op:
+        batch_op.alter_column('date_created',
+               existing_type=flaskbb.utils.database.UTCDateTime(timezone=True),
+               nullable=False)
+        batch_op.alter_column('important',
+               existing_type=sa.BOOLEAN(),
+               nullable=False)
+        batch_op.alter_column('last_updated',
+               existing_type=flaskbb.utils.database.UTCDateTime(timezone=True),
+               nullable=False)
+        batch_op.alter_column('locked',
+               existing_type=sa.BOOLEAN(),
+               nullable=False)
+        batch_op.alter_column('post_count',
+               existing_type=sa.INTEGER(),
+               nullable=False)
+        batch_op.alter_column('views',
+               existing_type=sa.INTEGER(),
+               nullable=False)
+
+    with op.batch_alter_table('topicsread', schema=None) as batch_op:
+        batch_op.alter_column('last_read',
+               existing_type=flaskbb.utils.database.UTCDateTime(timezone=True),
+               nullable=False)
+
+    with op.batch_alter_table('users', schema=None) as batch_op:
+        batch_op.alter_column('activated',
+               existing_type=sa.BOOLEAN(),
+               nullable=False)
+        batch_op.alter_column('date_joined',
+               existing_type=flaskbb.utils.database.UTCDateTime(timezone=True),
+               nullable=False)
+        batch_op.alter_column('login_attempts',
+               existing_type=sa.INTEGER(),
+               nullable=False)
+
+    # ### end Alembic commands ###
+
+
+def downgrade():
+    # ### commands auto generated by Alembic - please adjust! ###
+    with op.batch_alter_table('users', schema=None) as batch_op:
+        batch_op.alter_column('login_attempts',
+               existing_type=sa.INTEGER(),
+               nullable=True)
+        batch_op.alter_column('date_joined',
+               existing_type=flaskbb.utils.database.UTCDateTime(timezone=True),
+               nullable=True)
+        batch_op.alter_column('activated',
+               existing_type=sa.BOOLEAN(),
+               nullable=True)
+
+    with op.batch_alter_table('topicsread', schema=None) as batch_op:
+        batch_op.alter_column('last_read',
+               existing_type=flaskbb.utils.database.UTCDateTime(timezone=True),
+               nullable=True)
+
+    with op.batch_alter_table('topics', schema=None) as batch_op:
+        batch_op.alter_column('views',
+               existing_type=sa.INTEGER(),
+               nullable=True)
+        batch_op.alter_column('post_count',
+               existing_type=sa.INTEGER(),
+               nullable=True)
+        batch_op.alter_column('locked',
+               existing_type=sa.BOOLEAN(),
+               nullable=True)
+        batch_op.alter_column('last_updated',
+               existing_type=flaskbb.utils.database.UTCDateTime(timezone=True),
+               nullable=True)
+        batch_op.alter_column('important',
+               existing_type=sa.BOOLEAN(),
+               nullable=True)
+        batch_op.alter_column('date_created',
+               existing_type=flaskbb.utils.database.UTCDateTime(timezone=True),
+               nullable=True)
+
+    with op.batch_alter_table('reports', schema=None) as batch_op:
+        batch_op.alter_column('reporter_id',
+               existing_type=sa.INTEGER(),
+               nullable=False)
+        batch_op.alter_column('reported',
+               existing_type=flaskbb.utils.database.UTCDateTime(timezone=True),
+               nullable=True)
+        batch_op.alter_column('post_id',
+               existing_type=sa.INTEGER(),
+               nullable=False)
+
+    with op.batch_alter_table('posts', schema=None) as batch_op:
+        batch_op.alter_column('date_created',
+               existing_type=flaskbb.utils.database.UTCDateTime(timezone=True),
+               nullable=True)
+
+    with op.batch_alter_table('messages', schema=None) as batch_op:
+        batch_op.alter_column('date_created',
+               existing_type=flaskbb.utils.database.UTCDateTime(timezone=True),
+               nullable=True)
+
+    with op.batch_alter_table('groups_users', schema=None) as batch_op:
+        batch_op.alter_column('user_id',
+               existing_type=sa.INTEGER(),
+               nullable=True)
+        batch_op.alter_column('group_id',
+               existing_type=sa.INTEGER(),
+               nullable=True)
+
+    with op.batch_alter_table('forumsread', schema=None) as batch_op:
+        batch_op.alter_column('last_read',
+               existing_type=flaskbb.utils.database.UTCDateTime(timezone=True),
+               nullable=True)
+
+    with op.batch_alter_table('conversations', schema=None) as batch_op:
+        batch_op.alter_column('date_created',
+               existing_type=flaskbb.utils.database.UTCDateTime(timezone=True),
+               nullable=True)
+
+    # ### end Alembic commands ###