I've been working to finish the database stuff, the API functions, and ensure the current tests pass. That's all done and my next step is to write more tests. The entire afternoon, after doing the above, I've been working on the documentation available here. I've made it very thorough and updated it to match the new stuff. It's pretty much complete except for the fact that I need to update the database schema picture tonight. The documentation is thorough, but I'm not sure that it's organized. Oh well, not important right now.
8:20 ==>

I forgot to blog that a few days ago I had an idea: I wanted to create a first ticket for each project, one that users wouldn't be able to touch. It would contain the default values for each field-description, their type, etc. (It would have to be updated when new field-descriptions are inserted). This ticket could then be cloned when inserting a new ticket into the database instead of having to go through each field-description looking up its default value, parsing it, and what not. It would also reduce the need to have an explicit class for supported data type (since we wouldn't need the parse function); the classes could be generated automatically in a loop. Jeff, however, vetoed the idea since special case tickets would be bad.
8:20 ==>
I forgot to blog that a few days ago I had an idea: I wanted to create a first ticket for each project, one that users wouldn't be able to touch. It would contain the default values for each field-description, their type, etc. (It would have to be updated when new field-descriptions are inserted). This ticket could then be cloned when inserting a new ticket into the database instead of having to go through each field-description looking up its default value, parsing it, and what not. It would also reduce the need to have an explicit class for supported data type (since we wouldn't need the parse function); the classes could be generated automatically in a loop. Jeff, however, vetoed the idea since special case tickets would be bad.


Comments
1. Testing the ondelete='cascade' constraint.
This was in reference to FieldDescription.project. Test stubs are in place and tests are just itching to be written. Soon.
2. > Can the default fields be configured? I think a prof would want to start minimal, and then let it grow, rather than having all these fields pre-populated.
Default fields can be changed easily in the code, but when it comes to administrative tasks in DrP, they cannot be configured. That would involve setting up a configuration page outside of all projects, and that is something beyond our current stage of development for this new subsystem.
Besides, the default fields were chosen with some consideration; it's likely that if we left them out, profs would have to add these very fields for each project.
3. > Why doesn't `Project` have a reference to its fields?
The advantage of having this reference is minimal. Think about it... the most important query is to get the values of all fields for a given ticket; that can done by "for k, v in t.fields.items() ..." But how often would you want to list the fields available in a given project? (Perhaps in preferences, when adding new fields, etc, but not often). All we need to do to query all fields of project p is "FieldDescriptions.query.filter_by(proje
4. > `Ticket.setvalue()` removes a ticket?
Well, kind of. Tickets are never removed but something (whatever that may be) is changed to indicate the "removal". Hence a TicketChange is created which is done through setvalue. Had there been a "active" field or something like that in the Ticket table, that would've been a different story.
5. > Use the `.` operator to show membership, as in `Ticket.fetch`
I've done that for Ticket.fetch and FieldDescription.fetch, but if I did that for something like TicketSystem:add_ticket, that would imply that add_ticket is a classmethod, which it of course isn't.
6. > How do you add a `Field` with some value? Will this work?:
> `t = Ticket(project=p, summary="bla", reporter="gary", milestone="someday")`
You create a ticket using add_ticket. It will get the default values of all the existing fields. To add a new field, you'll use add_field and the ticket will get the default value. To change those values, you'll have to go in and make TicketChanges. It's also possible to access the t.fields['field'] dict and make assignments in the Field objects returned.
So t = Ticket(project=p, reporter="gary")
t.fields['summary'].value = 'bla'
BTW, this hasn't been tested. I'm tired at the moment, lol, let me know if I've done something wrong here.
7. > `t.fields.keys`: isn't this only strings, not the actual instances?
Yes, that's true. But then again, why would you ever need to access FieldDescription objects via tickets?
Your comments were extremely helpful and I've made many changes thanks to them. Veyr much appreciated.