Add entries to model with ForeignKey - python

I been struggling with this for a while and can't seem to find an answer on any of the other threads.
I am trying to programmatically add some entries to a model in Django, the model I am trying to add to has a foreign key, and this is what I am getting hung up on.
My two models are:
class Post(models.Model):
direct_url = models.URLField(unique=True)
post_url = models.URLField()
post_title = models.CharField(max_length=300)
time_posted = models.DateTimeField(default=timezone.now)
class Comment(models.Model):
post = models.ForeignKey(Post, related_name='comments', on_delete=models.CASCADE)
content = models.CharField(max_length=500)
author = models.CharField(max_length=60)
date_created = models.DateTimeField(default=timezone.now)
I am trying to run some code to add some data I am pulling from another location in the DetailView (Class based view)
The code that I have for that is here:
class PostDetailView(DetailView):
model = Post
for i in hot:
if i.url.endswith(Endings):
post_to = model.objects.get(direct_url=i.url)
submission = reddit.submission(url=f'https://www.reddit.com/r/{i.permalink}')
submission.comments.replace_more(limit=None)
for comment in submission.comments.list():
Comment.objects.create(post=f'{post_to}', content=f'{comment.body}', author=f'{comment.author}', date_created=f'{datetime.datetime.fromtimestamp(comment.created)}')
I am trying to pull the reddit comments, and store them in a database. The problem I am running into is the following:
ValueError: Cannot assign "'Post object (22)'": "Comment.post" must be a "Post" instance.
What am I doing wrong?

As per this meta directive, I have turned the following comment by #Sajad into a community wiki, signalling that this question is solved.
In the last line, you're formatting post_to to string and assigning it to post which must be a Post instance and not str. Just write post=post_to.
The following code should work:
class PostDetailView(DetailView):
model = Post
for i in hot:
if i.url.endswith(Endings):
post_to = model.objects.get(direct_url=i.url)
submission = reddit.submission(url=f'https://www.reddit.com/r/{i.permalink}')
submission.comments.replace_more(limit=None)
for comment in submission.comments.list():
Comment.objects.create(post=post_to, content=f'{comment.body}', author=f'{comment.author}', date_created=f'{datetime.datetime.fromtimestamp(comment.created)}')

Related

"Object has no property _set" in Django

Can't figure out where my mistake is. Not able to map through to display the list of blog comments. I'm using Django and react. From the code below, I tried to assess each blog post with comments using foreign key. But I'm not able to get the comment property from the blog. If I do something like {blog.title} I get the title of the blog back on the browser. Since comments are associated with each post I try to get different properties of comment from the blog object (just as I specified in the code below) but the value I'm getting is undefined. And have the following blog post and blog comment models:
class BlogComment(models.Model):
post = models.ForeignKey(BlogPost, on_delete=models.SET_NULL, related_name="post_comment", null=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, related_name="user_comment", null=True)
name = models.CharField(max_length=200, null=True, blank=True)
comment = models.TextField(null=True, blank=True)
dateCreated = models.DateTimeField(auto_now_add=True)
def __str__(self):
return str(self.user.username)
class BlogPost(models.Model):
...
author = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, on_delete=models.CASCADE)
body = models.TextField()
dateCreated = models.DateTimeField(auto_now_add=True)
And the serializers for both models are:
class CommentSerializer(serializers.ModelSerializer):
class Meta:
model = BlogComment
fields = '__all__'
class BlogPostSerializer(serializers.ModelSerializer):
comments = serializers.SerializerMethodField(read_only=True)
class Meta:
model = BlogPost
fields = "__all__"
def get_comments(self, obj):
comments = obj.comment_set.all()
serializer = CommentSerializer(comments, many=True)
return serializer.data
The endpint of comment is path('posts/<str:pk>/comment/', CreateCommentView, name="create-comment"),.
The endpoint is working. I'm able to add comment to posts both from the front end. The error comes when I try to map through the
comments for each post. Get the error: AttributeError: 'BlogPost' object has no attribute 'comment_set'.
Here is the code I'm using to map through to display all the blogs of a particular post in the blog details page in react. I'm assess each blog there:
<h2>{blog.title}</h2>
<img src={blog.image} />
<div variant='flush'>
{blog.comments.map((comment) => (
<div key={comment.id}>
<strong>{comment.name}</strong>
<p>{comment.dateCreated}</p>
<p>{comment.comment}</p>
</div>
))}
</div>
Here is the code I'm using to map through to display all the blogs of a particular post in the blog details page in react. If I do not map the error does not come up and I'm able to add comment. However, in order to display the comments under each blog post I map through. How do I fix this?
You need to use post_comment:
comments = obj.post_comment.all()
You declared it here:
post = models.ForeignKey(BlogPost, on_delete=models.SET_NULL, related_name="post_comment", null=True)
related_name is used as a name for Django relation. See more here.
But changing post_comment with something else would be a better solution for me.

Error when adding many-to-many-field on Post

