QuerySets are lazy in template - django

I am working on one question and answer website.I think i have mess with code.I am sending querysets all objects when only one needed.
Like sending all answer of one question when only one needed.
I print only one.
So at that time will it affect database's all record or only record which i will print in template?
View.py
questions = Question.objects.all()
context = {
'questions':questions
}
return render(request,'index.html',context=context)
template_tag.py
#register.simple_tag
def getmostvotedanswer(answers):
answer = answers.order_by('-vote')[0]
return answer.answer
index.html
<p>{% getmostvotedanswer question.answer_set.all %}</p>
In this i am sending all answers but only needed so will it affect database's performance?
Question Model
class Question(models.Model):
question = models.CharField(max_length=400)
uid = models.ForeignKey("User",on_delete=models.SET_DEFAULT,default=1,related_name='user_q_id_set')
vote = models.IntegerField(default=0)
created_at = models.DateTimeField(auto_now_add=True)
catitle = models.ForeignKey("Category", on_delete=models.CASCADE)
editUser = models.ManyToManyField("User",related_name='user_q_edit_set',null=True,blank=True)
Answer Model
class Answer(models.Model):
answer = models.TextField()
qid = models.ManyToManyField("Question")
uid = models.ForeignKey("User",on_delete=models.CASCADE,related_name='user_a_id_set')
vote = models.IntegerField(default=0)
created_at = models.DateTimeField(auto_now_add=True)
editUser = models.ManyToManyField("User",related_name='user_a_edit_set',null=True,blank=True)

In your templates, you are iterating through questions, passing all the answers to your custom template tag and find the one with the most vote.
If that's what you want, you can simply put ordering into your answers model like this:
class Answer(models.Model):
vote = models.IntegerField(default=0)
# ...
class Meta:
ordering = ['-vote']
This way, when you call question.answer_set, it will automatically sort the answers by the vote field.
So you can say question.answer_set.first to get the top voted answer.

Related

Select users with common answers to questions

I have four models and a CustomUser table.
class Profile(models.Model):
user = models.OneToOneField(CustomUser, on_delete=models.CASCADE)
class Question(models.Model):
question = models.CharField(max_length=140)
class Answer(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE, related_name='answers')
answer = models.CharField(max_length=70)
class Response(models.Model):
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='responses')
question = models.ForeignKey(Question, on_delete=models.CASCADE)
answer = models.ForeignKey(Answer, on_delete=models.CASCADE)
Each question has multiple answers but each user can only pick one answer to each question.
Each user can answer multiple questions.
How do I select a list of users with a nested list of their common answers to a reference user with just the ORM?
I can think of a hacky solution of retrieving the list of common answers and then a python loop to increment the count for each user but I would like to confine it to the ORM as I need to append this to a parent serializer (UserSerializer -> ResponseSerializer).
We can use a Prefetch object here, like:
from django.db.models import Prefetch
user_answers = Answer.objects.filter(response__user=reference_user)
CustomUser.objects.prefetch_related(
Prefetch(
'response_set',
queryset=Response.objects.filter(answer__in=user_answers),
to_attr='common_answers'
)
)
Now the CustomUsers that arise from this queryset, will have an extra attribute common_answers with Response objects that will contain Responses with an Answer that they share with reference_user.
If you are only looking for users that have at least one common answer with reference_user, you can filter out the others with:
CustomUser.objects.filter(
response__answer__response__user=reference_user
).prefetch_related(
Prefetch(
'response_set',
queryset=Response.objects.filter(answer__in=user_answers),
to_attr='common_answers'
)
).distinct()

Tag system for Django

