Skip to content

Commit

Permalink
Odstranil razred ProblemText
Browse files Browse the repository at this point in the history
  • Loading branch information
matijapretnar committed Nov 29, 2022
1 parent da19e12 commit d444098
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 112 deletions.
5 changes: 1 addition & 4 deletions nadlogar/problems/admin.py
Original file line number Diff line number Diff line change
@@ -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)
56 changes: 12 additions & 44 deletions nadlogar/problems/forms.py
Original file line number Diff line number Diff line change
@@ -1,59 +1,40 @@
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
exclude = ["content_type", "document"]

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:
Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
@@ -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",
),
]
61 changes: 21 additions & 40 deletions nadlogar/problems/models/meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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"
Expand All @@ -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))
Expand Down Expand Up @@ -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):
Expand Down
3 changes: 2 additions & 1 deletion nadlogar/problems/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,9 @@ def test_default_arguments(self):
"id",
"document",
"content_type",
"text",
"problem_ptr",
"instruction",
"solution",
]:
self.assertNotEqual(
field.default,
Expand Down
4 changes: 2 additions & 2 deletions nadlogar/problems/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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",
Expand Down
28 changes: 7 additions & 21 deletions nadlogar/templates/problems/create_problem.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ <h3>Besedilo naloge</h3>
<article class="media">
<div class="media-left">
<label class="radio">
{% if form.initial.text == None %}
<input type="radio" name="{{ form.text.html_name }}" checked>
{% if form.initial.uses_custom_text %}
<input type="radio" name="{{ form.uses_custom_text.html_name }}" value="false">
{% else %}
<input type="radio" name="{{ form.text.html_name }}">
<input type="radio" name="{{ form.uses_custom_text.html_name }}" value="false" checked>
{% endif %}
</label>
</div>
Expand All @@ -34,33 +34,19 @@ <h4>Privzeto besedilo</h4>
Če tega ne želite, si spodaj ustvarite novo besedilo na osnovi privzetega.
</div>
</article>
{% for value, rendered_text in form.fields.text.choices %}
<article class="media">
<div class="media-left">
<label class="radio">
{% if form.initial.text == value %}
<input type="radio" name="{{ form.text.html_name }}" value="{{ value }}" checked>
{% if form.initial.uses_custom_text %}
<input type="radio" name="{{ form.uses_custom_text.html_name }}" value="true" checked>
{% else %}
<input type="radio" name="{{ form.text.html_name }}" value="{{ value }}">
<input type="radio" name="{{ form.uses_custom_text.html_name }}" value="true">
{% endif %}
</label>
</div>
<div class="media-content">
<div class="content">
{% include "problems/_rendered_text.html" %}
</div>
</div>
</article>
{% endfor %}
<article class="media">
<div class="media-left">
<label class="radio">
<input type="radio" name="{{ form.text.html_name }}" value="new">
</label>
</div>
<div class="media-content">
<div class="content">
<h4>Novo besedilo</h4>
<h4>Lastno besedilo</h4>
{% include "_field.html" with field=form.instruction %}
{% include "_field.html" with field=form.solution %}
</div>
Expand Down

0 comments on commit d444098

Please sign in to comment.