Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
*.pyc
.DS_Store
.venv
*.sqlite3
21 changes: 4 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,8 @@
# PROCESSO DE SELEÇÃO DE PESSOA DESENVOLVEDORA

Se você não tem experiência com o Django, recomendamos que você faça pelo menos
este tutorial antes de começar:
https://docs.djangoproject.com/en/3.1/intro/tutorial01/

Neste repositório, encontra-se o código de um sistema simples desenvolvido em
Django(3.1.X). O sistema consiste em uma página que contém uma questão de
múltipla escolha, ao respondê-la o usuário recebe um feedback de acerto ou erro.


## Para participar desta parte do processo você deve:
- Clonar esse repositório;
- Criar uma branch com o nome observando o padrão `desafio-nome-sobrenome` (por exemplo: `desafio-maria-silva`);
- Desenvolver as histórias abaixo na branch que você criou, de preferência com pelo menos um commit na finalização de cada história;
- Colocar no arquivo Readme: seu nome, email e outras observações que julgar adequadas;
- Ao terminar o desenvolvimento, abra um pull request para a branch `master`. Se não tiver permissão, nos informe seu usuário do Github;
- Nos avise por email quando concluir.
- Artur Felipe da Silva Veloso
- arturfdasveloso@gmail.com
- (86) 99927-2370
- Teresina/PI

## Considerações:
- Se não for possível fazer todas as histórias, entregue apenas as histórias que você fez.
Expand Down
23 changes: 22 additions & 1 deletion question/admin.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
from django.contrib import admin
from .models import Question, Alternatives, QuestionLogs

# Register your models here.
# Register admin models
admin.site.register(Question)

@admin.register(Alternatives)
class AlternativesAdmin(admin.ModelAdmin):
list_display = (
'alternative_order',
'question',
'alternative_text',
'is_correct'
)

@admin.register(QuestionLogs)
class QuestionLogsAdmin(admin.ModelAdmin):
list_display = (
'user',
'question',
'chosen_alternative',
'is_correct',
'answer_date'
)
57 changes: 56 additions & 1 deletion question/models.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,58 @@
from django.db import models
from django.contrib.auth.models import User

# Create your models here.
# Models
class Question(models.Model):
question_text = models.TextField(verbose_name="Questão")

def __str__(self):
return self.question_text

class Meta:
ordering = ('pk',)
verbose_name = 'Questão'
verbose_name_plural = 'Questões'

class Alternatives(models.Model):
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Boa 👍
Usou a nomenclatura certa para as coisas não ficarem confusas.

Answer sempre foi uma escolha pior, porque aqui o que importa são as alternativas da questão, as respostas são uma coisa ligada ao usuário e assim devem estar relacionadas à tabela de ligação (neste caso QuestionLogs).

Apenas para lembrar, normalmente se usa nomes no singular para as classes dos modelos 😉

alternative_order = models.CharField(max_length=4, verbose_name="Alternativa")
question = models.ForeignKey(
'Question',
on_delete=models.CASCADE,
verbose_name="Questão"
)
alternative_text = models.TextField(verbose_name="Questão")
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Como estes são atributos de Alternative, não seria necessário prefixá-los com alternative_, chega a ser um pouco redundante:

correct_alternative = Alternatives.objects.filter(question=question, is_correct=True).first()
correct_alternative.alternative_text         # soa estranho, não é?

is_correct = models.BooleanField(
verbose_name="Está correta?",
default=False
)

def __str__(self):
return self.alternative_text

class Meta:
ordering = ('alternative_order',)
verbose_name = 'Alternativa'
verbose_name_plural = 'Alternativas'

class QuestionLogs(models.Model):
user = models.ForeignKey(User, verbose_name="Usuário", on_delete=models.CASCADE, null=True, blank=True)

question = models.ForeignKey(
'Question',
on_delete=models.CASCADE,
verbose_name="Questão"
)
chosen_alternative = models.CharField(max_length=4, verbose_name="Alternativa", null=True, blank=True)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Olha minha sugestão:

Se ao invés de guardar o valor da alternativa, tivesse usado uma ForeignKey para Alternative, você teria com facilidade o estado de se ela está correta ou não e poderia ter usado uma property para recuperar o is_correct, que no final das contas é um estado transitório e não deveria ser armazenado em cada QuestionLog, não é mesmo?

is_correct = models.BooleanField(
verbose_name="Está correta?",
default=False
)
answer_date = models.DateField(null=True, blank=True)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Campos DateTimeField são mais flexíveis, e você poderia ter aproveitado para usar o parâmetro auto_now_add para setar a data automaticamente.


def __str__(self):
return self.question.question_text

class Meta:
ordering = ('pk',)
verbose_name = 'Log'
verbose_name_plural = 'Logs'
12 changes: 11 additions & 1 deletion question/templates/question/answer.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,17 @@

<br/>
<br/>
<a href="{% url 'question' %}">Tente novamente</a>

{% if id and next %}
<a href="{% url 'question' id %}">Tente novamente</a>

<a href="{% url 'question' next %}">Próxima questão</a>

{% if request.user.is_authenticated %}
<a href="{% url 'logs' %}">Logs deste usuário</a>
{% endif %}

{% endif %}

</body>
</html>
8 changes: 4 additions & 4 deletions question/templates/question/question.html
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<title>Questão 1</title>
<title>Questão {{ questions.question_complete.id }}</title>
</head>

<body>
<form action="{% url 'question_answer' %}" method="POST">
{% csrf_token %}
<p>{{ question_text}}</p>
<p>{{ questions.question }}</p>

{% for letter, value in answers.items %}
<input type="radio" name="answer" value="{{ letter }}"><b>{{ letter }}.</b> {{ value }}</input><br/>
{% for alternative in questions.alternatives %}
<input type="radio" name="answer" value="{{ alternative.id }}"><b>{{ alternative.alternative_order }}.</b> {{ alternative }}</input><br/>
{% endfor %}

<br/>
Expand Down
15 changes: 15 additions & 0 deletions question/templates/question/question_logs.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<title>Logs</title>
</head>

<body>
<h1>Logs de respostas do usuário: {{ user }}</h1>
{% for log in logs %}
<p>{{ log.user }} | {{ log.question }} | {{ log.chosen_alternative }} | {% if log.is_correct %} Correto {% else %} Errado {% endif %} | {{ log.answer_date }}</p>
{% endfor %}
<a href="{% url 'question_home' %}">Home</a>
</form>
</body>
</html>
141 changes: 140 additions & 1 deletion question/tests.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,142 @@
from django.test import TestCase
from .models import Question, Alternatives, QuestionLogs

# Create your tests here.
# Tests
class TestViewQuestion(TestCase):

# Test home access
def test_home_view(self):
# Test Question Response
response_question = self.client.get('')
self.assertEqual(
200,
response_question.status_code
)

# Test question access
def test_question_view(self):

# Question 1
question1 = Question.objects.create(
id = 1,
question_text = "Quanto é 1 + 1?"
)

# Test Question Response with id error
response_question = self.client.get('/2/')
self.assertEqual(
404,
response_question.status_code
)

# Test Question Response
response_question = self.client.get('/1/')
self.assertEqual(
200,
response_question.status_code
)

# Test the return of the question object
self.assertEqual(
question1,
response_question.context["questions"]['question_complete']
)

# Test the return of the question text
self.assertEqual(
"Quanto é 1 + 1?",
response_question.context["questions"]['question'],
)

# Test the feedback if you have no alternatives for this question
self.assertEqual(
0,
response_question.context["questions"]['alternatives'].count(),
)

alternative1 = Alternatives.objects.create(
alternative_order = 'a',
question = question1,
alternative_text = "2",
is_correct = True
)

alternative2 = Alternatives.objects.create(
alternative_order = 'b',
question = question1,
alternative_text = "10",
is_correct = False
)

response_question = self.client.get('/1/')
# Test the feedback if you have one or more alternatives for this question
self.assertEqual(
2,
response_question.context["questions"]['alternatives'].count(),
)

# Test anser access
def test_answer_view(self):
question1 = Question.objects.create(
id = 1,
question_text = "Quanto é 1 + 1?"
)

alternative1 = Alternatives.objects.create(
alternative_order = 'a',
question = question1,
alternative_text = "2",
is_correct = True
)

alternative2 = Alternatives.objects.create(
alternative_order = 'b',
question = question1,
alternative_text = "10",
is_correct = False
)

response_answer = self.client.post(
'/resposta/',
{'answer': alternative1.id}
)

# Testar se deu certo o acesso
self.assertEqual(
200,
response_answer.status_code
)

# Testar se a respostar está correta
self.assertEqual(
True,
response_answer.context["is_correct"]
)

# Testar se foi gerado o log
self.assertEqual(
True,
response_answer.context["is_correct"]
)

# Testar um acesso errado a url
response_answer = self.client.post(
'/resposta/123',
{'answer': 'a'}
)

self.assertEqual(
404,
response_answer.status_code
)

# Testar uma resposta errada
response_answer = self.client.post(
'/resposta/',
{'answer': alternative2.id}
)

self.assertEqual(
False,
response_answer.context["is_correct"]
)
9 changes: 5 additions & 4 deletions question/urls.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
#coding: utf8

from django.urls import path, re_path
from django.urls import path

from . import views

urlpatterns = [
re_path(r'^$', views.question, name='question'),
re_path(r'^resposta/$', views.question_answer, name='question_answer'),

path('', views.home, name='question_home'),
path('<int:id>/', views.question, name='question'),
path('resposta/', views.question_answer, name='question_answer'),
path('log-questoes/', views.logs, name='logs'),
]
Loading