def find_posts_by_perms(user, verb, qsc=None): """ Fetch a list of relevant posts for a given user and verb """ if qsc == None: return UserBit.find_by_anchor_perms(AnnouncementLink, user, verb) else: return UserBit.find_by_anchor_perms(AnnouncementLink, user, verb, qsc=qsc)
def undoCheckIn(self, teacher, prog): """Undo what checkIn does""" userbits = UserBit.valid_objects().filter(user=teacher, qsc=prog.anchor, verb=GetNode('V/Flags/Registration/Teacher/Arrived')) if userbits: userbits.update(enddate=datetime.now()) UserBit.updateCache(teacher.id) return '%s is no longer checked in.' % teacher.name() else: return '%s was not checked in for %s.' % (teacher.name(), prog.niceName())
def bitsByTeacher(self, user): return { 'interview': UserBit.objects.filter(UserBit.not_expired(), verb=self.reg_verb, qsc__parent=self.qscs['interview'], user=user), 'training': UserBit.objects.filter(UserBit.not_expired(), verb=self.reg_verb, qsc__parent=self.qscs['training'], user=user), }
def make_user_admin(target_user): # Set the flags for Django's auth system setattr(target_user, 'is_staff', True) setattr(target_user, 'is_superuser', True) # Set the userbits target_user.userbit_set.add(UserBit(verb = GetNode('V/Administer'), qsc = GetNode('Q'))) target_user.userbit_set.add(UserBit(verb = GetNode('V/Flags/UserRole/Administrator'), qsc = GetNode('Q'))) # Clear the UserBit cache for this user UserBit.objects.cache(target_user).update() target_user.save()
def barcodecheckin(self, request, tl, one, two, module, extra, prog): context = {} attended_verb = GetNode('V/Flags/Registration/Attended') prog_anchor = prog.anchor if request.method == 'POST': results = { 'not_found': [], 'existing': [], 'new': [], 'not_student': [] } form = OnsiteBarcodeCheckinForm(request.POST) if form.is_valid(): codes = form.cleaned_data['uids'].split() for code in codes: try: result = ESPUser.objects.filter(id=code) except ValueError: results['not_found'].append(code) if len(result) > 1: raise ESPError( False ), "Something weird happened, there are two students with ID %s." % code elif len(result) == 0: results['not_found'].append(code) else: student = result[0] if student.isStudent(): existing = UserBit.valid_objects().filter( user=student, qsc=prog_anchor, verb=attended_verb) if existing: results['existing'].append(code) else: new = UserBit(user=student, qsc=prog_anchor, verb=attended_verb) new.save() results['new'].append(code) else: results['not_student'].append(code) else: results = {} form = OnsiteBarcodeCheckinForm() context['module'] = self context['form'] = form context['results'] = results return render_to_response(self.baseDir() + 'barcodecheckin.html', request, (prog, tl), context)
def subscribe_user(self, user): verb = GetNode('V/Subscribe') from esp.users.models import ESPUser, User if type(user) != User and type(user) != ESPUser: assert False, 'EXPECTED USER, received %s' \ % str(type(user)) ub = UserBit.objects.filter(verb=verb, qsc=self.anchor, user=user) if ub.count() > 0: return False ub = UserBit(verb=verb, qsc=self.anchor, user=user) ub.save() return True
def navBarDown(request, navbar, node, section): """ Swap the sort_rank of the specified NavBarEntry and the NavBarEntry immediately after it in the list of NavBarEntrys associated with this tree node, so that this NavBarEntry appears to move down one unit on the page Fail silently if this is not possible """ if not UserBit.UserHasPerms(request.user, navbar.path, GetNode(EDIT_VERB_STRING)): raise PermissionDenied, "You don't have permisssion to do that!" navbarList = NavBarEntry.objects.filter( path=navbar.path).order_by('sort_rank') if not navbar.indent: navbarList = navbarList.filter(indent=False) last_n = None for n in navbarList: if last_n != None and navbar == last_n: temp_sort_rank = n.sort_rank n.sort_rank = last_n.sort_rank last_n.sort_rank = temp_sort_rank n.save() last_n.save() last_n = n
def accesshandler(req): os.environ.update(req.subprocess_env) uri = req.subprocess_env['REQUEST_URI'] # check for PythonOptions _str_to_bool = lambda s: s.lower() in ('1', 'true', 'on', 'yes') options = req.get_options() permission_verb_name = options.get('ESPPermissionName', 'V/Flags/Public') settings_module = options.get('DJANGO_SETTINGS_MODULE', None) if settings_module: os.environ['DJANGO_SETTINGS_MODULE'] = settings_module from esp.users.models import UserBit from esp.datatree.models import DataTree, GetNode, QTree, get_lowest_parent, StringToPerm, PermToString request = AccessHandler()(req) if request.user.is_authenticated(): qsc = get_lowest_parent('Q/Static/' + uri.strip('/')) verb = get_lowest_parent(permission_verb_name) if UserBit.UserHasPerms(request.user, qsc, verb): return apache.OK return apache.HTTP_UNAUTHORIZED
def teacher_lookup(request, limit=10): # FIXME: REQUIRE PERMISSIONS! # Initialize anchors for identifying teachers q = GetNode('Q') v = GetNode('V/Flags/UserRole/Teacher') # Select teachers queryset = UserBit.bits_get_users(q, v) # Search for teachers with names that start with search string startswith = request.GET['q'] parts = startswith.split(', ') Q_name = Q(user__last_name__istartswith=parts[0]) if len(parts) > 1: Q_name = Q_name & Q(user__first_name__istartswith=parts[1]) # Isolate user objects queryset = queryset.filter(Q_name)[:(limit * 10)] users = [ub.user for ub in queryset] user_dict = {} for user in users: user_dict[user.id] = user users = user_dict.values() # Construct combo-box items obj_list = [[user.last_name + ', ' + user.first_name, user.id] for user in users] # Operation Complete! return JsonResponse(obj_list)
def classTemplateEditor(request, program, session): """ Generate and display a listing of all QSD pages in the Class template within the specified program (QSD pages that are created automatically when a new class is created) """ qsd_pages = [] try: template_node = GetNodeOrNoBits( 'Q/Programs/' + program + '/' + session + '/Template', request.user) except DataTree.NoSuchNodeException: raise Http404 for qsd in template_node.quasistaticdata_set.all(): qsd_pages.append({ 'edit_url': qsd.name + ".edit.html", 'view_url': qsd.name + ".html", 'page': qsd }) have_create = UserBit.UserHasPerms(request.user, template_node, GetNode('V/Administer/Edit')) return render_to_response('display/qsd_listing.html', request, program, { 'qsd_pages': qsd_pages, 'have_create': have_create })
def getSchedule(program, student): accept_node = GetNode('V/Flags/Registration/Accepted') schedule = """ Student schedule for %s: Time | Class | Room""" % student.name() classes = list(UserBit.find_by_anchor_perms(ClassSubject, student, accept_node).filter(parent_program = program)) # now we sort them by time/title classes.sort() for cls in classes: rooms = cls.prettyrooms() if len(rooms) == 0: rooms = 'N/A' else: rooms = ", ".join(rooms) schedule += """ %s|%s|%s""" % (",".join(cls.friendly_times()).ljust(20), cls.title().ljust(25), rooms) return schedule
def get_visible_announcements(user, limit, tl): verb = GetNode('V/Subscribe') models_to_search = [Entry, AnnouncementLink] results = [] grand_total = 0 overflowed = False for model in models_to_search: result = UserBit.find_by_anchor_perms(model, user, verb).order_by('-timestamp').filter(Q(highlight_expire__gte = datetime.now()) | Q(highlight_expire__isnull = True)) if tl: result = result.filter(section=tl) if limit: overflowed = ((len(result) - limit) > 0) total = len(result) result = result[:limit] else: overflowed = False total = len(result) results += result grand_total += total return {'announcementList': results, 'overflowed': overflowed, 'total': grand_total}
def render(self, context): try: user = self.user_variable.resolve(context) except template.VariableDoesNotExist: user = None try: anchor = template.Variable(self.input_anchor) anchor = anchor.resolve(context) except: anchor = GetNode(self.input_anchor) try: qsd = template.Variable(self.qsd_name) qsd = qsd.resolve(context) except: qsd = self.qsd_name edit_bits = UserBit.UserHasPerms(user, anchor, DataTree.get_by_uri('V/Administer/Edit')) qsd_obj = QuasiStaticData.objects.get_by_path__name(anchor, qsd) if qsd_obj == None: new_qsd = QuasiStaticData() new_qsd.path = anchor new_qsd.name = qsd new_qsd.title = qsd new_qsd.content = self.nodelist.render(context) if getattr(user, 'id', False): new_qsd.author = user new_qsd.save() qsd_obj = new_qsd return render_to_response("inclusion/qsd/render_qsd_inline.html", {'qsdrec': qsd_obj, 'edit_bits': edit_bits}, context_instance=context).content
def ajax_qsd(request): """ Ajax function for in-line QSD editing. """ from django.utils import simplejson from esp.lib.templatetags.markdown import markdown EDIT_VERB = 'V/Administer/Edit/QSD' result = {} post_dict = request.POST.copy() if (request.user.id is None): return HttpResponse( content= 'Oops! Your session expired!\nPlease open another window, log in, and try again.\nYour changes will not be lost if you keep this page open.', status=500) if post_dict['cmd'] == "update": qsdold = QuasiStaticData.objects.get(id=post_dict['id']) if not UserBit.UserHasPerms(request.user, qsdold.path, EDIT_VERB): return HttpResponse( content='Sorry, you do not have permission to edit this page.', status=500) qsd = qsdold.copy() qsd.content = post_dict['data'] qsd.load_cur_user_time(request, ) # Local change here, to enable QSD editing. qsd.save() result['status'] = 1 result['content'] = markdown(qsd.content) result['id'] = qsd.id if post_dict['cmd'] == "create": qsd_path = DataTree.objects.get(id=post_dict['anchor']) if not UserBit.UserHasPerms(request.user, qsd_path, EDIT_VERB): return HttpResponse( content="Sorry, you do not have permission to edit this page.", status=500) qsd, created = QuasiStaticData.objects.get_or_create( name=post_dict['name'], path=qsd_path, defaults={'author': request.user}) qsd.content = post_dict['data'] qsd.author = request.user qsd.save() result['status'] = 1 result['content'] = markdown(qsd.content) result['id'] = qsd.id return HttpResponse(simplejson.dumps(result))
def get_regdate(self, ordering='startdate'): reg_verb = GetNode('V/Flags/Registration/Enrolled') reg_node_parent = self.program.anchor['Classes'] bits = UserBit.valid_objects().filter( user=self.user, verb=reg_verb).filter(QTree(qsc__below=reg_node_parent)) if bits.exists(): return bits.order_by(ordering).values_list( 'startdate', flat=True)[0].strftime("%Y-%m-%d %H:%M:%S")
def extraform(self, request, tl, one, two, module, extra, prog): custom_form_id = Tag.getProgramTag('%s_extraform_id' % tl, prog, None) if custom_form_id: cf = Form.objects.get(id=int(custom_form_id)) else: raise ESPError( False ), 'Cannot find an appropriate form for the quiz. Please ask your administrator to create a form and set the %s_extraform_id Tag.' % tl form_wizard = FormHandler(cf, request, request.user).get_wizard() form_wizard.curr_request = request if request.method == 'POST': form = form_wizard.get_form(0, request.POST, request.FILES) if form.is_valid(): # Delete previous responses from this user dmh = DynamicModelHandler(cf) form_model = dmh.createDynModel() form_model.objects.filter(user=request.user).delete() form_wizard.done([form]) bit, created = UserBit.valid_objects().get_or_create( user=request.user, qsc=self.program.anchor, verb=self.reg_verb) return self.goToCore(tl) else: # If the user already filled out the form, use their earlier response for the initial values if self.isCompleted(): dmh = DynamicModelHandler(cf) form_model = dmh.createDynModel() prev_results = form_model.objects.filter( user=request.user).order_by('-id') if prev_results.exists(): prev_result_data = {} plain_form = form_wizard.get_form(0) # Load previous results, with a hack for multiple choice questions. for field in plain_form.fields: if isinstance(plain_form.fields[field], forms.MultipleChoiceField): prev_result_data[field] = getattr( prev_results[0], field).split(';') else: prev_result_data[field] = getattr( prev_results[0], field) form_wizard = FormHandler( cf, request, request.user).get_wizard( initial_data={0: prev_result_data}) form = form_wizard.get_form(0) return render_to_response(self.baseDir() + 'custom_form.html', request, (prog, tl), { 'prog': prog, 'form': form, 'tl': tl })
def _checkStudent(moduleObj, request, *args, **kwargs): if not_logged_in(request): return HttpResponseRedirect('%s?%s=%s' % (LOGIN_URL, REDIRECT_FIELD_NAME, quote(request.get_full_path()))) if not request.user.isStudent() and not request.user.isAdmin(moduleObj.program): allowed_student_types = Tag.getTag("allowed_student_types", moduleObj.program, default='') matching_user_types = UserBit.valid_objects().filter(user=request.user, verb__parent=GetNode("V/Flags/UserRole"), verb__name__in=allowed_student_types.split(",")) if not matching_user_types: return render_to_response('errors/program/notastudent.html', request, (moduleObj.program, 'learn'), {}) return method(moduleObj, request, *args, **kwargs)
def send_event_notice(event_start, event_end): """ Send event reminders for all events, if any fraction of an event occurs in the given time range. Send to all users who are subscribed to each event. """ messages = [] for e in Event.objects.filter(start__lte=event_end, end__gte=event_start): m = event_to_message(e) messages.append(m) for u in UserBit.bits_get_users(e.anchor, GetNode('V/Subscribe'), now = e.start, end_of_now = e.end).filter(startdate__lt=e.end, enddate__gt=e.start): user_to_email(m, u) EmailController().run(messages)
def select_lunch(self, request, tl, one, two, module, extra, prog): context = {'prog': self.program} user = request.user dates = prog.dates() if request.method == 'POST': forms = [ StudentLunchSelectionForm(prog, user, dates[i], request.POST, prefix='day%d' % i) for i in range(len(dates)) ] all_valid = True success = True for form in forms: if not form.is_valid(): all_valid = False if all_valid: context['messages'] = [] for form in forms: (result, msg) = form.save_data() if not result: success = False context['messages'] += [msg] if success: bit, created = UserBit.valid_objects().get_or_create( user=user, qsc=prog.anchor, verb=GetNode('V/Flags/Registration/LunchSelected')) return self.goToCore(tl) else: context['errors'] = True else: forms = [ StudentLunchSelectionForm(prog, user, dates[i], prefix='day%d' % i) for i in range(len(dates)) ] for i in range(len(forms)): forms[i].load_data() if 'messages' in context: print context['messages'] context['forms'] = forms return render_to_response(self.baseDir() + 'select_lunch.html', context)
def createBit(self, extension): verb = GetNode('V/Flags/Registration/' + extension) ub = UserBit.objects.filter(user=self.student, verb=verb, qsc=self.program_anchor_cached()) if len(ub) > 0: return False ub = UserBit() ub.verb = verb ub.qsc = self.program_anchor_cached() ub.user = self.student ub.recursive = False ub.save() return True
def setUp(self): SeleniumTestCase.setUp(self) # Make Q/Web public UserBit.objects.create(verb=GetNode('V/Flags/Public'), qsc=GetNode('Q/Web')) # Make our users self.admin_user, created = ESPUser.objects.get_or_create( username='******', first_name='Harry', last_name='Alborez') self.admin_user.set_password(self.PASSWORD_STRING) make_user_admin(self.admin_user) self.qsd_user, created = ESPUser.objects.get_or_create( username='******', first_name='Aylik', last_name='Kewesd') self.qsd_user.set_password(self.PASSWORD_STRING) self.qsd_user.userbit_set.add( UserBit(verb=GetNode('V/Administer/Edit'), qsc=GetNode('Q'), recursive=True)) self.qsd_user.save() # Check that a NavBarCategory exists if len(NavBarCategory.objects.all()) < 1: nbc = NavBarCategory() nbc.name = 'default' nbc.save() # Make our test page qsd_rec_new = QuasiStaticData() qsd_rec_new.path = GetNode('Q/Web') qsd_rec_new.name = 'test' qsd_rec_new.author = self.admin_user qsd_rec_new.nav_category = NavBarCategory.default() qsd_rec_new.content = '' qsd_rec_new.title = 'Test page' qsd_rec_new.description = '' qsd_rec_new.keywords = '' qsd_rec_new.save() # Set the port that the webdriver will try to access self.driver.testserver_port = settings.VARNISH_PORT # Add the varnish_purge tag Tag.objects.get_or_create(key='varnish_purge', value='true') # Set up the correct site site = Site.objects.get_current() site.domain = settings.VARNISH_HOST + ":" + str(settings.VARNISH_PORT) site.save()
def startreg(form, programs, students, profiles, result_dict={}): # Get first class registration bit and confirmation bit for each student and bin by day reg_dict = {} confirm_dict = {} for program in programs: reg_dict[program] = {} confirm_dict[program] = {} reg_verb = GetNode('V/Flags/Registration') confirm_verb = GetNode('V/Flags/Public') for student in students: for program in programs: reg_node = GetNode(program.anchor.uri + '/Classes') confirm_node = GetNode(program.anchor.uri + '/Confirmation') reg_bits = UserBit.objects.filter(user=student).filter( QTree(verb__below=reg_verb)).filter( QTree(qsc__below=reg_node)).order_by('startdate') if reg_bits.exists(): if reg_bits[0].startdate.date() not in reg_dict[program]: reg_dict[program][reg_bits[0].startdate.date()] = 0 reg_dict[program][reg_bits[0].startdate.date()] += 1 confirm_bits = UserBit.valid_objects().filter( user=student, verb=confirm_verb, qsc=confirm_node).order_by('-startdate') if confirm_bits.exists(): if confirm_bits[0].startdate.date( ) not in confirm_dict[program]: confirm_dict[program][confirm_bits[0].startdate.date()] = 0 confirm_dict[program][confirm_bits[0].startdate.date()] += 1 # Compile and render startreg_list = [] confirm_list = [] for program in programs: reg_dates = reg_dict[program].keys() reg_dates.sort() reg_counts = [reg_dict[program][key] for key in reg_dates] startreg_list.append(zip(reg_dates, reg_counts)) confirm_dates = confirm_dict[program].keys() confirm_dates.sort() confirm_counts = [confirm_dict[program][key] for key in confirm_dates] confirm_list.append(zip(confirm_dates, confirm_counts)) result_dict['program_data'] = zip(programs, startreg_list, confirm_list) return render_to_string('program/statistics/startreg.html', result_dict)
def authenhandler(req, **kwargs): """ Authentication handler that checks against Django's auth database. """ # mod_python fakes the environ, and thus doesn't process SetEnv. This fixes # that so that the following import works os.environ.update(req.subprocess_env) uri = req.subprocess_env['REQUEST_URI'] # check for PythonOptions _str_to_bool = lambda s: s.lower() in ('1', 'true', 'on', 'yes') options = req.get_options() permission_verb_name = options.get('ESPPermissionName', 'V/Flags/Public') settings_module = options.get('DJANGO_SETTINGS_MODULE', None) if settings_module: os.environ['DJANGO_SETTINGS_MODULE'] = settings_module from esp.users.models import UserBit from esp.datatree.models import DataTree, GetNode, QTree, get_lowest_parent, StringToPerm, PermToString from django.contrib.auth.models import User from django import db db.reset_queries() # check that the username is valid kwargs = {'username': req.user, 'is_active': True} try: try: user = User.objects.get(**kwargs) except User.DoesNotExist: return apache.HTTP_UNAUTHORIZED # check the password and any permission given if user.check_password(req.get_basic_auth_pw()): if user.is_authenticated(): qsc = get_lowest_parent('Q/Static/' + uri.strip('/')) verb = get_lowest_parent(permission_verb_name) if UserBit.UserHasPerms(user, qsc, verb): return apache.OK else: return apache.HTTP_UNAUTHORIZED else: return apache.HTTP_UNAUTHORIZED finally: db.connection.close()
def teachers(self, QObject=False): """Returns lists of teachers who've completed the teacher quiz.""" qo = Q( userbit__verb=self.controller.reg_verb, userbit__qsc=self.program_anchor_cached(), ) & UserBit.not_expired(prefix='userbit__') if QObject is True: return { 'quiz_done': self.getQForUser(qo), } else: return { 'quiz_done': ESPUser.objects.filter(qo).distinct(), }
def _checkDeadline_helper(method, extension, moduleObj, request, tl, *args, **kwargs): from esp.users.models import UserBit from esp.datatree.models import DataTree, GetNode, QTree, get_lowest_parent, StringToPerm, PermToString if tl != 'learn' and tl != 'teach': return (True, None) response = None canView = False if not_logged_in(request): response = HttpResponseRedirect('%s?%s=%s' % (LOGIN_URL, REDIRECT_FIELD_NAME, quote(request.get_full_path()))) else: canView = request.user.updateOnsite(request) if not canView: canView = UserBit.UserHasPerms(request.user, request.program.anchor_id, GetNode('V/Deadline/Registration/'+{'learn':'Student', 'teach':'Teacher'}[tl]+extension)) return (canView, response)
def printschedules(self, request, tl, one, two, module, extra, prog): " A link to print a schedule. " if not request.GET.has_key('sure') and not request.GET.has_key( 'gen_img'): printers = [x.name for x in GetNode('V/Publish/Print').children()] return render_to_response(self.baseDir() + 'instructions.html', request, (prog, tl), {'printers': printers}) if request.GET.has_key('sure'): return render_to_response( self.baseDir() + 'studentschedulesrenderer.html', request, (prog, tl), {}) verb_path = 'V/Publish/Print' if extra and extra != '': verb_path = "%s/%s" % (verb_path, extra) verb = GetNode(verb_path) qsc = self.program_anchor_cached().tree_create(['Schedule']) Q_qsc = Q(qsc=qsc.id) Q_verb = Q(verb__in=[verb.id] + list(verb.children())) ubits = UserBit.valid_objects().filter(Q_qsc & Q_verb).order_by( 'startdate')[:1] for ubit in ubits: ubit.enddate = datetime.now() ubit.save() # get students old_students = set([ESPUser(ubit.user) for ubit in ubits]) if len(old_students) > 0: response = ProgramPrintables.get_student_schedules( request, list(old_students), prog, onsite=True) # set the refresh rate #response['Refresh'] = '2' return response else: # No response if no users return HttpResponse('')
def edit_profile(request, module): curUser = ESPUser(request.user) if curUser.isStudent(): return profile_editor(request, None, True, 'student') elif curUser.isTeacher(): return profile_editor(request, None, True, 'teacher') elif curUser.isGuardian(): return profile_editor(request, None, True, 'guardian') elif curUser.isEducator(): return profile_editor(request, None, True, 'educator') else: user_types = UserBit.valid_objects().filter(verb__parent=GetNode("V/Flags/UserRole")).select_related().order_by('-id') return profile_editor(request, None, True, user_types[0].verb.name if user_types else '')
def send_miniblog_messages(): entries = Entry.objects.filter(email = True, sent = False) for entry in entries: entry.sent = True entry.save() verb = GetNode('V/Subscribe') if hasattr(settings, 'EMAILTIMEOUT') and settings.EMAILTIMEOUT is not None: wait = settings.EMAILTIMEOUT else: wait = 1.5 for entry in entries: if entry.fromemail is None or len(entry.fromemail.strip()) == 0: if entry.fromuser is None or type(entry.fromuser) == AnonymousUser: fromemail = '*****@*****.**' else: fromemail = '%s <%s>' % (ESPUser(entry.fromuser).name(), entry.fromuser.email) else: fromemail = entry.fromemail emails = {} bits = UserBit.bits_get_users(qsc = entry.anchor, verb = verb) for bit in bits: if bit.user is None or type(bit.user) == AnonymousUser: # print "Error with %s (%s)" % (str(entry), str(bit.user)) pass else: emails[bit.user.email] = ESPUser(bit.user).name() for email,name in emails.items(): send_mail(entry.title, entry.content, fromemail, ['%s <%s>' % (name, email)], True) print "Sent mail to %s" % (name) time.sleep(wait)
def myesp_onsite(request, module): user = ESPUser(request.user) if not user.isOnsite(): raise ESPError(False), 'You are not a valid on-site user, please go away.' verb = GetNode('V/Registration/OnSite') progs = UserBit.find_by_anchor_perms(Program, user = user, verb = verb) # Order them decreasing by id # - Currently reverse the list in Python, otherwise fbap's cache is ignored # TODO: Fix this progs = list(progs) progs.reverse() if len(progs) == 1: return HttpResponseRedirect('/onsite/%s/main' % progs[0].getUrlBase()) else: navnode = GetNode('Q/Web/myesp') return render_to_response('program/pickonsite.html', request, navnode, {'progs': progs})
def ajax_sections_cached(self, prog): sections = prog.sections().select_related() rrequests = ResourceRequest.objects.filter(target__in = sections) rrequest_dict = defaultdict(list) for r in rrequests: rrequest_dict[r.target_id].append((r.res_type_id, r.desired_value)) teacher_bits = UserBit.valid_objects().filter(verb=GetNode('V/Flags/Registration/Teacher'), qsc__in = (s.parent_class.anchor_id for s in sections), user__isnull=False).values("qsc_id", "user_id").distinct() teacher_dict = defaultdict(list) for b in teacher_bits: teacher_dict[b["qsc_id"]].append(b["user_id"]) sections_dicts = [ { 'id': s.id, 'class_id': s.parent_class_id, 'emailcode': s.emailcode(), 'text': s.title(), 'category': s.category.category, 'length': float(s.duration), 'teachers': teacher_dict[s.parent_class.anchor_id], 'resource_requests': rrequest_dict[s.id], 'max_class_capacity': s.max_class_capacity, 'capacity': s.capacity, 'class_size_max': s.parent_class.class_size_max, 'optimal_class_size': s.parent_class.class_size_optimal, 'optimal_class_size_range': s.parent_class.optimal_class_size_range.range_str() if s.parent_class.optimal_class_size_range else None, 'allowable_class_size_ranges': [ cr.range_str() for cr in s.parent_class.get_allowable_class_size_ranges() ], 'status': s.status, 'parent_status': s.parent_class.status, 'grades': [s.parent_class.grade_min, s.parent_class.grade_max], 'prereqs': s.parent_class.prereqs, 'comments': s.parent_class.message_for_directors, } for s in sections ] response = HttpResponse(content_type="application/json") simplejson.dump(sections_dicts, response) return response