Update ordering of related model at runtime in django - django

I do not want to apply permanent ordering with the default ordering in Meta. I would rather update it at run time and than access it from templates. Is there a more elegant way than the following?
def get_object(self, queryset=None):
question = super().get_object(queryset)
question.choice_set.ordered = question.choice_set.order_by('-votes')
return question
Because this will not update if the underlying objects changed.

Why don't you use the order_by method of the QuerySet?
Assuming you have a modell Question, which has some related model, let's call it Answer:
class Answer(models.Model):
content = models.CharField()
votes = models.IntegerField()
class Question(models.Model):
content = models.CharField()
answer = models.ForeignKey(Answer, related_name="questions")
Then you can order your retrieved results like this:
q = Question.objects.order_by('-answer__votes')
This is everything done with Django tools, no need to create anything extra.

Related

How to update through model in django many to many?

class Blog():
likes = models.ManyToManyField(User, through="myapp.Like")
class Like():
user = models.ForeignKey(Like)
blog = models.ForeignKey(Blog)
liked_at = models.DateTimeField(auto_now_add=True)
some_bool_field = models.BooleanField(default=False)
Now in views:
def like_blog(request, id):
blog = Blog.objects.get(id=id)
blog.users.add(request.user)
# now how can I update some_bool_field and How can I make use of this field
In future I can use some query like blog.users.filter(some_bool_field=False) so for that case I want to update this field.
OR AM I MISSING THE USES OF THROUGH MODEL ?
If you want to update the through model objects you can do like so:
def like_blog(request, id):
blog = Blog.objects.get(id=id)
blog.users.add(request.user)
# query your through model
Like.objects.filter(user=request.user, blog=blog).update(some_bool_field=True)
Getting all blogs filtered likes with some_bool_field=True:
true_boolean_likes = Blog.objects.filter(likes__some_bool_field=True)
for through model update you can use bellow method to update
like = Blog.objects.get(id=id)
for like in Likes.objects.filter(likes__some_bool_field =False): #or true by what you want to filter
like.the_field_want_to_update.update(id=like.id)
here .update update the value by which you are filtering here with id so it will update what data passed to it.

django model reference, Add more contraint to reference

I have a question about Django model references.
I want to add more constraints to a ForeignKey or ManytoManyField like this:
question_id = models.ManyToManyField(Question(open==True))
Or put another similar constraint:
Actually I don't want to show a question that is not open as a selection( heightened in Answer form like the image above),
of course, I have done it by some query but does Django has any built-in support for it? I have tried some other way but it didn't work. Thanks!
class Answer(models.Model):
"""Give answers"""
answer = models.TextField()
question_id = models.ManyToManyField(Question(open==True))
upVote = models.IntegerField(default=0)
downVote = models.IntegerField(default=0)
def __str__(self):
"""return string """
return self.answer
While you still can, change your model relations. What you have now is that an answer can be linked to multiple questions. However, answer contains up and down vote.
So I can create two questions:
Is 1 + 1 two?
yes
no
Is 1 + 1 three?
yes
no
I can link the answers "yes" and "no" to both questions, which can be convenient with a good interface and is normalized. But they will share the up/down votes. Instead, answer should have a foreign key to question, because an answer can only be linked to one question at a time, even if the answer text is identical to prevent sharing of the up and down votes.
Secondly, we generally don't name fields question_id, but question:
From an object relation perspective, you relate an answer to a question not to a question id. (Under the hood, question_id is created to allow faster lookups and to serve as field name in the underlying database table).
On to your actual problem: you want to limit the available choices, which is what limit_choices_to does for you. So you would end up with this:
class Answer(models.Model):
"""Give answers"""
answer = models.TextField()
question = models.ForeignKey(
Question, on_delete=models.CASCADE, related_name='answers',
limit_choices_to={'open': True},
)
upVote = models.IntegerField(default=0)
downVote = models.IntegerField(default=0)
def __str__(self):
"""return string """
return self.answer
# Serializer
class AnswerSerializer(serializers.ModelSerializer)
class Meta:
model = Answer
fields = ('answer', 'upVote', 'downVote', 'question_id')
As you can see, your serializer can reference the magic field question_id.

How do I use a ModelManager on a Django ManyToMany through field?

Let's say I have the following models:
class Poll(model):
title = models.CharField()
class Option(model):
title = models.CharField()
polls = models.ManyToManyField(
Poll,
through='PollOption',
null=True,
blank=True,
related_name='options'
)
class PollOptionManager(models.Manager):
use_for_related_fields = True
def get_queryset(self):
return super(PollOptionManager, self).get_queryset().filter(
is_active=True
)
class PollOption(model):
poll = ForeignKey(Poll)
option = ForeignKey(Option)
is_active = BooleanField(default=True)
objects = PollOptionManager()
When I try to query Poll.options.all() I'm still getting Option instances for which PollOption.is_active is False. How can I get my model manager to appropriately filter my ManyToMany relationship based on a flag on the through field?
The problem is that the through model's (related) manager is never actually used in your scenario. In order to utilize the custom manager, you have to explicitly use it, e.g.:
class Poll(models.Model):
#property
def active_options(self):
return Option.objects.filter(id__in=self.polloption_set.values_list('option'))
Here, polloption_set filters out inactive options as intended. This, however, makes the manager kind of pointless because you can just as well put the extra filter in the custom property.

Filter and count with django

Suppose I have a Post and Vote tables.
Each post can be either liked or disliked (this is the post_type).
class Post(models.Model):
author = models.ForeignKey(User)
title = models.CharField(verbose_name=_("title"), max_length=100, null=True, blank=True)
content = models.TextField(verbose_name=_("content"), unique=True)
ip = models.CharField(verbose_name=_("ip"), max_length=15)
class Vote(models.Model):
user = models.ForeignKey(User)
post = models.ForeignKey(Post)
post_type = models.PositiveSmallIntegerField(_('post_type'))
I want to get posts and annotate each post with number of likes.
What is the best way to do this?
You should make a function in Post model and call this whenever you need the count.
class Post(models.Model):
...
def likes_count(self):
return self.vote_set.filter(post_type=1).count()
Use it like this:
p = Post.objects.get(pk=1)
print p.likes_count()
One approach is to add a method to the Post class that fetches this count, as shown by #sachin-gupta. However this will generate one extra query for every post that you fetch. If you are fetching posts and their counts in bulk, this is not desirable.
You could annotate the posts in bulk but I don't think your current model structure will allow it, because you cannot filter within an annotation. You could consider changing your structure as follows:
class Vote(models.Model):
"""
An abstract vote model.
"""
user = models.ForeignKey(User)
post = models.ForeignKey(Post)
class Meta:
abstract = True
class LikeVote(Vote)
pass
class DislikeVote(Vote)
pass
i.e., instead of storing likes and dislikes in one model, you have a separate model for each. Now, you can annotate your posts in bulk, in a single query:
from django.db.models import Count
posts = Post.objects.all().annotate(Count('likevote_set'))
for post in posts:
print post.likevote__count
Of course, whether or not this is feasible depends on the architecture of the rest of your app, and how many "vote types" you are planning to have. However if you are going to be querying the vote counts of posts frequently then you will need to try and avoid a large number of database queries.

How can I write to the instance on the parent class from a subclass in Django models?

Following on from this question...
I have two primary models for my blog, Article and Link, and both are subclasses of Post. Simplifying a little, they look something like this:
class Post(models.Model):
title = models.CharField(max_length=100)
body = models.TextField()
post_date = models.DateField(db_index=True, auto_now_add=True)
class Article(Post):
feature_image = models.FileField(upload_to='feature_images')
class Link(Post):
link = models.URLField(verify_exists=True)
I want to collect over both Articles and Links, so in my view, I run Post.objects.order_by('post_date') and presto, I get the whole list--but only with the fields that are on Post. If I want to use the link in a Link instance, I can't.
I have the primary key, so I should be able to do something like Link.objects.get(pk=item.pk) and be set--but I'd have to know if this was a Link or an Article.
Can I create a post_type property on the parent model and write to it with the correct model name from the children?
I solved this in a totally different way in the end, by writing a custom manager for Post:
class PostManager(models.Manager):
def __get_final(self, pk):
for k in Post.__subclasses__():
if k.objects.filter(pk=pk).exists():
return k.objects.get(pk=pk)
return None
def __subclass_queryset(self, qs):
collection = []
for item in qs:
collection.append(self.__get_final(item.pk))
return collection
def all(self):
return self.__subclass_queryset(super(PostManager, self).all())
Now Post.objects.all() (or any other QuerySet operation I add to the manager, like order_by), and I'll get back a list of all of the objects, with their full set of specific fields. (I then reset the manager on the subclasses, so they're not saddled with these extra queries for routine operations.)