From e135ff945f8cb5a98ca300f294d3290739b961f7 Mon Sep 17 00:00:00 2001 From: nik8 Date: Sat, 5 Apr 2025 12:07:56 +0200 Subject: [PATCH] Kopie eines Quizzes (Datenbank) --- django/library/admin.py | 1 - django/library/forms.py | 2 +- .../0025_qivipquiz_modified_description.py | 18 ++++ ...26_alter_qivipquiz_modified_description.py | 18 ++++ .../migrations/0027_qivipquiz_creator.py | 21 +++++ .../0028_alter_qivipquiz_creator.py | 21 +++++ .../migrations/0029_qivipquiz_credits.py | 18 ++++ .../0030_remove_qivipquiz_creator_and_more.py | 27 ++++++ django/library/models.py | 6 +- django/library/urls.py | 2 + django/library/views.py | 84 +++++++++++++++++-- django/templates/library/detail_quiz.html | 47 ++++++++--- django/templates/library/overview_quiz.html | 18 +++- 13 files changed, 259 insertions(+), 24 deletions(-) create mode 100644 django/library/migrations/0025_qivipquiz_modified_description.py create mode 100644 django/library/migrations/0026_alter_qivipquiz_modified_description.py create mode 100644 django/library/migrations/0027_qivipquiz_creator.py create mode 100644 django/library/migrations/0028_alter_qivipquiz_creator.py create mode 100644 django/library/migrations/0029_qivipquiz_credits.py create mode 100644 django/library/migrations/0030_remove_qivipquiz_creator_and_more.py diff --git a/django/library/admin.py b/django/library/admin.py index 14c0c5b..4c7eda2 100644 --- a/django/library/admin.py +++ b/django/library/admin.py @@ -6,7 +6,6 @@ class QivipQuizAdmin(admin.ModelAdmin): list_display = ('name', 'user_id', 'status', 'category', 'creation_date', 'update_date') # Welche Felder sollen in der Übersicht angezeigt werden search_fields = ('name', 'user_id__username', 'category__name') # Suchfelder list_filter = ('status', 'category') # Filteroptionen - # Für das QivipQuestion Modell class QivipQuestionAdmin(admin.ModelAdmin): list_display = ('quiz_id', 'data', 'creation_date', 'update_date') diff --git a/django/library/forms.py b/django/library/forms.py index 4ca84f8..c454b71 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', 'tags',"difficulty"] + fields = ['name', 'description','image', 'status', 'category', 'tags',"difficulty","credits"] class QuestionForm(forms.ModelForm): class Meta: diff --git a/django/library/migrations/0025_qivipquiz_modified_description.py b/django/library/migrations/0025_qivipquiz_modified_description.py new file mode 100644 index 0000000..603c205 --- /dev/null +++ b/django/library/migrations/0025_qivipquiz_modified_description.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.7 on 2025-04-03 16:46 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('library', '0024_alter_qivipquiz_image'), + ] + + operations = [ + migrations.AddField( + model_name='qivipquiz', + name='modified_description', + field=models.TextField(blank=True, default='Das Quiz wurde modifiziert von:', editable=False), + ), + ] diff --git a/django/library/migrations/0026_alter_qivipquiz_modified_description.py b/django/library/migrations/0026_alter_qivipquiz_modified_description.py new file mode 100644 index 0000000..0dd27b6 --- /dev/null +++ b/django/library/migrations/0026_alter_qivipquiz_modified_description.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.7 on 2025-04-04 13:28 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('library', '0025_qivipquiz_modified_description'), + ] + + operations = [ + migrations.AlterField( + model_name='qivipquiz', + name='modified_description', + field=models.TextField(blank=True, editable=False), + ), + ] diff --git a/django/library/migrations/0027_qivipquiz_creator.py b/django/library/migrations/0027_qivipquiz_creator.py new file mode 100644 index 0000000..5d99ae1 --- /dev/null +++ b/django/library/migrations/0027_qivipquiz_creator.py @@ -0,0 +1,21 @@ +# Generated by Django 5.1.7 on 2025-04-04 13:37 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('library', '0026_alter_qivipquiz_modified_description'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.AddField( + model_name='qivipquiz', + name='creator', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='creator_quiz', to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/django/library/migrations/0028_alter_qivipquiz_creator.py b/django/library/migrations/0028_alter_qivipquiz_creator.py new file mode 100644 index 0000000..b3e7941 --- /dev/null +++ b/django/library/migrations/0028_alter_qivipquiz_creator.py @@ -0,0 +1,21 @@ +# Generated by Django 5.1.7 on 2025-04-04 13:57 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('library', '0027_qivipquiz_creator'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.AlterField( + model_name='qivipquiz', + name='creator', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='creator_quiz', to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/django/library/migrations/0029_qivipquiz_credits.py b/django/library/migrations/0029_qivipquiz_credits.py new file mode 100644 index 0000000..7b4e8fd --- /dev/null +++ b/django/library/migrations/0029_qivipquiz_credits.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.7 on 2025-04-04 16:02 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('library', '0028_alter_qivipquiz_creator'), + ] + + operations = [ + migrations.AddField( + model_name='qivipquiz', + name='credits', + field=models.TextField(blank=True), + ), + ] diff --git a/django/library/migrations/0030_remove_qivipquiz_creator_and_more.py b/django/library/migrations/0030_remove_qivipquiz_creator_and_more.py new file mode 100644 index 0000000..0401baa --- /dev/null +++ b/django/library/migrations/0030_remove_qivipquiz_creator_and_more.py @@ -0,0 +1,27 @@ +# Generated by Django 5.1.7 on 2025-04-05 09:39 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('library', '0029_qivipquiz_credits'), + ] + + operations = [ + migrations.RemoveField( + model_name='qivipquiz', + name='creator', + ), + migrations.RemoveField( + model_name='qivipquiz', + name='modified_description', + ), + migrations.AddField( + model_name='qivipquiz', + name='base_quiz', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='child_quizzes', to='library.qivipquiz'), + ), + ] diff --git a/django/library/models.py b/django/library/models.py index a35d6d9..f49d071 100644 --- a/django/library/models.py +++ b/django/library/models.py @@ -27,6 +27,8 @@ class QivipQuiz(models.Model): image = models.ImageField(max_length=256, upload_to='quiz_images/', blank=True, null=True) # Bild speichern in media/quiz_images/ 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') + base_quiz = models.ForeignKey('self', on_delete=models.SET_NULL,blank=True, null=True, related_name='child_quizzes') creation_date = models.DateTimeField(auto_now_add=True) update_date = models.DateTimeField(auto_now=True) status = models.CharField(max_length=10, choices=list(STATUS_VALUES.items()), default="öffentlich") @@ -35,11 +37,13 @@ class QivipQuiz(models.Model): name = models.CharField(max_length=75) description = models.TextField(validators=[validate_description],max_length=200,blank=False, default="In dem Quiz geht es um ...") difficulty= models.CharField(max_length=13, choices=list(DIFFICULTY_VALUES.items()), default="nicht gesetzt", help_text="1: niedrigste Schwierigkeit und 5: höchste Schwierigkeit") - + credits=models.TextField(blank=True, editable=True) def __str__(self): + return self.name + # Create your models here. class QivipQuestion(models.Model): uuid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) diff --git a/django/library/urls.py b/django/library/urls.py index 45d780c..befd359 100644 --- a/django/library/urls.py +++ b/django/library/urls.py @@ -14,6 +14,8 @@ urlpatterns = [ path('question/new/', views.new_question, name='new_question'), path('question/edit//', views.edit_question, name='edit_question'), path('question/delete//', views.delete_question, name='delete_question'), + path('detail/copy//', views.copy_quiz, name='copy_quiz'), + ]# Nur für die Entwicklungsumgebung if settings.DEBUG: urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/django/library/views.py b/django/library/views.py index cd95d07..b947631 100644 --- a/django/library/views.py +++ b/django/library/views.py @@ -1,3 +1,4 @@ +import uuid from django.shortcuts import render, redirect, get_object_or_404 from django.contrib.auth.decorators import login_required from django.contrib.auth.models import User @@ -26,7 +27,6 @@ def overview_quiz(request): filter_my_quizzes = QivipQuiz.objects.none() filter_other_quizzes = QivipQuiz.objects.annotate(max_amout_questions=Count('question')) - @@ -67,13 +67,14 @@ def overview_quiz(request): except: filter_other_quizzes=filter_other_quizzes - # Anzahl der Quiz pro Seite für Swiper - print("kein Filter ,form_valid") + + filter_other_quizzes = filter_other_quizzes.filter(max_amout_questions__gte=1).filter(status='öffentlich') + context = { 'show_search': True, - 'filter_my_quizzes': filter_my_quizzes, - 'filter_other_quizzes': filter_other_quizzes, + 'filter_my_quizzes': filter_my_quizzes.order_by('-creation_date'), + 'filter_other_quizzes': filter_other_quizzes.order_by('-creation_date'), 'form': form, } @@ -91,6 +92,7 @@ def new_quiz(request): if form.is_valid(): quiz = form.save(commit=False) quiz.user_id = request.user + quiz.creator = request.user quiz.save() form.save_m2m() # Speichert die Many-to-Many Beziehungen (Tags) return redirect('library:detail_quiz', pk=quiz.pk) @@ -106,12 +108,15 @@ def edit_quiz(request, pk): if request.method == 'POST': form = QuizForm(request.POST, instance=quiz, files=request.FILES) if form.is_valid(): + form.save() - return redirect('library:detail_quiz', pk=quiz.pk) + return redirect('library:detail_quiz', pk=pk) + #return modified(request, pk) + else: form = QuizForm(instance=quiz) return render(request, 'library/form.html', {'form': form}) - + # Quiz löschen @login_required def delete_quiz(request, pk): @@ -122,9 +127,9 @@ def delete_quiz(request, pk): return render(request, 'library/delete_confirmation.html', {'object': quiz}) # Quiz anzeigen -@login_required def detail_quiz(request, pk): - quiz = get_object_or_404(QivipQuiz, pk=pk, user_id=request.user) + #quiz = get_object_or_404(QivipQuiz, pk=pk, user_id=request.user) + quiz = get_object_or_404(QivipQuiz, pk=pk) questions = QivipQuestion.objects.filter(quiz_id=quiz) # Parse JSON data for each question @@ -137,6 +142,63 @@ def detail_quiz(request, pk): 'questions': questions } return render(request, 'library/detail_quiz.html', context) +""" +def modified(request, pk): + + original_quiz = get_object_or_404(QivipQuiz, pk=pk) + words=original_quiz.modified_description.split() + word_exist=0 + print(original_quiz.creator.username) + print(request.user.username) + + for word in words: + + if word==request.user.username or word+","==request.user.username: + word_exist=1 + + + if word_exist==0 and len(words)!=0 and request.user.username!=original_quiz.creator.username: + original_quiz.modified_description +=", "+ request.user.username + + + elif word_exist==0 and request.user.username!=original_quiz.creator.username: + original_quiz.modified_description +=" "+ request.user.username + + original_quiz.save() + + return redirect('library:detail_quiz', pk=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) + + # Quiz kopieren (ohne ID, damit ein neues Objekt erstellt wird) + + new_quiz = original_quiz # Kopie erstellen (aber Achtung: Noch gleiche Referenz!) + 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.base_quiz_id = pk + #new_quiz.creator = original_quiz.creator or request.user + new_quiz.save() # Speichern als neues Objekt + # Optional: Beschreibung anpassen + # Alle zugehörigen Fragen kopieren + questions = QivipQuestion.objects.filter(quiz_id=pk) + for question in questions: + question.uuid = uuid.uuid4() + 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() + + return redirect('library:detail_quiz', pk=new_quiz.pk) + # Übersicht aller Fragen @login_required @@ -212,6 +274,7 @@ def new_question(request): question.data = json.dumps(json_data) question.quiz_id = quiz question.save() + #return modified(request, pk=quiz.pk) return redirect('library:detail_quiz', pk=quiz.pk) else: # Initialize empty question data for new questions @@ -340,7 +403,9 @@ def edit_question(request, pk): question.data = json.dumps(json_data) question.save() + #return modified(request, question.quiz_id.pk) return redirect('library:detail_quiz', pk=question.quiz_id.pk) + else: template_name = f'library/question/question_{question_type}.html' context = { @@ -351,6 +416,7 @@ def edit_question(request, pk): return render(request, template_name, context) + # Frage löschen @login_required def delete_question(request, pk): diff --git a/django/templates/library/detail_quiz.html b/django/templates/library/detail_quiz.html index e6736ef..9120802 100644 --- a/django/templates/library/detail_quiz.html +++ b/django/templates/library/detail_quiz.html @@ -1,10 +1,13 @@ {% extends 'base.html' %} {% block content %} + +

