Remove many_to_one, use more explicit ReferenceCol instead

Mostly because I couldn't get many_to_one to work with Flask-SQLA =/
master
Steven Loria 11 years ago
parent 58c95a9a4c
commit f5f5d37eb6
  1. 50
      {{cookiecutter.app_name}}/{{cookiecutter.app_name}}/database.py
  2. 10
      {{cookiecutter.app_name}}/{{cookiecutter.app_name}}/tests/test_models.py
  3. 14
      {{cookiecutter.app_name}}/{{cookiecutter.app_name}}/user/models.py

@ -1,41 +1,12 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
'''Database module, including the SQLAlchemy database object and DB-related """Database module, including the SQLAlchemy database object and DB-related
utilities. utilities.
''' """
from sqlalchemy.orm import relationship from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declared_attr
from .extensions import db from .extensions import db
# Helpers from Mike Bayer's atmcraft example app relationship = relationship
# https://bitbucket.org/zzzeek/pycon2014_atmcraft/src/a6d96575bc49?at=master
def many_to_one(clsname, **kw):
"""Use an event to build a many-to-one relationship on a class.
This makes use of the :meth:`.References._reference_table` method
to generate a full foreign key relationship to the remote table.
"""
@declared_attr
def m2o(cls):
cls._references((cls.__name__, clsname))
return relationship(clsname, **kw)
return m2o
def one_to_many(clsname, **kw):
"""Use an event to build a one-to-many relationship on a class.
This makes use of the :meth:`.References._reference_table` method
to generate a full foreign key relationship from the remote table.
"""
@declared_attr
def o2m(cls):
cls._references((clsname, cls.__name__))
return relationship(clsname, **kw)
return o2m
class CRUDMixin(object): class CRUDMixin(object):
"""Mixin that adds convenience methods for CRUD (create, read, update, delete) """Mixin that adds convenience methods for CRUD (create, read, update, delete)
@ -56,24 +27,31 @@ class CRUDMixin(object):
@classmethod @classmethod
def create(cls, **kwargs): def create(cls, **kwargs):
'''Create a new record and save it the database.''' """Create a new record and save it the database."""
instance = cls(**kwargs) instance = cls(**kwargs)
return instance.save() return instance.save()
def update(self, commit=True, **kwargs): def update(self, commit=True, **kwargs):
'''Update specific fields of a record.''' """Update specific fields of a record."""
for attr, value in kwargs.iteritems(): for attr, value in kwargs.iteritems():
setattr(self, attr, value) setattr(self, attr, value)
return commit and self.save() or self return commit and self.save() or self
def save(self, commit=True): def save(self, commit=True):
'''Save the record.''' """Save the record."""
db.session.add(self) db.session.add(self)
if commit: if commit:
db.session.commit() db.session.commit()
return self return self
def delete(self, commit=True): def delete(self, commit=True):
'''Remove the record from the database.''' """Remove the record from the database."""
db.session.delete(self) db.session.delete(self)
return commit and db.session.commit() return commit and db.session.commit()
def ReferenceCol(tablename, nullable=False, **kwargs):
"""Column that adds primary key foreign key reference."""
return db.Column(
db.ForeignKey("{0}.id".format(tablename)),
nullable=nullable, **kwargs)

@ -3,7 +3,7 @@ import unittest
from nose.tools import * # PEP8 asserts from nose.tools import * # PEP8 asserts
from {{ cookiecutter.app_name }}.database import db from {{ cookiecutter.app_name }}.database import db
from {{ cookiecutter.app_name }}.user.models import User from {{ cookiecutter.app_name }}.user.models import User, Role
from .base import DbTestCase from .base import DbTestCase
from .factories import UserFactory from .factories import UserFactory
@ -29,5 +29,13 @@ class TestUser(DbTestCase):
user = UserFactory(first_name="Foo", last_name="Bar") user = UserFactory(first_name="Foo", last_name="Bar")
assert_equal(user.full_name, "Foo Bar") assert_equal(user.full_name, "Foo Bar")
def test_roles(self):
role = Role(name='admin')
role.save()
u = UserFactory()
u.roles.append(role)
u.save()
assert_in(role, u.roles)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()

@ -3,10 +3,21 @@ import datetime as dt
from flask.ext.login import UserMixin from flask.ext.login import UserMixin
from {{cookiecutter.app_name}}.database import db, CRUDMixin from {{cookiecutter.app_name}}.database import (
db,
CRUDMixin,
ReferenceCol,
relationship,
)
from {{cookiecutter.app_name}}.extensions import bcrypt from {{cookiecutter.app_name}}.extensions import bcrypt
class Role(CRUDMixin, db.Model):
__tablename__ = 'roles'
name = db.Column(db.String(80), unique=True, nullable=False)
user_id = ReferenceCol('users', nullable=True)
user = relationship('User', backref='roles')
class User(UserMixin, CRUDMixin, db.Model): class User(UserMixin, CRUDMixin, db.Model):
__tablename__ = 'users' __tablename__ = 'users'
@ -19,6 +30,7 @@ class User(UserMixin, CRUDMixin, db.Model):
active = db.Column(db.Boolean()) active = db.Column(db.Boolean())
is_admin = db.Column(db.Boolean()) is_admin = db.Column(db.Boolean())
def __init__(self, username=None, email=None, password=None, def __init__(self, username=None, email=None, password=None,
first_name=None, last_name=None, first_name=None, last_name=None,
active=False, is_admin=False): active=False, is_admin=False):

Loading…
Cancel
Save