diff --git a/django/library/admin.py b/django/library/admin.py index 7d617a5..700000b 100644 --- a/django/library/admin.py +++ b/django/library/admin.py @@ -1,5 +1,5 @@ from django.contrib import admin -from .models import QivipQuiz, QivipQuestion, QivipQuizFavorite, QuizCategory +from .models import QivipQuiz, QivipQuestion, QivipQuizFavorite, QuestionImage, QuizCategory, QuizImage # Für das QivipQuiz Modell class QivipQuizAdmin(admin.ModelAdmin): @@ -23,8 +23,17 @@ class QuizCategoryAdmin(admin.ModelAdmin): class QivipQuizFavoriteAdmin(admin.ModelAdmin): list_display = ('user', 'favorite', 'quiz') # Welche Felder sollen in der Übersicht angezeigt werden + +class QuizImageAdmin(admin.ModelAdmin): + list_display = ('image',) + +class QuestionImageAdmin(admin.ModelAdmin): + list_display = ('image',) + # Registrierung der Modelle im Admin admin.site.register(QivipQuiz, QivipQuizAdmin) admin.site.register(QivipQuestion, QivipQuestionAdmin) admin.site.register(QuizCategory, QuizCategoryAdmin) admin.site.register(QivipQuizFavorite, QivipQuizFavoriteAdmin) +admin.site.register(QuizImage, QuizImageAdmin) +admin.site.register(QuestionImage, QuestionImageAdmin) \ No newline at end of file diff --git a/django/library/forms.py b/django/library/forms.py index 7cb8773..fb55f92 100644 --- a/django/library/forms.py +++ b/django/library/forms.py @@ -4,7 +4,7 @@ from .models import QivipQuiz, QivipQuestion class QuizForm(forms.ModelForm): class Meta: model = QivipQuiz - fields = ['name', 'description','image', 'status', 'category','difficulty','credits'] + fields = ['name', 'description', 'status', 'category','difficulty','credits'] class QuestionForm(forms.ModelForm): class Meta: diff --git a/django/library/migrations/0050_questionimage_quizimages_alter_qivipquestion_image_and_more.py b/django/library/migrations/0050_questionimage_quizimages_alter_qivipquestion_image_and_more.py new file mode 100644 index 0000000..240534c --- /dev/null +++ b/django/library/migrations/0050_questionimage_quizimages_alter_qivipquestion_image_and_more.py @@ -0,0 +1,38 @@ +# Generated by Django 5.1.7 on 2025-04-22 16:04 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('library', '0049_alter_qivipquestion_image'), + ] + + operations = [ + migrations.CreateModel( + name='QuestionImage', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('image', models.ImageField(blank=True, null=True, upload_to='question_images/', verbose_name='Bild')), + ], + ), + migrations.CreateModel( + name='QuizImage', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('image', models.ImageField(blank=True, max_length=256, null=True, upload_to='quiz_images/', verbose_name='Bild')), + ], + ), + migrations.AlterField( + model_name='qivipquestion', + name='image', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='questions', to='library.questionimage'), + ), + migrations.AlterField( + model_name='qivipquiz', + name='image', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='quizzes', to='library.QuizImage'), + ), + ] diff --git a/django/library/migrations/0051_alter_qivipquestion_image_alter_qivipquiz_image.py b/django/library/migrations/0051_alter_qivipquestion_image_alter_qivipquiz_image.py new file mode 100644 index 0000000..28594d5 --- /dev/null +++ b/django/library/migrations/0051_alter_qivipquestion_image_alter_qivipquiz_image.py @@ -0,0 +1,24 @@ +# Generated by Django 5.1.7 on 2025-04-23 12:04 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('library', '0050_questionimage_quizimages_alter_qivipquestion_image_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='qivipquestion', + name='image', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='questions', to='library.questionimage'), + ), + migrations.AlterField( + model_name='qivipquiz', + name='image', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='quizzes', to='library.quizimage'), + ), + ] diff --git a/django/library/migrations/0052_alter_qivipquestion_image_alter_qivipquiz_image_and_more.py b/django/library/migrations/0052_alter_qivipquestion_image_alter_qivipquiz_image_and_more.py new file mode 100644 index 0000000..05b791b --- /dev/null +++ b/django/library/migrations/0052_alter_qivipquestion_image_alter_qivipquiz_image_and_more.py @@ -0,0 +1,29 @@ +# Generated by Django 5.1.7 on 2025-04-23 12:21 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('library', '0051_alter_qivipquestion_image_alter_qivipquiz_image'), + ] + + operations = [ + migrations.AlterField( + model_name='qivipquestion', + name='image', + field=models.ImageField(blank=True, null=True, upload_to='question_images/', verbose_name='Bild'), + ), + migrations.AlterField( + model_name='qivipquiz', + name='image', + field=models.ImageField(blank=True, max_length=256, null=True, upload_to='quiz_images/', verbose_name='Bild'), + ), + migrations.DeleteModel( + name='QuestionImage', + ), + migrations.DeleteModel( + name='QuizImage', + ), + ] diff --git a/django/library/migrations/0053_questionimage_quizimage_alter_qivipquestion_image_and_more.py b/django/library/migrations/0053_questionimage_quizimage_alter_qivipquestion_image_and_more.py new file mode 100644 index 0000000..c935670 --- /dev/null +++ b/django/library/migrations/0053_questionimage_quizimage_alter_qivipquestion_image_and_more.py @@ -0,0 +1,38 @@ +# Generated by Django 5.1.7 on 2025-04-23 13:15 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('library', '0052_alter_qivipquestion_image_alter_qivipquiz_image_and_more'), + ] + + operations = [ + migrations.CreateModel( + name='QuestionImage', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('image', models.ImageField(blank=True, null=True, upload_to='question_images/', verbose_name='Bild')), + ], + ), + migrations.CreateModel( + name='QuizImage', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('image', models.ImageField(blank=True, max_length=256, null=True, upload_to='quiz_images/', verbose_name='Bild')), + ], + ), + migrations.AlterField( + model_name='qivipquestion', + name='image', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='questions', to='library.questionimage'), + ), + migrations.AlterField( + model_name='qivipquiz', + name='image', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='quizzes', to='library.quizimage'), + ), + ] diff --git a/django/library/models.py b/django/library/models.py index 23d46a3..9b17d6f 100644 --- a/django/library/models.py +++ b/django/library/models.py @@ -4,6 +4,15 @@ from django.utils.text import slugify import uuid from django.core.exceptions import ValidationError + +class QuizImage(models.Model): + image = models.ImageField(max_length=256,verbose_name="Bild", upload_to='quiz_images/', blank=True, null=True) # Bild speichern in media/quiz_images/ + + +class QuestionImage(models.Model): + image = models.ImageField(verbose_name="Bild", upload_to="question_images/", blank=True, null=True) + + class QivipQuiz(models.Model): STATUS_VALUES = { "öffentlich": "Öffentlich", @@ -27,7 +36,15 @@ class QivipQuiz(models.Model): if value.strip() == "In dem Quiz geht es um ...": raise ValidationError("Bitte gib eine aussagekräftige Beschreibung ein.") - image = models.ImageField(max_length=256,verbose_name="Bild", upload_to='quiz_images/', blank=True, null=True) # Bild speichern in media/quiz_images/ + image = models.ForeignKey( + QuizImage, + null=True, + blank=True, + on_delete=models.PROTECT, + related_name="quizzes" + ) + + uuid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) user_id = models.ForeignKey(User, on_delete=models.CASCADE, related_name='quiz') #creator = models.ForeignKey(User, on_delete=models.SET_NULL,blank=True, null=True, related_name='creator_quiz') @@ -74,7 +91,14 @@ class QivipQuestion(models.Model): update_date = models.DateTimeField(auto_now=True) data = models.TextField() time_per_question = models.CharField(max_length=3, choices=list(TIME_VALUES.items()), default=30, help_text="Zeit pro Frage in Sekunden") - image = models.ImageField(verbose_name="Bild", upload_to="question_images/", blank=True, null=True) + image = models.ForeignKey( + QuestionImage, + null=True, + blank=True, + on_delete=models.PROTECT, + related_name="questions" +) + def __str__(self): return self.data[:50] diff --git a/django/library/views.py b/django/library/views.py index 034543d..867a4c2 100644 --- a/django/library/views.py +++ b/django/library/views.py @@ -6,7 +6,7 @@ from django.contrib.auth.decorators import login_required from django.contrib.auth.models import User from django.urls import reverse from django.contrib import messages -from .models import QivipQuiz, QivipQuestion, QivipQuizFavorite +from .models import QivipQuiz, QivipQuestion, QivipQuizFavorite, QuestionImage, QuizImage from .forms import QuizForm, QuestionForm import json from django.core.paginator import Paginator @@ -193,10 +193,23 @@ def favorite_quiz(request, pk): # Neues Quiz erstellen @login_required def new_quiz(request): + + if request.method == 'POST': + + form = QuizForm(request.POST, request.FILES) if form.is_valid(): quiz = form.save(commit=False) + try: + quiz_image=request.FILES['quiz_image'] + imagequiz=QuizImage.objects.create(image=quiz_image) + quiz.image=imagequiz + + except: + pass + + quiz.user_id = request.user #quiz.creator = request.user quiz.save() @@ -214,8 +227,28 @@ def edit_quiz(request, pk): if request.method == 'POST': form = QuizForm(request.POST, instance=quiz, files=request.FILES) if form.is_valid(): - + + if 'reset_image' in request.POST: + quiz.image = None + + try: + quiz_image=request.FILES['quiz_image'] + imagequiz=QuizImage.objects.create(image=quiz_image) + quiz.image=imagequiz + + + except: + pass + + + form.save() + for img in QuizImage.objects.all(): + try: + img.delete() + img.image.delete(save=False) + except: + pass return redirect('library:detail_quiz', pk=pk) #return modified(request, pk) @@ -229,6 +262,19 @@ def delete_quiz(request, pk): quiz = get_object_or_404(QivipQuiz, pk=pk, user_id=request.user) if request.method == 'POST': quiz.delete() + for img in QuizImage.objects.all(): + try: + img.delete() + img.image.delete(save=False) + except: + pass + for img in QuestionImage.objects.all(): + try: + img.delete() + img.image.delete(save=False) + except: + pass + return redirect('library:overview_quiz') return render(request, 'library/delete_confirmation.html', {'object': quiz}) @@ -254,6 +300,7 @@ def detail_quiz(request, pk): @login_required def copy_quiz(request, pk): original_quiz = get_object_or_404(QivipQuiz, pk=pk) + # Quiz kopieren (ohne ID, damit ein neues Objekt erstellt wird) @@ -264,11 +311,10 @@ def copy_quiz(request, pk): new_quiz.pk = None # Setzt die ID auf None, damit Django es als neues Objekt erkennt new_quiz.uuid = uuid.uuid4() # Neue UUID generieren new_quiz.user_id = request.user # Neuer Besitzer ist der aktuelle User - new_quiz.name += " - Kopie" # Optional: Name anpassen + new_quiz.name += " - Kopie" new_quiz.base_quiz_id = pk new_quiz.rating_count = 0 new_quiz.average_rating = 3.0 - #new_quiz.creator = original_quiz.creator or request.user new_quiz.save() # Speichern als neues Objekt # Optional: Beschreibung anpassen # Alle zugehörigen Fragen kopieren @@ -278,6 +324,7 @@ def copy_quiz(request, pk): question.pk = None # Setze pk auf None, damit es als neues Objekt gespeichert wird question.quiz_id = original_quiz # Verknüpfe mit dem neuen Quiz question.data = question.data # `data`-Feld wird explizit übernommen # Verknüpfe mit dem neuen Quiz + question.save() messages.success(request, "Quiz wurde erfolgreich kopiert!") @@ -315,10 +362,9 @@ def new_question(request): if question_type not in ['multiple_choice', 'true_false']: base_url = reverse('library:new_question') return redirect(f'{base_url}?type=multiple_choice&quiz_id={quiz_id}') - + if request.method == 'POST': question_text = request.POST.get('question', '') - question_image = request.FILES.get('question_image', None) # Handle different question types if question_type == 'true_false': @@ -358,7 +404,14 @@ def new_question(request): question = QivipQuestion() question.data = json.dumps(json_data) question.quiz_id = quiz - question.image = question_image + try: + question_image=request.FILES['question_image'] + imagequestion=QuestionImage.objects.create(image=question_image) + question.image=imagequestion + except: + pass + + question.time_per_question = request.POST.get('time_per_question', '30') question.save() #return modified(request, pk=quiz.pk) @@ -400,6 +453,8 @@ def new_question(request): @login_required def edit_question(request, pk): question = get_object_or_404(QivipQuestion, pk=pk, quiz_id__user_id=request.user) + if 'reset_ques_image' in request.POST: + question.image = None if question.quiz_id.user_id != request.user: return redirect('library:question_list') @@ -453,7 +508,9 @@ def edit_question(request, pk): if request.method == 'POST': question_text = request.POST.get('question', '') try: - question_image = request.FILES['question_image'] + question_image=request.FILES['question_image'] + imagequestion=QuestionImage.objects.create(image=question_image) + question.image=imagequestion except Exception: pass @@ -498,8 +555,15 @@ def edit_question(request, pk): question.data = json.dumps(json_data) question.time_per_question = request.POST.get('time_per_question', '30') - question.image = question_image + + question.save() + for img in QuestionImage.objects.all(): + try: + img.delete() + img.image.delete(save=False) + except: + pass #return modified(request, question.quiz_id.pk) return redirect('library:detail_quiz', pk=question.quiz_id.pk) @@ -527,5 +591,11 @@ def delete_question(request, pk): if request.method == 'POST': question.delete() + for img in QuestionImage.objects.all(): + try: + img.delete() + img.image.delete(save=False) + except: + pass return redirect('library:detail_quiz', pk=question.quiz_id.pk) return render(request, 'library/delete_confirmation.html', {'object': question}) diff --git a/django/templates/library/form.html b/django/templates/library/form.html index a7d8da5..2352368 100644 --- a/django/templates/library/form.html +++ b/django/templates/library/form.html @@ -5,6 +5,21 @@