I am using a Detail View generic and I am trying to add an attribute to each item for a group of Comments (The detail view is for a Post that has many comments). I am trying to loop through the group of comments and assign a boolean to a new attribute is_liked_by_user. When I try to print comment.is_liked_by_user it will show in the scope of it but when I try to find it in the context['post'] I get this error *** AttributeError: 'Comment' object has no attribute 'is_liked_by_user'. What is the correct way to assign this attribute so that it can be passed to my template?
class DetailView(LoginRequiredMixin,generic.DetailView):
model = Post
template_name = 'posts/detail.html'
form_class = CommentsForm
def get_context_data(self, **kwargs):
# Call the base implementation first to get the context
context = super(DetailView, self).get_context_data(**kwargs)
# Create any data and add it to the context
context['form'] = self.form_class
post = context['post']
comments = post.comment_set.all()
for i, comment in enumerate(comments):
comment.is_liked_by_user = check_existing_dictionary_in_list(comment.reactions.all(), "user", self.request.user)
print("Was comment liked by user?", comment.is_liked_by_user, comment.comment_body)
# comment.is_liked_by_user = check_existing_dictionary_in_list(comment.reactions.all(), "user", self.request.user)
# context['is_liked_by_user'] = check_existing_dictionary_in_list(post.reactions.all(), "user", self.request.user)
pdb.set_trace()
return context
class Comment(models.Model):
comment_body = models.CharField(max_length=200)
like_count = models.IntegerField(default=0)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
author = models.ForeignKey(User, on_delete=models.CASCADE, null = True)
created_date = models.DateTimeField('date created', null=True, auto_now_add=True,blank=True )
reactions = GenericRelation(Reaction)
def __str__(self):
return self.comment_body
Related
I am making django app I have a problem I dont have idea how to make seperate comment section to each Item. I do not want to have same comments for every Item on a page.
models.py
class Comment(models.Model):
comment_user = models.OneToOneField(User, on_delete=CASCADE)
item = models.OneToOneField(Item, on_delete=CASCADE)
content = models.TextField(default='')
views.py
class ShopDetailView(DetailView):
model = Item
template_name = 'shop/detail.html'
context_object_name = 'item'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['comments'] = Comment.objects.all()
return context
For a DetailView, you can obtain the related comments with:
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['comments'] = Comment.objects.filter(item=self.object)
return context
It makes however not much sense to work with a OneToOneField here, since that means that each item can only have at most one comment. You probably want a many-to-one relation, and thus work with a ForeignKey [Django-doc]:
class Comment(models.Model):
comment_user = models.OneToOneField(User, on_delete=CASCADE)
item = models.ForeignKey(Item, on_delete=CASCADE)
content = models.TextField(default='')
I have made a blog where a user can like or unlike, so everything is working fine now but I have tried to add a Like Model to view more details related to each like that takes place by which user and when.
In the Like Model I have added a value for each model and choices are Like and 'Unlike'
I have tried in the views to use get_or_create but it cause an error TypeError: Field 'id' expected a number but got <built-in function id>.
and I tried to add the value incase a like and unlike is made it returned AttributeError: 'str' object has no attribute 'save'
I am going to show the view with my trials commented
First here is the post model:
class Post(models.Model):
content = RichTextUploadingField(null=True, blank=True)
num_likes = models.IntegerField(default=0, verbose_name='No. of Likes')
likes = models.ManyToManyField(User, related_name='liked', blank=True)
Here is the like model:
LIKE_CHOICES = (
('Like', 'Like'),
('Unlike', 'Unlike')
)
class Like(models.Model):
# To know Who liked
user = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
value = models.CharField(choices=LIKE_CHOICES, max_length=8)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now=True)
Here is the views.py
def LikeView(request):
# post = get_object_or_404(Post, id=request.POST.get('post_id'))
post = get_object_or_404(Post, id=request.POST.get('id'))
liked = False
current_likes = post.num_likes
user = request.user
if post.likes.filter(id=request.user.id).exists():
post.likes.remove(request.user)
liked = False
current_likes = current_likes - 1
# Like.value=='Unlike'(..2nd Trial..)
else:
post.likes.add(request.user)
liked = True
current_likes = current_likes + 1
# Like.value=='Like'(..2nd Trial..)
# Like.value.save() (..2nd Trial..)
post.num_likes=current_likes
post.save()
#-----------------------1st trial--------------------
# like, created = Like.objects.get_or_create(user=user, id=id)
# if not created:
# if like.value == 'Like':
# like.value = 'Unlike'
# else:
# like.value = 'Like'
# like.save()
# ----------------------------------------------------------
context = {
'total_likes': post.total_likes,
'liked': liked,
'post': post
}
if request.is_ajax:
html = render_to_string('blog/like_section.html', context, request=request)
return JsonResponse({'form': html})
My question:
When a user clicks the like button how do I create an new like with the value of 'Like'?
If you have id then you don't need to use the user field. So you can try this way:
like, created = Like.objects.get_or_create(user=user, post=post)
The above code will create or just fetch a Like object or record with the specified user & post. i.e the user has liked the post.
And I think you should also set default value for the value field in Like Model.
Like model
LIKE_CHOICES = (
('like', 'Like'),
('unlike', 'Unlike')
)
class Like(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
value = models.CharField(choices=LIKE_CHOICES, max_length=8, default='like') #like this
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now=True)
models.py
class PostAdvertisment(models.Model):
# post=models.ForeignKey(Post,on_delete=models.CASCADE,null=True,blank=True)
created_at=models.DateTimeField(auto_now_add=True)
title=models.CharField(max_length=255,null=True,blank=True)
url=models.URLField(null=True,blank=True)
advertizing_content= models.TextField(null =True ,blank=True)
def __str__(self):
return f'{self.title}'
class Post(models.Model):
# created_at=models.DateTimeField(efault=datetime.now, blank=True)
created_at=models.DateTimeField(auto_now_add=True)
author=models.ForeignKey(User,on_delete=models.CASCADE,related_name="post")
title=models.CharField(max_length=128,null=True,blank=True)
rate=models.IntegerField(validators=[MinValueValidator(1),MaxValueValidator(5)],default=True,null=True,blank=True)
# rating=models.IntegerField(null=True,blank=True)
content=models.TextField(null=True,blank=True)
review=models.CharField(max_length=250,null=True,blank=True)
url=models.URLField(null=True,blank=True)
voters = models.ManyToManyField(settings.AUTH_USER_MODEL,blank=True,related_name="post_voters")
tags = TaggableManager(blank=True)
comments=models.ManyToManyField('Comment',blank=True,related_name="comments_post")
anonymous = models.BooleanField(default=False, blank=True)
fake = models.BooleanField(default=False, blank=True)
genuine = models.ManyToManyField(settings.AUTH_USER_MODEL , blank=True, related_name="post_genuines")
spam = models.ManyToManyField(settings.AUTH_USER_MODEL , blank=True, related_name="post_spames")
advertisement=models.ForeignKey(PostAdvertisment,on_delete=models.CASCADE,null=True,blank=True)
def __str__(self):
return f'{self.content}'
def get_absolute_url(self):
return reverse('post:post_detail' , kwargs={'post_id':Post.id})
so here is my serializers.py
class PostSerializer(TaggitSerializer,serializers.ModelSerializer):
tags = TagListSerializerField()
author = serializers.StringRelatedField(read_only=True)
comments = CommentSerializer(many=True, required=False, read_only=True)
# title = serializers.CharField()
advertisement = PostAdvertisementSerializer()
# advertisement = serializers.SlugRelatedField(
# queryset=PostAdvertisment.objects.all(),
# slug_field='advertisement'
# )
# category_name = serializers.CharField(source='advertisement.title')
class Meta:
model = Post
fields = ('id','title','rate','author','content','review','url','tags', 'fake','comments', 'created_at', 'anonymous','advertisement')
# def create(self, validated_data):
# tag = validated_data.pop('advertisement')
# tag_instance, created =PostAdvertisment.objects.get_or_create(title=tag)
# article_instance = Post.objects.create(**validated_data, advertisement=tag_instance)
# return article_instance
# def create(self, validated_data):
# serializer = self.get_serializer(data=self.request.data)
# advertisment = self.request.data.pop('advertisement')
# company_instance = PostAdvertisment.objects.filter(id=advertisment).first()
# if not serializer.is_valid():
# print(serializer.errors)
# data = serializer.validated_data
# serializer.save(PostAdvertisment=company_instance)
# headers = self.get_success_headers(serializer.data)
# return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
def create(self,validated_data):
advertisement=validated_data.pop('advertisement')
post= Post.objects.create(**validated_data)
for advertise in advertisement:
PostAdvertisment.object.create(**advertise)
return post
so the commented part of the code is something which I've Tried
differnt appraoches gave me differnt kidn of error but none of them have worked
https://www.django-rest-framework.org/api-guide/relations/#writable-nested-serializers
I've followeed this
but its no use when ever i try to post an object either that advertisment might be null or it gives me some kind of strange error depening on the create method i have used
"advertisement":[]
this is what the error
{
"advertisement": {
"non_field_errors": [
"Invalid data. Expected a dictionary, but got list."
]
}
}
when i changed it to {}
"advertisement": null
but when i tried to give data to it
AttributeError at /api/post/
type object 'PostAdvertisment' has no attribute 'object'
Request Method: POST
Request URL: http://localhost:8000/api/post/
im not sure how to add data to nested objects
You missprinted, not PostAdvertisment.object.create(**advertise) but PostAdvertisment.objects.create(**advertise) you missed "s".
Advice you to read the error(traceback).
First, I don't think the advertisement is expected to be a list. Based on the Post model and PostSerializer, advertisement is only one.
After creating a PostAdvertisement you also have to update post.advertisement/post.advertisement_id. This is how I think it would be:
advertisement=validated_data.pop('advertisement')
post = Post.objects.create(**validated_data)
post.advertisement = PostAdvertisment.objects.create(**advertisement)
post.save()
return post
You could also create the PostAdvertisement first then create the Post so there is only 2 db queries instead of 3:
validated_data["advertisement"] = PostAdvertisment.objects.create(**validated_data["advertisement"])
post = Post.objects.create(**validated_data)
return post
I have app in Django 1.8 and I want to take last object (based on pub_date) and set for this object filed is_mainteaser on True and rest ssould be set on False.
Here is my code, but latest object hasn't field set to True.
class ArticleListView(ListView):
model = Article
queryset = Article.objects.order_by('-pub_date')
def get_context_data(self, **kwargs):
context = super(ArticleListView, self).get_context_data(**kwargs)
lates_object = Article.objects.latest('pub_date')
lates_object.is_mainteaser = True
return context
Here is my model:
class Article(model.Models):
title = models.CharField(max_length=255)
short_text = models.TextField(max_length=10000, default='')
image = FilerImageField(null=True)
pub_date = models.DateTimeField('date published')
online_from = models.DateTimeField('online from', blank=True)
online_to = models.DateTimeField('online to', blank=True)
position = models.PositiveIntegerField(default=0)
is_mainteaser = models.BooleanField(default=False)
def __str__(self):
return self.title
class Meta:
ordering = ['position']
When you have object instance and change model attribute you must save instance. Example:
lates_object = Article.objects.latest('pub_date')
lates_object.is_mainteaser = True
lates_object.save()
I think better for this solution is use django signals or action when you add new article. In ListView is't good solution to do it that.
models.py:
class Tag(models.Model):
name = models.CharField(max_length=100)
description = models.CharField(max_length=500, null=True, blank=True)
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now_add=True)
class Post(models.Model):
user = models.ForeignKey(User)
tag = models.ManyToManyField(Tag)
title = models.CharField(max_length=100)
content = models.TextField()
created = models.DateTimeField(default=datetime.datetime.now)
modified = models.DateTimeField(default=datetime.datetime.now)
def __unicode__(self):
return '%s,%s' % (self.title,self.content)
class PostModelForm(forms.ModelForm):
class Meta:
model = Post
class PostModelFormNormalUser(forms.ModelForm):
class Meta:
model = Post
widgets = { 'tag' : TextInput() }
exclude = ('user', 'created', 'modified')
def __init__(self, *args, **kwargs):
super(PostModelFormNormalUser, self).__init__(*args, **kwargs)
self.fields['tag'].help_text = None
what i tried in views.py: (that doesn't look the correct way)
if request.method == 'POST':
form = PostModelFormNormalUser(request.POST)
print form
print form.errors
tagstring = form.data['tag']
splitedtag = tagstring.split()
if form.is_valid():
temp = form.save(commit=False)
temp.user_id = user.id
temp.save()
post = Post.objects.get(id=temp.id)
l = len(splitedtag)
for i in range(l):
obj = Tag(name=splitedtag[i])
obj.save()
post.tag.add(obj)
post = Post.objects.get(id=temp.id)
return HttpResponseRedirect('/viewpost/' + str(post.id))
else:
form = PostModelFormNormalUser()
context = {'form':form}
return render_to_response('addpost.html', context, context_instance=RequestContext(request))
Can anyone post example complete code editing this to save into Post table, Tag table and post_tag table?
The input form will contain a textbox to type 'title' and texarea for 'content' and a textbox to type 'tag' as string. The tag string is seperated by space. I need to save those tag words into Tag table and map in post_tag table.
How can i do this?
In the Django docs regarding ModelForms and save(commit=False), you'll find information regarding the save_m2m() method. I believe that is what you're looking for.
As an aside, if you're implimenting tagging, you could just use django-tagging or django-taggit
http://code.google.com/p/django-tagging/
http://django-taggit.readthedocs.org/en/latest/index.html
http://djangopackages.com/grids/g/tagging/