How to update through model in django many to many? - django

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.

Related

Django, How to update the DateTimeField() of model by the view

As mentioned in the title, I have a model containing the DateTimeField()
models.py
class DataRow(models.Model):
last_edit_date = models.DateTimeField(default=datetime.now())
I would like to update this field every time I call the model in view. I tried to do it as follows:
views.py
data_row = get_object_or_404(DataRow, pk=row_id)
data_row.last_edit_date = datetime.now()
data_row.save()
I also checked the auto_add=True attribute and calling the .save() method of model, but it did not work either.
Answer to this question is in the comments above.

Django - Update field values in extended user model after a request is performed

My project is a social networking site that can send requests to friends and make friends.
I have extended django's existing user model using oneToone field .
So far i've been able to do the above said thing but when ever a user accepts the request , Both the user who sent request and also the user accepted it must increment a value in their extended user model which stores the value of their friends count .
I'm facing difficulties trying to solve this .
I've also used signals but it doesn't work .
Here is my code:
models.py:
class Friends(models.Model):
"""Model for saving relationship of user and friends"""
request_id = models.ForeignKey(User,on_delete=models.CASCADE,related_name='current_user')
friend_id = models.ForeignKey(User,on_delete=models.CASCADE,related_name='user_friend')
created_on = models.DateTimeField(auto_now_add=True,auto_now=False)
class Meta:
verbose_name_plural = "Friends"
def __str__(self):
return str(self.friend_id)
class Profile(models.Model):
user = models.OneToOneField(User,related_name='profile',on_delete=models.CASCADE)
location = models.CharField(max_length=30,blank=True)
friends_count = models.PositiveIntegerField(default=0)
profile_pic = models.ImageField(upload_to='profile_pics/',blank=True,null=True)
def natural_key(self):
return (self.user.username,)
signals.py:
#receiver(post_save,sender=Friends)
def update_friends_count(sender,instance,created,**kwargs):
if created:
user_profile = Profile(user = instance.request_id)
user_profile.friends_count=F('friends_count')+1
user_profile.save()
Any help would be greatly appreciated!!!!! Thank you in advance!!!
You were initializing a new instance of Profile every time a friend is made. Instead you can use get_or_create to generate a profile or retrieve the one associated with that id. Next, you want to update both users so fetch the other update the counts and save.
#receiver(post_save,sender=Friends)
def update_friends_count(sender,instance,created,**kwargs):
if created:
user_profile, profile_created = Profile.objects.get_or_create(user = instance.request_id)
user_profile.friends_count=F('friends_count')+1
user_profile.save()
friend_profile, profile_created = Profile.objects.get_or_create(user = instance.friend_id)
friend_profile.friends_count=F('friends_count')+1
friend_profile.save()
With Q filter and update
Profile.objects.filter(
Q(user=instance.request_id) |
Q(user=instance.friend_id)
).update(
friends_count=F('friends_count')+1
)
This last query uses the django.db.models Q object to make an SQL OR statement to retrieve the two profile instances; that of the requested and the requester: the update call acts on the query and updates all instances in the list

Update ordering of related model at runtime in 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.

How can I create model instance via Serializer without creating models from nested serialziers?

I have model with many links into it:
class Travel(BaseAbstractModel):
tags = models.ManyToManyField(
Tag,
related_name='travels',
)
owner = models.ForeignKey(
'users.TravelUser',
related_name='travel_owner'
)
payment = models.ForeignKey(
Payment,
related_name='travels',
)
country = models.ForeignKey(
Country,
related_name='travels,
)
........
Many of these models have only two fields with unique name and image.
I create serializer for each of these models and put them in TravelSerializer
class TravelBaseSerializer(DynamicFieldsModelSerializer):
owner = UserSerializer(required=False)
tags = TagSerializer(many=True)
payment = PaymentSerializer()
country = CountrySerializer()
Based on docs I override create() and update.
The problem is, when I sent JSON data, Django create each model from nested serializers. But I want to create only Travel instance. Also I want receive and respond serialized object not only pk field.
UPDATE
I solved this problem, put code in the answer. Now I can receive and respond with Serializer data without creating object.
But I think the DRF provides more elegant approach then I do. It is my first project with DRF, maybe I miss something and there's an easier solution.
I decide override to_internal_value() put it in custom serailizer and inherit all nested serializers from it:
class NestedRelatedSerializer(serializers.ModelSerializer):
def to_internal_value(self, data):
try:
pk = data['pk']
except (TypeError, KeyError):
# parse pk from request JSON
raise serializers.ValidationError({'_error': 'object must provide pk!'})
return pk
Get all pk from it and save in create and updated methods:
def update(self, instance, validated_data):
# If don't get instance from db, m2m field won't update immediately
# I don't understand why
instance = Travel.objects.get(pk=instance.pk)
instance.payment_id = validated_data.get('payment', instance.payment_id)
instance.country_id = validated_data.get('country', instance.country_id)
# update m2m links
instance.tags.clear()
instance.tags.add(*validated_data.get('tags'))
instance.save()
return instance
I'm not exactly sure I understand what you want to do, but could setting read_only_fields is the Meta class be what you need ?
class TravelBaseSerializer(DynamicFieldsModelSerializer):
owner = UserSerializer(required=False)
tags = TagSerializer(many=True)
payment = PaymentSerializer()
country = CountrySerializer()
class Meta:
read_only_fields = ('tags',)
See this section in the docs.

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.