Use case: using a form to enter grades for each course a student is enrolled in.
Model:
Using SQLAlchemy, I defined a Student
object, a Course
object, and a StudentCourse
association object that stores each student's grade for each course.
class Student(Base):
__tablename__ = 'students'
id = Column(Integer, primary_key=True)
name = Column(Text)
courses = association_proxy('student_courses', 'grade',
creator=lambda k, v: StudentCourse(course_title=k, grade=v))
...
class Course(Base):
__tablename__ = 'courses'
id = Column(Integer, primary_key=True)
title = Column(Text, unique=True)
...
# Link students to courses and store grades
class StudentCourse(Base):
__tablename__ = 'student_courses'
student_id = Column(Integer, ForeignKey(Student.id), primary_key=True)
course_id = Column(Integer, ForeignKey(Course.id), primary_key=True)
grade = Column(Integer)
student = relationship(Student,backref=backref(
'student_courses',
collection_class=attribute_mapped_collection('course_title'),
cascade='all, delete-orphan'))
course = relationship(Course)
@property
def course_title(self):
if self.course is not None:
return self.course.title
else:
return self._course_title
...
View:
I can query the StudentCourses model and construct a relevant form, but I can't figure out how to pass/retrieve the data from the query as an object.
def view(request):
student = Student.from_request(request)
student_courses = DBSession.query(StudentCourse).\
filter(StudentCourse.student_id == student.id).\
all()
class GradesForm(Form):
pass
# Add form field for each course the student is enrolled in
for c in student_courses:
setattr(GradesForm,
c.course_title,
IntegerField()
)
form = GradesForm(request.POST, obj=student_courses) # this doesn't populate the form
return {'form': form}
This produces a blank form, so I obviously can't populate the form with data directly from the Query
object. But I've been unsuccessful populating the form with any kind of object, even when creating a form with a FormField
type for each course:
class StudentCourseForm(Form):
course_title = StringField()
grade = IntegerField()
def view(request):
...
class GradesForm(Form):
pass
# Add form field for each course
for c in student_courses:
setattr(GradesForm,
c.course_title,
FormField(StudentCourseForm)
)
form = GradesForm(request.POST, obj=student_courses)
return {'form': form}
Using a query, if possible, would be the easiest. Per the SQLAlchemy docs, using the query()
method on a session creates a Query
object. When iterated like I did in my controller, this object is a list of StudentCourse
objects.
[<app.models.StudentCourse object at 0x10875bd50>, <app.models.StudentCourse object at 0x10875bed0>]
...and my progress ends here. Any help appreciated!