Skip to content

Instantly share code, notes, and snippets.

@wpjunior
Created October 9, 2012 18:08
Show Gist options
  • Select an option

  • Save wpjunior/3860415 to your computer and use it in GitHub Desktop.

Select an option

Save wpjunior/3860415 to your computer and use it in GitHub Desktop.
Prova/models.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2012 Wilson Pinto Júnior <[email protected]>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import datetime
from bson import ObjectId
from django.http import HttpResponse
from django.core.servers.basehttp import FileWrapper
from bson import ObjectId
from mongoengine import *
from mongoengine.queryset import Q, QuerySet
from eleicoes.accounts.models import Eleitor
from eleicoes.unidades.models import Unidade, Turma, Serie
from constants import *
class Opcao(EmbeddedDocument):
_id = ObjectIdField(default=ObjectId)
nome = StringField(max_length=200)
correct = BooleanField(default=False)
meta = {'allow_inheritance': False}
@property
def pk(self):
return self._id
@classmethod
def load(cls, data):
"""
Carrega a questão vindo de um arquivo JSON
"""
obj = cls()
_id = data.get('id', None)
if _id:
obj._id = ObjectId(_id)
obj.nome = data.get('nome')
obj.correct = data.get('correct')
return obj
def to_json(self):
return {
'id': str(self._id),
'nome': self.nome,
'correct': self.correct
}
class Questao(EmbeddedDocument):
_id = ObjectIdField(default=ObjectId)
questao = StringField()
tp = StringField(
verbose_name=u"Tipo de questão",
choices=QUESTAO_TP_CHOICES)
opcoes = ListField(EmbeddedDocumentField(Opcao))
pontos = IntField()
meta = {'allow_inheritance': False}
@classmethod
def load(cls, data):
"""
Carrega a questão vindo de um arquivo JSON
"""
obj = cls()
if data.has_key('id'):
obj._id = ObjectId(data['id'])
obj.tp = data.get('tp')
obj.questao = data.get('questao')
obj.pontos = data.get('pontos')
if data.has_key('opcoes'):
obj.opcoes = [Opcao.load(d) for d in data['opcoes']]
else:
obj.opcoes = []
return obj
def to_json(self):
o = {
'id': str(self._id),
'questao': self.questao,
'tp': self.tp,
'opcoes': [o.to_json() for o in self.opcoes],
'pontos': self.pontos
}
return o
class ProvaQuerySet(QuerySet):
def open_for_eleitor(self, user):
"""
Retorna as provas disponíveis para o eleitor
"""
self.filter(
(Q(serie=user.serie, turma=None, unidade=None)| # Restrito a série do eleitor
Q(serie=user.serie, turma=None, unidade=user.unidade)| # quando uma prova é amarrada pela série/unidade
Q(serie=None, turma=None, unidade=None)| # quando uma prova é pública a todos eleitores
Q(serie=None, turma=None, unidade=user.unidade)| # quando uma prova é para apenas uma unidade
Q(turma=user.turma)), # quando uma prova é amarrada pela turma
status='a')
return self
class Prova(Document):
nome = StringField(required=True, max_length=150)
questoes = ListField(EmbeddedDocumentField(Questao))
status = StringField(
required=True,
verbose_name="Status",
choices=PROVA_STATUS_CHOICES)
unidade = ReferenceField(
Unidade, verbose_name="Unidade")
serie = ReferenceField(
Serie, verbose_name=u"Série")
turma = ReferenceField(
Turma, verbose_name="Turma")
categoria = StringField(
required=False,
verbose_name="Categoria",
max_length=200)
pontuacao_maxima = IntField()
meta = {'allow_inheritance': False,
'queryset_class': ProvaQuerySet}
def get_resultados_url(self):
return "/provas/resultados/%s/" % self.pk
def load(self, data):
"""
Carrega informações atravez de um JSON
"""
self.nome = data.get('nome')
self.status = data.get('status')
self.categoria = data.get('categoria')
if data.get('serie', None):
self.serie = Serie.objects.with_id(data['serie'])
else:
self.serie = None
if data.get('unidade', None):
self.unidade = Unidade.objects.with_id(data['unidade'])
else:
self.unidade = None
if data.get('turma', None):
self.turma = Turma.objects.with_id(data['turma'])
else:
self.turma = None
if data.has_key('questoes'):
self.questoes = [Questao.load(d) for d in data['questoes']]
else:
self.questoes = []
def save(self, *args, **kwargs):
self.calculate_pontuacao_maxima()
return super(Prova, self).save(*args, **kwargs)
def calculate_pontuacao_maxima(self):
self.pontuacao_maxima = sum([
q.pontos for q in self.questoes])
def get_absolute_url(self):
return '/provas/%s/' % self.pk
def get_responder_url(self):
return '/provas/responder/%s/' % self.pk
def get_resultado_url(self):
return '/provas/resultado/%s/' % self.pk
def pontos_list_sorted_by_name(self):
lista = [
("/provas/resposta/%s" % pk, eleitor.get_full_name(), pontos)
for pk, eleitor, pontos in Resposta.objects(
prova=self).scalar('pk', 'eleitor', 'pontuacao')]
return sorted(lista, key=lambda x: x[1])
def pontos_list_sorted_by_pontos(self):
return list([
("/provas/resposta/%s" % pk, eleitor.get_full_name(), pontos)
for pk, eleitor, pontos in Resposta.objects(
prova=self).order_by('-pontuacao').scalar('pk', 'eleitor', 'pontuacao')])
def to_json(self):
o = {
'nome': self.nome,
'status': self.status}
if self.categoria:
o['categoria'] = self.categoria
if self.questoes:
o['questoes'] = [q.to_json() for q in self.questoes]
if self.serie:
o['serie'] = str(self.serie.pk)
if self.unidade:
o['unidade'] = str(self.unidade.pk)
if self.turma:
o['turma'] = str(self.turma.pk)
return o
def resultado_by_unidade(self):
for unidade in Resposta.objects(prova=self).distinct('unidade'):
yield ResultadoUnidade(unidade=unidade, prova=self)
@property
def resultado_pontuacao_maxima(self):
max_obj = Resposta.objects(
prova=self).order_by(
'-pontuacao').first()
if max_obj:
return max_obj.pontuacao
else:
return 0
@property
def resultado_pontuacao_minima(self):
min_obj = Resposta.objects(
prova=self).order_by(
'pontuacao').first()
if min_obj:
return min_obj.pontuacao
else:
return 0
@property
def resultado_pontuacao_media(self):
avg = Resposta.objects(
prova=self).average('pontuacao')
return "%0.4f" % avg
@property
def resultado_total_alunos(self):
return Eleitor.objects(tp="A", is_active=True).count()
@property
def resultado_total_provas(self):
return Resposta.objects(prova=self).count()
class QuestaoResposta(EmbeddedDocument):
_id = ObjectIdField()
correct = BooleanField()
opcao = ObjectIdField()
opcoes = ListField(
ObjectIdField())
meta = {'allow_inheritance': False}
@property
def pk(self):
return str(self._id)
class RespostaQuerySet(QuerySet):
def get_unidade_avg(self):
"""
Retorna o mapa total da média da prova
"""
map_func = """
function() {
if (this.unidade)
var key = this.unidade.$id.toString();
else
var key = null;
var out = {
pontuacao: this.pontuacao,
count: 1, avg: 0.0,
series: {}}
if (this.serie) {
var serieOut = {
pontuacao: this.pontuacao, count: 1, avg: 0.0, turmas: {}};
if (this.turma) {
serieOut.turmas[this.turma.$id.toString()] = {
pontuacao: this.pontuacao, count: 1, avg: 0.0}
}
out.series[this.serie.$id.toString()] = serieOut;
}
emit(key, out);
}
"""
reduce_func = """
function(key, values) {
var out = {count: 0, pontuacao: 0.0, avg: 0.0, series: {}};
values.forEach(function (value) {
out.count += value.count;
out.pontuacao += value.pontuacao;
if (value.series) {
for (var serie in value.series) {
if (!out.series[serie])
out.series[serie] = {pontuacao: 0, count: 0, avg: 0.0, turmas: {}};
out.series[serie].count += value.series[serie].count;
out.series[serie].pontuacao += value.series[serie].pontuacao;
if (value.series[serie].turmas) {
for (var turma in value.series[serie].turmas) {
if (!out.series[serie].turmas[turma])
out.series[serie].turmas[turma] = {pontuacao: 0, count: 0, avg: 0.0};
out.series[serie].turmas[turma].count += value.series[serie].turmas[turma].count;
out.series[serie].turmas[turma].pontuacao += value.series[serie].turmas[turma].pontuacao;
}
}
}
}
});
return out;
}
"""
finalize_func = """
function (key, value) {
if (value.count > 0)
value.avg = value.pontuacao / value.count;
if (value.series) {
for (var serie in value.series) {
value.series[serie].avg = value.series[serie].pontuacao / value.series[serie].count;
if (value.series[serie].turmas) {
for (var turma in value.series[serie].turmas) {
value.series[serie].turmas[turma].avg = (
value.series[serie].turmas[turma].pontuacao / value.series[serie].turmas[turma].count)
}
}
}
}
return value;
}
"""
values = self.map_reduce(
map_f=map_func, reduce_f=reduce_func,
output='inline', finalize_f=finalize_func)
_map = {}
for v in values:
_map[v.key] = v.value
serie_map = dict([
(str(pk), nome)
for pk, nome in Serie.objects.scalar('pk', 'nome')])
for pk, unidade in Unidade.objects.in_bulk([
ObjectId(u) for u in _map.iterkeys() if u]).iteritems():
unidade_data = _map[str(pk)]
unidade_data['nome'] = unidade.nome
unidade_data['pk'] = str(pk)
for serie_pk, serie in unidade_data['series'].iteritems():
serie_data = unidade_data['series'][str(serie_pk)]
serie_data['pk'] = str(serie_pk)
serie_data['nome'] = serie_map.get(serie_pk)
for turma_pk, turma in Turma.objects.in_bulk([
ObjectId(t) for t in serie_data['turmas'].iterkeys() if t]).iteritems():
turma_data = serie_data['turmas'][str(turma_pk)]
turma_data['pk'] = str(turma_pk)
turma_data['nome'] = turma.nome
serie_data['turmas'] = serie_data['turmas'].values()
unidade_data['series'] = unidade_data['series'].values()
return _map.values()
class Resposta(Document):
eleitor = ReferenceField(
'Eleitor', required=True, dbref=True)
serie = ReferenceField('Serie', dbref=True)
unidade = ReferenceField('Unidade', dbref=True)
turma = ReferenceField('Turma', dbref=True)
prova = ReferenceField(
Prova, required=True, dbref=True)
pontuacao = IntField()
resp = ListField(EmbeddedDocumentField(
QuestaoResposta))
meta = {'allow_inheritance': False,
'queryset_class': RespostaQuerySet}
def scalar_questoes(self):
resp_questoes_map = dict([
(str(r._id), r)
for r in self.resp])
for questao in self.prova.questoes:
yield QuestaoAdapter(resp_questoes_map.get(str(questao._id)),
questao)
def get_absolute_url(self):
return "/provas/resposta/%s/" % self.pk
@classmethod
def for_eleitor(cls, user):
respostas = []
for prova in Prova.objects(status='l'):
for resposta in cls.objects(prova=prova, eleitor=user):
resposta.append(resposta)
return respostas
PHOTO_MIMETYPES = {
'PNG': 'image/png',
'JPEG': 'image/jpeg',
'JPG': 'image/jpeg',
#TODO: se encontrar mais coloque aqui
}
class ProvaPhoto(Document):
image = ImageField(
db_alias='fs', #database especial para arquivos
size=(800, 600),
thumbnail_size=(320, 240, False))
created = DateTimeField(default=datetime.datetime.now)
def get_url(self):
return u"/provas/photos/%s.jpg" % self.pk
def get_thumb_url(self):
return u"/provas/photos/%s.thumb.jpg" % self.pk
@property
def mimetype(self):
return PHOTO_MIMETYPES.get(self.image.format)
def as_response(self):
wrapper = FileWrapper(self.image)
response = HttpResponse(wrapper, content_type=self.mimetype)
response['Cache-Control'] = 'no-store, no-cache, must-revalidate'
response['Expires'] = 'Sat, 26 Jul 1997 05:00:00 GMT'
response['Pragma'] = 'no-cache'
return response
def json_format(self):
return {
'pk': str(self.pk),
'url': self.get_url(),
'thumb_url': self.get_thumb_url()
}
def as_thumb_response(self):
wrapper = FileWrapper(self.image.thumbnail)
response = HttpResponse(wrapper, content_type=self.mimetype)
response['Cache-Control'] = 'no-store, no-cache, must-revalidate'
response['Expires'] = 'Sat, 26 Jul 1997 05:00:00 GMT'
response['Pragma'] = 'no-cache'
return response
def delete(self, force=False, *args, **kwargs):
self.image.delete() #apaga a imagem do banco de dados
return super(ProvaPhoto, self).delete(*args, **kwargs)
meta = {'allow_inheritance': False,
'collection': 'prova_photo',
'ordering': ['created'],
'indexes': [
{'fields': ['created']},
]}
class ResultadoUnidade(object):
def __init__(self, unidade, prova):
self.unidade = unidade
self.prova = prova
@property
def total_alunos(self):
return Eleitor.objects(
tp="A", is_active=True,
unidade=self.unidade).count()
@property
def total_provas(self):
return Resposta.objects(
unidade=self.unidade, prova=self.prova).count()
@property
def pontuacao_maxima(self):
max_obj = Resposta.objects(
unidade=self.unidade, prova=self.prova).order_by(
'-pontuacao').first()
if max_obj:
return max_obj.pontuacao
else:
return 0
@property
def pontuacao_minima(self):
min_obj = Resposta.objects(
unidade=self.unidade, prova=self.prova).order_by(
'pontuacao').first()
if min_obj:
return min_obj.pontuacao
else:
return 0
@property
def pontuacao_media(self):
avg = Resposta.objects(
unidade=self.unidade, prova=self.prova).average('pontuacao')
return "%0.4f" % avg
def resultado_by_serie(self):
for serie in Resposta.objects(
prova=self.prova, unidade=self.unidade).distinct('serie'):
yield ResultadoSerie(
prova=self.prova,
unidade=self.unidade,
serie=serie)
class ResultadoSerie(object):
def __init__(self, prova, unidade, serie):
self.prova = prova
self.unidade = unidade
self.serie = serie
@property
def total_alunos(self):
return Eleitor.objects(
tp="A", unidade=self.unidade,
is_active=True,
serie=self.serie).count()
@property
def total_provas(self):
return Resposta.objects(
unidade=self.unidade,
serie=self.serie, prova=self.prova).count()
@property
def pontuacao_maxima(self):
max_obj = Resposta.objects(
unidade=self.unidade,
prova=self.prova,
serie=self.serie).order_by(
'-pontuacao').first()
if max_obj:
return max_obj.pontuacao
else:
return 0
@property
def pontuacao_minima(self):
min_obj = Resposta.objects(
unidade=self.unidade,
prova=self.prova,
serie=self.serie).order_by(
'pontuacao').first()
if min_obj:
return min_obj.pontuacao
else:
return 0
@property
def pontuacao_media(self):
avg = Resposta.objects(
unidade=self.unidade,
prova=self.prova,
serie=self.serie).average('pontuacao')
return "%0.4f" % avg
def resultado_by_turma(self):
for turma in Resposta.objects(
prova=self.prova, unidade=self.unidade,
serie=self.serie).distinct('turma'):
yield ResultadoTurma(
prova=self.prova,
unidade=self.unidade,
serie=self.serie,
turma=turma)
class ResultadoTurma(object):
def __init__(self, prova, serie, unidade, turma):
self.prova = prova
self.serie = serie
self.unidade = unidade
self.turma = turma
@property
def total_alunos(self):
return Eleitor.objects(
tp="A", unidade=self.unidade,
is_active=True,
turma=self.turma).count()
@property
def total_provas(self):
return Resposta.objects(
unidade=self.unidade,
turma=self.turma,
prova=self.prova).count()
@property
def pontuacao_maxima(self):
max_obj = Resposta.objects(
prova=self.prova,
turma=self.turma).order_by(
'-pontuacao').first()
if max_obj:
return max_obj.pontuacao
else:
return 0
@property
def pontuacao_minima(self):
min_obj = Resposta.objects(
prova=self.prova,
turma=self.turma).order_by(
'pontuacao').first()
if min_obj:
return min_obj.pontuacao
else:
return 0
@property
def pontuacao_media(self):
avg = Resposta.objects(
prova=self.prova,
turma=self.turma).average('pontuacao')
return "%0.4f" % avg
class QuestaoAdapter(object):
def __init__(self, questao_resposta, questao):
self.questao_resposta = questao_resposta
self.questao = questao
@property
def nome(self):
return self.questao.questao
@property
def pontos(self):
return self.questao.pontos
@property
def opcoes(self):
return self.questao.opcoes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment