diff --git a/countdown_numbers/admin.py b/countdown_numbers/admin.py new file mode 100644 index 00000000..ecc0fc81 --- /dev/null +++ b/countdown_numbers/admin.py @@ -0,0 +1,39 @@ +from django.contrib import admin +from django.db import models +from django.forms.widgets import TextInput + +from .models import NumbersGame + + +class NumbersGameAdmin(admin.ModelAdmin): + model = NumbersGame + list_display = ( + 'game_nums', 'target_number', 'player_num_achieved', + 'comp_num_achieved', 'game_result', 'entry_date' + ) + ordering = ('-entry_date',) + readonly_fields= [field.name for field in NumbersGame._meta.get_fields()] + + formfield_overrides = { + models.CharField: {'widget': TextInput(attrs={'size': '20'})}, + models.IntegerField: {'widget': TextInput(attrs={'size': '2'})}, + } + + fieldsets = ( + ('Selection', { + 'fields': ['game_nums', 'target_number'] + }), + ('Results', { + 'fields': ( + ('valid_calc', 'player_num_achieved', 'player_score'), + ('comp_num_achieved', 'comp_score'), + 'solution_str', + 'game_result' + ) + }), + ('Dates', { + 'fields': ('entry_date', ) + }), + ) + +admin.site.register(NumbersGame, NumbersGameAdmin) diff --git a/countdown_numbers/migrations/0001_initial.py b/countdown_numbers/migrations/0001_initial.py new file mode 100644 index 00000000..e8b5d120 --- /dev/null +++ b/countdown_numbers/migrations/0001_initial.py @@ -0,0 +1,33 @@ +# Generated by Django 3.0.8 on 2020-07-26 17:03 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Game', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('game_nums', models.CharField(max_length=9)), + ('target_number', models.IntegerField()), + ('player_num_achieved', models.IntegerField()), + ('valid_calc', models.BooleanField(default=False)), + ('comp_num_achieved', models.IntegerField()), + ('player_score', models.IntegerField(default=0)), + ('comp_score', models.IntegerField(default=0)), + ('solution_str', models.CharField(max_length=255)), + ('game_result', models.CharField(max_length=255)), + ('entry_date', models.DateTimeField(auto_now_add=True)), + ], + options={ + 'ordering': ('-entry_date',), + }, + ), + ] diff --git a/countdown_numbers/migrations/0002_auto_20200726_1707.py b/countdown_numbers/migrations/0002_auto_20200726_1707.py new file mode 100644 index 00000000..34e1d5b6 --- /dev/null +++ b/countdown_numbers/migrations/0002_auto_20200726_1707.py @@ -0,0 +1,18 @@ +# Generated by Django 3.0.8 on 2020-07-26 17:07 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('countdown_numbers', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='game', + name='game_nums', + field=models.CharField(max_length=255), + ), + ] diff --git a/countdown_numbers/migrations/0003_auto_20200726_1743.py b/countdown_numbers/migrations/0003_auto_20200726_1743.py new file mode 100644 index 00000000..15e0f74a --- /dev/null +++ b/countdown_numbers/migrations/0003_auto_20200726_1743.py @@ -0,0 +1,17 @@ +# Generated by Django 3.0.8 on 2020-07-26 17:43 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('countdown_numbers', '0002_auto_20200726_1707'), + ] + + operations = [ + migrations.RenameModel( + old_name='Game', + new_name='NumbersGame', + ), + ] diff --git a/countdown_numbers/migrations/__init__.py b/countdown_numbers/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/countdown_numbers/models.py b/countdown_numbers/models.py new file mode 100644 index 00000000..dde78d70 --- /dev/null +++ b/countdown_numbers/models.py @@ -0,0 +1,40 @@ +from django.db import models + + +class NumbersGame(models.Model): + game_nums = models.CharField(max_length=255) + target_number = models.IntegerField() + player_num_achieved = models.IntegerField() + valid_calc = models.BooleanField(default=False) + comp_num_achieved = models.IntegerField() + player_score = models.IntegerField(default=0) + comp_score = models.IntegerField(default=0) + solution_str = models.CharField(max_length=255) + game_result = models.CharField(max_length=255) + entry_date = models.DateTimeField(auto_now_add=True) + + class Meta: + ordering = ('-entry_date', ) + + @property + def entry_year(self) -> int: + return self.entry_date.year + + @staticmethod + def create_record(context: dict): + """ + Following context dictionary validations within the view + process, posts the results to the database for reference and + later retrieval. + """ + NumbersGame.objects.create( + game_nums=context['game_nums'], + target_number=context['target_number'], + player_num_achieved=context['player_num_achieved'], + valid_calc=context['valid_calc'], + comp_num_achieved=context['comp_num_achieved'], + player_score=context['player_score'], + comp_score=context['comp_score'], + solution_str=context['solution_str'], + game_result=context['game_result'], + ) diff --git a/countdown_numbers/tests/test_models.py b/countdown_numbers/tests/test_models.py new file mode 100644 index 00000000..ad67a610 --- /dev/null +++ b/countdown_numbers/tests/test_models.py @@ -0,0 +1,73 @@ +import pytest +from django.db import models +from mixer.backend.django import mixer + +from countdown_numbers.models import NumbersGame + +pytestmark = pytest.mark.django_db + + +class TestNumbersGame: + def test_single_numbers_game_saves(self): + game = mixer.blend(NumbersGame) + assert game.pk == 1, 'Should create a `Numbers Game` instance' + + def test_multi_numbers_game_saves(self): + games = mixer.cycle(10).blend(NumbersGame) + assert games[9].pk == 10, '10th instance should have a PK of 10' + assert NumbersGame.objects.count() == 10, 'Should have 10 objects in the database' + + def test_can_delete_numbers_game(self): + games = mixer.cycle(10).blend(NumbersGame) + games[4].delete() + assert NumbersGame.objects.count() == 9, 'Should have 9 objects remaining in the database' + + def test_game_nums_is_charfield(self): + game = mixer.blend(NumbersGame) + field = game._meta.get_field("game_nums") + assert isinstance(field, models.CharField), 'Should be a char field' + + def test_target_number_is_integerfield(self): + game = mixer.blend(NumbersGame) + field = game._meta.get_field("target_number") + assert isinstance(field, models.IntegerField), 'Should be an integer field' + + def test_player_num_achieved_is_integerfield(self): + game = mixer.blend(NumbersGame) + field = game._meta.get_field("player_num_achieved") + assert isinstance(field, models.IntegerField), 'Should be an integer field' + + def test_valid_calc_is_booleanfield(self): + game = mixer.blend(NumbersGame) + field = game._meta.get_field("valid_calc") + assert isinstance(field, models.BooleanField), 'Should be a boolean field' + + def test_comp_num_achieved_is_integerfield(self): + game = mixer.blend(NumbersGame) + field = game._meta.get_field("comp_num_achieved") + assert isinstance(field, models.IntegerField), 'Should be an integer field' + + def test_player_score_is_integerfield(self): + game = mixer.blend(NumbersGame) + field = game._meta.get_field("player_score") + assert isinstance(field, models.IntegerField), 'Should be an integer field' + + def test_comp_score_is_integerfield(self): + game = mixer.blend(NumbersGame) + field = game._meta.get_field("comp_score") + assert isinstance(field, models.IntegerField), 'Should be an integer field' + + def test_solution_str_is_charfield(self): + game = mixer.blend(NumbersGame) + field = game._meta.get_field("solution_str") + assert isinstance(field, models.CharField), 'Should be a char field' + + def test_game_result_is_charfield(self): + game = mixer.blend(NumbersGame) + field = game._meta.get_field("game_result") + assert isinstance(field, models.CharField), 'Should be a char field' + + def test_entry_date_is_datefield(self): + game = mixer.blend(NumbersGame) + field = game._meta.get_field("entry_date") + assert isinstance(field, models.DateField), 'Should be a date field' diff --git a/countdown_numbers/views.py b/countdown_numbers/views.py index d7b7bd35..b5b32ef8 100644 --- a/countdown_numbers/views.py +++ b/countdown_numbers/views.py @@ -7,6 +7,7 @@ from . import logic from .forms import NumberSelectionForm, SelectedNumbersForm +from .models import NumbersGame from .validations import calc_entered_is_valid, get_permissible_nums, is_calc_valid @@ -60,7 +61,8 @@ def results_screen(request): best_solution = best_solution.replace(chr(215), '*').replace(chr(247), '/') comp_num_achieved = int(eval(best_solution)) solution_str = f""" - {best_solution.replace('*', chr(215)).replace('/', chr(247))} = {comp_num_achieved}""" + {best_solution.replace( + '*', chr(215)).replace('/', chr(247))} = {comp_num_achieved}""".strip() answers = { 'player_num_achieved': player_num_achieved, 'comp_num_achieved': comp_num_achieved, @@ -84,4 +86,6 @@ def results_screen(request): 'game_result': game_result, } + NumbersGame.create_record(context) + return render(request, 'countdown_numbers/results.html', context)