I am building a Quiz app where a user (Content Creator or Author) can create quizzes (choice based questions and their solutions) from a specific domain. These quiz can be attempted by other users (Consumers - not yet implemented).
To allow quiz consumers to be able to search questions based on specific domains of their interest (and to add granularity to the quiz content), I am implementing a tagging system attached to the questions.
Here are my models:
class question(models.Model):
ques_id = models.AutoField(primary_key=True)
ques_text = models.TextField(max_length=1024, blank=False)
ques_author = models.ForeignKey('author')
ques_created = models.DateField(auto_now_add=True)
ques_dscore = models.IntegerField()
ques_bloom = models.CharField(max_length=3)
ques_subject = models.CharField(max_length=3)
ques_type = models.CharField(max_length=1)
ques_flags = models.CharField(max_length=16)
ques_quiz = models.ManyToManyField('quiz')
def __unicode__(self):
return self.ques_text
class choice(models.Model):
choice_id = models.AutoField(primary_key=True)
choice_text = models.CharField(max_length=256, blank=False)
choice_ques = models.ForeignKey('question')
choice_ans = models.BooleanField(default=False)
choice_tags = models.CharField(max_length=32)
def __unicode__(self):
return self.choice_text
class answer(models.Model):
answer_id = models.AutoField(primary_key=True)
answer_text = models.TextField(max_length=1024)
answer_ques = models.ForeignKey('question')
answer_choice = models.ForeignKey('choice')
answer_tags = models.CharField(max_length=128)
class author(models.Model):
user = models.OneToOneField(User)
domain = models.CharField(max_length=16)
def __unicode__(self):
return self.user.username
# a table for storing all the tags
class tags(models.Model):
tags_id = models.AutoField(primary_key=True)
tags_text = models.CharField(max_length=16)
def __unicode__(self):
return self.tags_text
# table that connects tags with question attached to the tag
# from all the research on the web, it can be infered that
# 3NF tagging (Toxi Solution) is the best way to go
# good for inserts but slow on selects
class tagcon(models.Model):
tagcon_id = models.AutoField(primary_key=True)
tagcon_tags = models.ForeignKey('tags')
tagcon_ques = models.ForeignKey('question')
I have currently applied the 3NF tagging Toxi solution. The issue is that a denormalized system would help in faster selects and a 3NF would be faster inserts but slow searches.
I am confused if I should use ManyToMany field type for tags. Could someone enlighten if it would be better to use a ManyToMany field inbuilt in Django or implement the 3NF system as done?
This is already exactly the same as a ManyToManyField. The only difference is that adding the field would give you an explicit accessor from question to tag.
(Note, your models are very odd. There is absolutely no benefit in prefixing every field name with an abbreviated version of the model name; you can only ever access the field via the model anyway, so you would always be doing question.ques_text, which is redundant. And you shouldn't be defining your own PK fields unless you have a very good reason.)
In my opinion I suggest you try these 2 projects
django-tagging.
django-taggit.

Django Queryset of related objects, after prefiltering on original model

Given a queryset for one model, I want to get a queryset of another model that is related by foreign key. Take the Django project docs' weblog schema:
class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField()
def __unicode__(self):
return self.name
class Author(models.Model):
name = models.CharField(max_length=50)
email = models.EmailField()
def __unicode__(self):
return self.name
class Entry(models.Model):
blog = models.ForeignKey(Blog)
headline = models.CharField(max_length=255)
body_text = models.TextField()
pub_date = models.DateField()
mod_date = models.DateField()
authors = models.ManyToManyField(Author)
n_comments = models.IntegerField()
n_pingbacks = models.IntegerField()
rating = models.IntegerField()
def __unicode__(self):
return self.headline
Suppose I have an author object, and I want to get every blog that author has written for, as a queryset. I do something like author_blogs = [entry.blog for entry in author.entry_set]. But I'm left with a list in this case, not a queryset. Is there a way I can do this directly with ORM queries, so I can set it up via a custom Entry manager with use_for_related_fields = True and do something like author_blogs = author.entry_set.blogs, and get the benefits of delayed evaluation, etc., of a queryset?
Edited scenario and solution
So, I realized after the fact that the application of my question is slightly different than how I posed it above, for which Daniel Roseman's situation makes a lot of sense. My situation is really more like author.entry_set.manager_method().blogs, where manager_method() returns a queryset of Entry objects. I accepted his answer because it inspired the solution I found which is to do:
author_blogs = Blog.objects.filter(entry__in=author.entry_set.manager_method())
The nice thing is that it only uses one DB query. It's a bit tricky and verbose, so I think it's best to define blogs() as an object method of Author, returning the above.
The trick for this is to remember that if you want a queryset of Blogs, you should start with the Blog model. Then, you can use the double-underscore syntax to follow relations. So:
author_blogs = Blog.objects.filter(entry__authors=author)

Modeling django model statistics

I'm working on a questionnaire model for django that should be maintainable by someone with no programming experience, so I've spent a lot of time crafting my models to compensate for minor details.. Now I want to unlock the potential of SQL database queries to be able to generate statistics about the responses and feedback given.
One of my question types is a 5 star rating, so I would like to be able to gather statistics about the question like:
How many responses for question q were 5 star (, 4star, 3star, etc.)?
What was the average rating response?
Ideally I would like to record these statistic questions in a model, and create a view that shows all the statistics asked and keep the entire thing programmatic.
Should this be a carefully crafted model or set of models like feedback, or is there already some framework or module that handles these situations for me?
My questionnaire/models.py:
class QuestionType(models.Model):
name = models.CharField(max_length=256, blank=True, default="")
class Question(models.Model):
text = models.TextField()
type = models.ForeignKey(QuestionType)
class Response(models.Model):
question = models.ForeignKey(Question)
answer = models.TextField()
class Feedback(models.Model):
user = models.ForeignKey(User)
responses = models.ManyToManyField(Response)
response_time = models.DateTimeField(auto_now_add=True)
This would cover your requirements:
class QuestionType(models.Model):
name = models.CharField(max_length=256, blank=True, default="")
class Question(models.Model):
text = models.TextField()
type = models.ForeignKey(QuestionType)
def how_many_ratings_where_x_stars(self, stars):
return self.rating_set.filter(stars=stars).count()
def average_rating(self, stars):
return self.rating_set.aggregate(models.Avg('stars'))['stars__avg']
class Response(models.Model):
question = models.ForeignKey(Question)
answer = models.TextField()
user = models.ForeignKey(User)
timestamp = models.DateTimeField(auto_now_add=True)
class Rating(models.Model):
question = models.ForeignKey(Question)
stars = models.PositiveIntegerField(min_value=1, max_value=5)
user = models.ForeignKey(User)
timestamp = models.DateTimeField(auto_now_add=True)
class Meta:
unique_together = [('question', 'user')]

Django Admin Inline objects

I'm completely new to Django coming from PHP and therefore struggling a little with the terminology. This makes searching for an answer quite hard. Hopefully, somebody can tell me if this can be done within the excellent Django admin.
Ok, so the idea is that I have a questionaire which will be filled in by members of the design world. The questionaire class has very few fields, title, introduction, date.
The questions have their own class, there is a limited number in this case 20 and they are the same on each questionaire.
Therefore I have an answers class, the answer belongs to both a questionaire and a question.
class Questionaire(models.Model):
title = models.CharField(max_length=255)
intro = models.TextField(max_length=4000)
date_entered = models.DateField()
date_modified = models.DateField()
def __unicode__(self):
return self.title
class Question(models.Model):
title = models.CharField(max_length=255)
number = models.IntegerField()
def __unicode__(self):
return self.title
class Answer(models.Model):
response = models.TextField(max_length=4000)
questionaire = models.ForeignKey('articles.Questionaire')
question = models.ForeignKey('articles.Question')
def __unicode__(self):
return self.response
Sorry about the formatting above
What I am needing in the Questionaire admin is for each question, an answer field is available inline. If possible with the question name as the form field name.
Is this possible within Django admin?
Would be most grateful for any assistance
See: https://docs.djangoproject.com/en/dev/ref/contrib/admin/#inlinemodeladmin-objects
class AnswerInlineAdmin(admin.StackedInline):
model = Answer
extra = 1
class QuestionAdmin(admin.ModelAdmin):
...
inlines = [AnswerInlineAdmin]