DJango user-profile - Каждый раз, когда я изменяю профиль пользователя, создается новый профиль - PullRequest
0 голосов
/ 07 апреля 2020

Это, вероятно, базовый c вопрос, но я новичок в django. , .

Я создаю приложение для викторин, которое позволяет пользователям отвечать на вопросы по порядку. Например, пользователи могут ответить на вопрос 2 только после того, как они успешно ответили на вопрос 1.

Я использую django .contrib.auth для аутентификации пользователя и добавил модель профиля для расширенной информации о пользователе, включая Отслеживание всех вопросов, на которые ответил каждый пользователь.

Вот мои модели:

class Question(models.Model):
  question_text = models.CharField(max_length=400)
  answer1 = models.CharField(max_length=200)
  times_solved = models.IntegerField(default=0)
  number = models.IntegerField(default=1, unique=True)

def __str__(self):
    return self.question_text

class Profile(models.Model):
  user = models.OneToOneField(User, on_delete=models.CASCADE)
  real_name = models.CharField(max_length=100)
  questions_answered = models.ManyToManyField(Question, blank=True, null=True)
  last_wrong_answer_made_on = models.DateTimeField('last wrong answer date', null=True, blank=True)

def __str__(self):
    return self.user.username

@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    if created:
        Profile.objects.create(user=instance)

@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
    instance.profile.save()

У меня также есть индексное представление, в котором перечислены все пользователи вместе с номером последнего вопроса, на который они ответили:

class IndexView(generic.ListView):
template_name = 'piratehunt/index.html'

context_object_name = 'user_list'

def get_queryset(self):

   return Profile.objects.all().order_by('-questions_answered__number')

И мой индекс. html:

{% if user_list %}
    <ul>
    {% for user in user_list %}
        <li><a href="{% url 'piratehunt:user_detail' user.id %}">{{ team.user.username }} - {{ user.questions_answered.last.number }}</a></li>
    {% endfor %}
    </ul>
{% else %}
    <p>No users have signed up.</p>
{% endif %}

Моя проблема в моем представлении QuestionDetail. Каждый раз, когда я пытаюсь обновить профиль пользователя, чтобы указать, что он решил новый вопрос, я заканчиваю тем, что создаю новый профиль для пользователя, а не просто обновляю существующий профиль пользователя. Вот соответствующий код:

@login_required
def QuestionDetail(request, question_number):

user = User.objects.get(pk=request.user.id)
p = user.profile
last_question = user.profile.questions_answered.last()
current_question = Question.objects.get(number=(last_question.number + 1)) 
form = AnswerForm(request.POST)

if form.is_valid():
    attempt = form.cleaned_data.get('answer')
    if  attempt == current_question.answer1

   ##########This is what triggers the problem########
        user.profile.questions_answered.add(current_question)
        p.save()
        #make sure to reset the clock so that the team can answer the next question quickly
        current_question.times_solved = current_question.times_solved + 1
        current_question.save()

        messages.info(request, 'Great News!  You are correct! You can now go on to the next problem')
        return HttpResponseRedirect(reverse('piratehunt:index'))

    else:
        p.last_wrong_answer_made_on = now()
        p.save()

        messages.info(request, 'All guesses are wrong!  Try again in 2 hours.')
        return HttpResponseRedirect(reverse('piratehunt:index'))

else: #this is the GET for this view

    return render(request, 'piratehunt/question_answer.html', {'form': form, 'question': current_question.question_text})

Конечным результатом является то, что, как только пользователь ответил на два вопроса, он появляется в индексе 2 раза. html, а после того, как он ответил на три вопроса, он появляется 3 раза. и др. c. и др. c.

Вот как это выглядит:

enter image description here Почему я создаю новый профиль каждый раз, когда я сохраняю профиль ??

1 Ответ

1 голос
/ 07 апреля 2020

Вы не создаете новые профили, но набор запросов:

Profile.objects.all().order_by('-questions_answered__number')

возвращает дубликаты, потому что number - это много-много. Вы просите, чтобы профиль был упорядочен по свойству в списке объектов, прикрепленных к нему. Вы можете сделать аннотацию в этом списке, например Min или Max, или применить .distinct().

Мин. / Макс .:

from django.db.models import Max
Profile.objects.annotate(
    max_number=Max('questions_answered__number')
).order_by('-max_number')

Distinct:

Profile.objects.order_by('-questions_answered__number').distinct()

Я бы рекомендовал идти по маршруту аннотации, так как он более последовательный. И вам не нужно использовать {{ user.questions_answered.last.number }} в вашем шаблоне, который делает еще один запрос к БД.

...