I have an app within my project called posts, where inside their in the models.py, I have two models: Post and Like.
I want to add a many-to-many-field on the post that references the Like model.
I have executed makemigrations and migrate, however I am getting this error:
NameError: name 'Like' is not defined
models.py:
class Post(models.Model):
file = models.ImageField(upload_to='images/')
summary = models.TextField(max_length=600)
pub_date = models.DateTimeField(auto_now=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
likes = models.ManyToManyField(Like)
def __str__(self):
return self.user.username
def summary_pretty(self):
return self.summary[:50]
def pub_date_pretty(self):
return self.pub_date.strftime('%b %e %Y')
class Like(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
status = models.BooleanField(default=False)
it says
NameError: name 'Like' is not defined
because you must move Like model above Post model it hasn't been defined yet in your code in that line (python code is interpreted)
and it's not a good thing to design database models like that based on:
Why should I avoid loops when designing relationships for a database?
so delete the Post foreign key in Like model and you can retrieve a like's post with reverse lookup
you can find more about it in django official docs:
Lookups that span relationships
and also
Many-to-many relationships
You're referencing the class Like before initiating it in your Python file. Hence "Like" is not defined.
likes = models.ManyToManyField(Like)
You need to delete "likes" from your Post class. That will fix the error.
As for your code, I think you're misunderstanding why we use Intermediary Tables. You don't need to reference Like in your Post class. You've already established that relationship in the Like Class:
post = models.ForeignKey(Post, on_delete=models.CASCADE)
Retrieving the users who have liked a post is as simple as writing a filter on the Likes table.
#views.py
from models import Post, Like
post_id = 1
likes = Like.objects.filter(post=post_id)

Django efficient Queryset with Foreign Key Models

I'm trying to find the most efficient way (as less db queries as possible) for the following model structure.
In my template I then want to pass all the data from all 3 models because I would have to show the post data as well as looping through the comments to create a comments list and display all the attachments for the different comments.
class Post(BaseModel):
user = models.ForeignKey('User', blank=True, null=True,
title = models.CharField(max_length=128)
content = models.TextField()
class Comment(BaseModel):
post = models.ForeignKey('Post', on_delete=models.CASCADE)
user = models.ForeignKey('User', on_delete=models.SET_NULL)
text = models.TextField()
class CommentAttachment(BaseModel):
comment = models.ForeignKey('Comment', on_delete=models.CASCADE)
name = models.CharField(max_length=128)
Should I fetch all data from CommentAttachment direction (meaning fetching all CommentAttachments where comment__post__id is the post id and then get all other data with select_related) or is there another way to start from the Post Model?
You can use prefetch_related or select_related in your query:
posts = Post.objects.filter(user=some_user).prefetch_related(
'comment_set', 'comment_set__commentattachment_set'
)
For example, after making a query as mentioned, the following command may retrieve all the comments for the first post in the queryset without making a SQL query:
posts.first().comment_set.all()

View articles by author in Django blog

I'm trying to create a view that allows one to see all blog posts written by a particular author. Here's the URL pattern I'm using:
url(r'^user/(?P<username>[\w-]+)/$', views.user_articles, name="user_articles"),
And here's my view:
def user_articles(request, username):
articles = Article.objects.filter(author=username).order_by('-date')
return render(request, "articles/article_list.html", {'articles': articles})
This is returning the error:
ValueError at /articles/user/danny/
invalid literal for int() with base 10: 'danny'
Editing to add model as well:
class Article(models.Model):
title = models.CharField(max_length=100)
slug = models.SlugField(max_length=100, unique=True)
body = HTMLField('Body')
date = models.DateTimeField(auto_now_add=True)
thumb = models.ImageField(default="keys.jpg", blank=True)
author = models.ForeignKey(User, default=None)
danny is a valid username, and it should be a string, not an integer, so I'm not sure what's going wrong here. Any ideas?
Considering author, which is a ForeignKey to auth.User .
Your query should be
Article.objects.filter(author__username=username)
instead of ...Article.objects.filter(author=username)
Post your model but I assume the association between models, is a Foreign Key. So 'author' on your model Article is likely an ID and not a string. So instead of the username 'danny' try retrieving 'danny's ID.

how to delete item in listfield for django nonrel

I use mongodb as the django nonrel database to build a blog site. The basic models for the blog site are:
class Post:
comments = ListField(EmbeddedModelField('Comment'))
....(omitted here)
class Comment:
created = models.DateTimeField(auto_now_add=True)
author = models.CharField(max_length=35)
email = models.EmailField(max_length=64)
text = models.TextField()
ip_addr = models.IPAddressField()
I found that when I created a comment and append it to the listfield of a post, the comment will not have an objectid because it's embedded. Thus, when I want to delete a comment, I have trouble to let the database know which comment I want to delete. Is it possible that I pass the comment from the template to views without the url function in urls.py?
You can rewrite the model as
class Post:
comments = ListField(models.ForeignKey('Comment'))
....(omitted here)
class Comment:
created = models.DateTimeField(auto_now_add=True)
author = models.CharField(max_length=35)
email = models.EmailField(max_length=64)
text = models.TextField()
ip_addr = models.IPAddressField()

Categories