DJango 用户配置文件 - 每次我修改用户配置文件时都会创建一个新配置文件
DJango user-profile - Each time that I modify a user's profile a new profile is created
这可能是一个基本问题,但我是 django 的新手。 . .
我正在构建一个允许用户按顺序回答问题的测验应用程序。例如,用户在成功回答问题一后才能回答问题二。
我正在使用 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')
还有我的index.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})
最终结果是,一旦用户回答了两个问题,他就在 index.html 中出现了 2 次,一旦他回答了三个问题,他就出现了 3 次,依此类推
这是它的样子:
为什么我每次保存配置文件都要创建一个新的配置文件??
您不是在创建新的配置文件,而是在创建查询集:
Profile.objects.all().order_by('-questions_answered__number')
返回重复项,因为 number
是多对多的。您要求一个配置文件由附加到它的对象列表中的 属性 排序。您可以在该列表上进行注释,例如 Min
或 Max
,也可以应用 .distinct()
.
Min/Max:
from django.db.models import Max
Profile.objects.annotate(
max_number=Max('questions_answered__number')
).order_by('-max_number')
不同:
Profile.objects.order_by('-questions_answered__number').distinct()
我建议使用注释路线,因为它更一致。而且您不必在模板中使用 {{ user.questions_answered.last.number }}
进行另一个数据库查询。
这可能是一个基本问题,但我是 django 的新手。 . .
我正在构建一个允许用户按顺序回答问题的测验应用程序。例如,用户在成功回答问题一后才能回答问题二。
我正在使用 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')
还有我的index.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})
最终结果是,一旦用户回答了两个问题,他就在 index.html 中出现了 2 次,一旦他回答了三个问题,他就出现了 3 次,依此类推
这是它的样子:
您不是在创建新的配置文件,而是在创建查询集:
Profile.objects.all().order_by('-questions_answered__number')
返回重复项,因为 number
是多对多的。您要求一个配置文件由附加到它的对象列表中的 属性 排序。您可以在该列表上进行注释,例如 Min
或 Max
,也可以应用 .distinct()
.
Min/Max:
from django.db.models import Max
Profile.objects.annotate(
max_number=Max('questions_answered__number')
).order_by('-max_number')
不同:
Profile.objects.order_by('-questions_answered__number').distinct()
我建议使用注释路线,因为它更一致。而且您不必在模板中使用 {{ user.questions_answered.last.number }}
进行另一个数据库查询。