From d44409895f95d4e36f6ec0e9d53e179c8e160a68 Mon Sep 17 00:00:00 2001 From: Matija Pretnar Date: Tue, 29 Nov 2022 09:44:14 +0100 Subject: [PATCH] Odstranil razred ProblemText --- nadlogar/problems/admin.py | 5 +- nadlogar/problems/forms.py | 56 ++++------------- ...oblem_text_problem_instruction_and_more.py | 30 +++++++++ nadlogar/problems/models/meta.py | 61 +++++++------------ nadlogar/problems/tests.py | 3 +- nadlogar/problems/views.py | 4 +- .../templates/problems/create_problem.html | 28 +++------ 7 files changed, 75 insertions(+), 112 deletions(-) create mode 100644 nadlogar/problems/migrations/0018_remove_problem_text_problem_instruction_and_more.py diff --git a/nadlogar/problems/admin.py b/nadlogar/problems/admin.py index 47810e5..2408760 100644 --- a/nadlogar/problems/admin.py +++ b/nadlogar/problems/admin.py @@ -1,11 +1,8 @@ from django.contrib import admin -from .models import Problem, ProblemText +from .models import Problem class ProblemInline(admin.TabularInline): model = Problem extra = 2 - - -admin.site.register(ProblemText) diff --git a/nadlogar/problems/forms.py b/nadlogar/problems/forms.py index da3f8de..7189c85 100644 --- a/nadlogar/problems/forms.py +++ b/nadlogar/problems/forms.py @@ -1,32 +1,12 @@ from django import forms from django.core.exceptions import ValidationError -from django.forms.models import ModelChoiceIterator - -from .models import ProblemText def problem_form(content_type, *args, **kwargs): Generator = content_type.model_class() - example_problem = kwargs.get("instance", Generator()) - example_data = example_problem.example_data() - - class ProblemTextChoiceIterator(ModelChoiceIterator): - def choice(self, obj): - return (self.field.prepare_value(obj), obj.render(example_data)) class ProblemForm(forms.ModelForm): - instruction = forms.CharField( - label="Navodilo", - widget=forms.Textarea(attrs={"rows": 5}), - required=False, - initial=Generator.default_instruction, - ) - solution = forms.CharField( - label="Rešitev", - widget=forms.Textarea(attrs={"rows": 3}), - required=False, - initial=Generator.default_solution, - ) + uses_custom_text = forms.BooleanField(initial=False, required=False) class Meta: model = Generator @@ -34,26 +14,27 @@ class Meta: def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.fields["text"].queryset = content_type.problemtext_set - self.fields["text"].iterator = ProblemTextChoiceIterator - self.fields["text"].empty_label = None - for field_name in ["text", "instruction", "solution"]: + instance_uses_custom_text = self.instance.uses_custom_text() + user_wants_custom_text = self.data.get("uses_custom_text") != "false" + if not instance_uses_custom_text: + self.initial["instruction"] = Generator.default_instruction + self.initial["solution"] = Generator.default_solution + self.initial["uses_custom_text"] = ( + instance_uses_custom_text and user_wants_custom_text + ) + for field_name in ["uses_custom_text", "instruction", "solution"]: self.fields[field_name].custom_display = True def clean(self): super().clean() errors = {} - if self.data["text"] == "new": - del self.errors["text"] + if self.cleaned_data["uses_custom_text"]: for field_name in ["instruction", "solution"]: if not self.cleaned_data[field_name]: errors[ field_name ] = "Ob izbiri novega besedila mora biti to polje neprazno." else: - if "text" not in self.cleaned_data: - self.cleaned_data["text"] = None - del self.errors["text"] if self.cleaned_data["instruction"] == Generator.default_instruction: self.cleaned_data["instruction"] = "" if self.cleaned_data["solution"] == Generator.default_solution: @@ -62,25 +43,12 @@ def clean(self): if self.cleaned_data[field_name]: errors[field_name] = ( "Da ne bi prišlo do izgube podatkov, mora biti ob izbiri" - " obstoječega besedila to polje prazno ali enako privzeti" + " privzetega besedila to polje prazno ali enako privzeti" " vrednosti." ) if errors: raise ValidationError(errors) - def save(self, commit=True): - problem = super().save(commit=False) - if "text" not in self.cleaned_data: - text = ProblemText.objects.create( - content_type=problem.content_type, - instruction=self.cleaned_data["instruction"], - solution=self.cleaned_data["solution"], - ) - problem.text = text - if commit: - problem.save() - return problem - def display_parameter_form(self): return any( not getattr(field.field, "custom_display", False) diff --git a/nadlogar/problems/migrations/0018_remove_problem_text_problem_instruction_and_more.py b/nadlogar/problems/migrations/0018_remove_problem_text_problem_instruction_and_more.py new file mode 100644 index 0000000..07b4bb4 --- /dev/null +++ b/nadlogar/problems/migrations/0018_remove_problem_text_problem_instruction_and_more.py @@ -0,0 +1,30 @@ +# Generated by Django 4.1.3 on 2022-11-29 08:33 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("problems", "0017_alter_problem_text"), + ] + + operations = [ + migrations.RemoveField( + model_name="problem", + name="text", + ), + migrations.AddField( + model_name="problem", + name="instruction", + field=models.TextField(blank=True, verbose_name="navodilo"), + ), + migrations.AddField( + model_name="problem", + name="solution", + field=models.TextField(blank=True, verbose_name="rešitev"), + ), + migrations.DeleteModel( + name="ProblemText", + ), + ] diff --git a/nadlogar/problems/models/meta.py b/nadlogar/problems/models/meta.py index 88fe41e..1882d40 100644 --- a/nadlogar/problems/models/meta.py +++ b/nadlogar/problems/models/meta.py @@ -20,27 +20,6 @@ class Template(PythonTemplate): delimiter = "@" -class ProblemText(models.Model): - content_type = models.ForeignKey( - ContentType, - on_delete=models.PROTECT, - limit_choices_to=limit_content_type_choices, - ) - instruction = models.TextField() - solution = models.TextField() - - def __str__(self): - return f"{self.content_type.name}: {self.instruction} / {self.solution}" - - def render(self, data): - rendered_texts = [] - for datum in data: - instruction = Template(self.instruction).substitute(**datum) - solution = Template(self.solution).substitute(**datum) - rendered_texts.append({"instruction": instruction, "solution": solution}) - return rendered_texts - - class GeneratedDataIncorrect(Exception): pass @@ -54,14 +33,13 @@ class Problem(models.Model): on_delete=models.PROTECT, limit_choices_to=limit_content_type_choices, ) - text = models.ForeignKey( - "problems.ProblemText", on_delete=models.SET_NULL, blank=True, null=True - ) number_of_subproblems = models.PositiveSmallIntegerField( "število podnalog", help_text="Če je izbrana več kot ena naloga, bodo navodila našteta v seznamu.", default=1, ) + instruction = models.TextField("navodilo", blank=True) + solution = models.TextField("rešitev", blank=True) class Meta: default_related_name = "problems" @@ -73,8 +51,6 @@ def clean(self): if issubclass(Problem, type(self)): raise ValidationError("Problems must have a non-trivial generator") self.content_type = ContentType.objects.get_for_model(type(self)) - if self.text is not None and self.content_type != self.text.content_type: - raise ValidationError("Generators of the problem and its text must match") def save(self, *args, **kwargs): self.content_type = ContentType.objects.get_for_model(type(self)) @@ -105,31 +81,36 @@ def _generate_data(self, seed): pass return data - @classmethod - def default_text(cls): - return ProblemText( - content_type=ContentType.objects.get_for_model(cls), - instruction=cls.default_instruction, - solution=cls.default_solution, - ) - - def _render_text(self, data): - if self.text is None: - return self.default_text().render(data) + def uses_custom_text(self): + return bool(self.instruction or self.solution) + + def render(self, data, default_text=False): + if not default_text and self.uses_custom_text(): + instruction = self.instruction + solution = self.solution else: - return self.text.render(data) + instruction = self.default_instruction + solution = self.default_solution + rendered_texts = [] + for datum in data: + rendered_instruction = Template(instruction).substitute(**datum) + rendered_solution = Template(solution).substitute(**datum) + rendered_texts.append( + {"instruction": rendered_instruction, "solution": rendered_solution} + ) + return rendered_texts def example_data(self): return self._generate_data(None) def example_text(self): data = self.example_data() - return self._render_text(data) + return self.render(data) def student_text(self, student): seed = f"{self.id}-{student.id}" data = self._generate_data(seed) - rendered_text = self._render_text(data) + rendered_text = self.render(data) return rendered_text def copy(self, document): diff --git a/nadlogar/problems/tests.py b/nadlogar/problems/tests.py index ff0de88..e5dda8b 100644 --- a/nadlogar/problems/tests.py +++ b/nadlogar/problems/tests.py @@ -43,8 +43,9 @@ def test_default_arguments(self): "id", "document", "content_type", - "text", "problem_ptr", + "instruction", + "solution", ]: self.assertNotEqual( field.default, diff --git a/nadlogar/problems/views.py b/nadlogar/problems/views.py index 234f5ae..2ae789e 100644 --- a/nadlogar/problems/views.py +++ b/nadlogar/problems/views.py @@ -55,7 +55,7 @@ def create_problem(request, group_id: int, document_id: int, content_type_id: in Generator = content_type.model_class() example_problem = Generator() example_data = example_problem.example_data() - default_text = example_problem.default_text().render(example_data) + default_text = example_problem.render(example_data, default_text=True) form = problem_form(content_type, request.POST or None) if form.is_valid(): problem: Problem = form.save(commit=False) @@ -84,7 +84,7 @@ def edit_problem(request, group_id: int, document_id: int, problem_id: int): problem: Problem = form.save() return redirect(problem.document.get_absolute_url()) example_data = problem.example_data() - default_text = problem.default_text().render(example_data) + default_text = problem.render(example_data, default_text=True) return render( request, "problems/edit_problem.html", diff --git a/nadlogar/templates/problems/create_problem.html b/nadlogar/templates/problems/create_problem.html index 0ff7c70..204c3b9 100644 --- a/nadlogar/templates/problems/create_problem.html +++ b/nadlogar/templates/problems/create_problem.html @@ -16,10 +16,10 @@

Besedilo naloge

@@ -34,33 +34,19 @@

Privzeto besedilo

Če tega ne želite, si spodaj ustvarite novo besedilo na osnovi privzetega.
- {% for value, rendered_text in form.fields.text.choices %}
- {% include "problems/_rendered_text.html" %} -
-
-
- {% endfor %} -
-
- -
-
-
-

Novo besedilo

+

Lastno besedilo

{% include "_field.html" with field=form.instruction %} {% include "_field.html" with field=form.solution %}