{{ quiz.name }}

+ {% if quiz.user_id == request.user %} @@ -16,26 +19,35 @@ + {% endif %} + Quiz kopieren +
{% if quiz.description %} -

{{ quiz.description }}

+

{{ quiz.description }}

{% endif %} + +

Fragen

+ {% if quiz.user_id == request.user %} Multiple Choice + {% endif %} + {% if quiz.user_id == request.user %} Wahr/Falsch + {% endif %}
@@ -46,7 +58,7 @@ {% for question in questions %} {% endif %}
+ +
+{% if quiz.base_quiz %} +

Kopie von: {{ quiz.base_quiz}}

+{% endif %} +
+
+ {% if quiz.base_quiz %} +

Autor: {{ quiz.base_quiz.user_id}}

+ {% endif %} +
+ +
+ {% if quiz.credits %} +

Credits: {{ quiz.credits }}

+ {% endif %} +
+
{% endblock %} diff --git a/django/templates/library/overview_quiz.html b/django/templates/library/overview_quiz.html index c5c66da..0cb1313 100644 --- a/django/templates/library/overview_quiz.html +++ b/django/templates/library/overview_quiz.html @@ -68,6 +68,19 @@ Schwierigkeit: {{ quiz.difficulty }}
Anzahl der Fragen: {{ quiz.question.count }}
Status: {{ quiz.status }} + + +

+ {% if quiz.authors.all %} + Autor(en): + {% for author in quiz.authors.all %} + + {{ author.username }}{% if not forloop.last %}, {% endif %} + {% endfor %} +

+ {% endif %} + +

@@ -126,6 +139,9 @@ Anzahl der Fragen: {{ quiz.question.count }}
Erstellt am: {{ quiz.creation_date }}

+ {% if quiz.original_creator %} +

Ursprünglich erstellt von: {{ quiz.original_creator }}

+ {% endif %}