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

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)

Related

How to make Django queries with associated tables?

I'm trying to create a 'saved post' feature on a website. I'm struggling with how to create a query that I can use to populate my HTML template with posts.
Here are my models:
class User(AbstractUser):
pass
class Post(models.Model):
title = models.CharField(max_length=200)
description = models.CharField(max_length=500)
class SavedPost(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE)
user = models.ForeignKey (User, on_delete=models.CASCADE, null=True)
My .views looks like this
def savedpostsview(request):
posts = Post.objects.all
savedposts = posts.savedpost_set(user = request.user)
return render(request, "posts/savedposts.html",{
'savedposts': savedposts
})
Right now I'm getting the error "'function' object has no attribute 'savedpost_set'".
I know I'm getting something wrong syntactically, but I've been reading documentation forever and can't figure out what it is for the life of me. Does anybody have any insight into what I'm doing wrong?
first of all here Post.objects.all all() is a function and thats why error is "'function' object has no attribute 'savedpost_set'"
You should call Post.objects.all() this will return queryset.
Then You are trying to reverse query on queryset which not possible and will throw error.
All you want is this Post.objects.filter(savedpost__user=request.user)

Add entries to model with ForeignKey

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)}')

Filtering by Field on Foreign Key

I've got two models that are related to one another
class IndustryService(models.Model):
title = models.CharField(max_length=120)
pricingisarate = models.BooleanField(default=False)
class UserService(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.ForeignKey(IndustryService, on_delete=models.CASCADE, null=True, blank=True)
Within a view, I'm trying to develop a queryset of UserService instances that
a) belongs to a user
b) on the foreign key, has pricingisarate == True
I've tried the following query, but it doesn't work:
services = UserService.objects.filter(user=user, industryservice__pricingisarate__is=True)
Thanks for your help!!!
Got it!
services = UserService.objects.filter(user=user, title__pricingisarate=True)
You can filtering Foreign-Keys fields by using double underline between foreign-key defined name and sub field name that you want filtering by this, for your case it is similar below:
title__pricingisarate
And your query must change as below:
services = UserService.objects.filter(user=user, title__pricingisarate=True)
Some formal examples of Django about this article is available...
services = UserService.objects.filter(user=user, title__pricingisarate=True)
Because UserService is related to IndustryService model using lookup title.
Please refer to this link - https://docs.djangoproject.com/en/2.1/topics/db/queries/#lookups-that-span-relationships

ValueError: Lookup failed for model referenced by field

I have made Custom User model in my Django project. Here it is:
class CustomUser(User):
avatar = models.ImageField(upload_to='avatars')
about_myself = models.TextField(max_length=300)
USERNAME_FIELD = 'username'
def __str__(self):
return self.username
def is_author(self):
return 'blog.change_post' and 'blog.add_post' in self.get_all_permissions()
And after it, I changed all Foreign Keys of user to new CustomUser model. It works OK. But I make one new migration and django cause error, when I want to migrate it:
ValueError: Lookup failed for model referenced by field blog.Comment.author: main.CustomUser
My blog.Comment model:
class Comment(models.Model):
content = models.TextField()
author = models.ForeignKey(CustomUser)
date_create = models.DateTimeField(auto_now_add=True)
post = models.ForeignKey(Post)
What should I do?
Thanks!
Judging from the code you posted, you might be might be better served by extending the user model rather than replacing it. This pattern is usually called a profile model and works via a one-to-one relationship with User.
Profiles provides application specific fields and behaviors, while allowing User to go about it's usual business unchanged. It doesn't require you to muck around with rewriting auth or even necessarily change your foreign keys.
Here's an example of your code written as a profile:
class Profile(models.Model):
# Link to user :
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
avatar = models.ImageField(upload_to='avatars')
about_myself = models.TextField(max_length=300)
def __str__(self):
return self.user.username
def is_author(self):
return 'blog.change_post' and 'blog.add_post' in self.user.get_all_permissions()
Comment model:
class Comment(models.Model):
content = models.TextField()
author = models.ForeignKey(settings.AUTH_USER_MODEL)
date_create = models.DateTimeField(auto_now_add=True)
post = models.ForeignKey(Post)
# How to access the profile:
def check_author(self):
self.author.profile.is_author()
You'll also want to add a signal to create a new profile when a user is registered:
#receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_profile_for_new_user(sender, created, instance, **kwargs):
if created:
profile = Profile(user=instance)
profile.save()
Django docs on extending users.
If a profile approach doesn't work for you, try inheriting from AbstractUser or AbstractBaseUser instead of User. The abstract models provide the same basic functionality as User and are the preferred technique for recent Django versions.
There are a handful of additional steps however, check out the docs on creating custom users for a run down.

Retrieve Django rest framework related fields

Using the django-rest-framework is it possible to retrieve content from a related field. So for example I want to create a genre list which contains all projects within it. This is what I have but I keep on getting the error:
'Genre' object has no attribute 'project_set'
models.py
class Genre(models.Model):
name = models.CharField(max_length=100, db_index=True)
class Project(models.Model):
title = models.CharField(max_length=100, unique=True)
genres = models.ManyToManyField(Genre, related_name='genres')
serializers.py
class GenreSerializer(serializers.ModelSerializer):
project_set = serializers.ManyRelatedField()
class Meta:
model = Genre
fields = ('name', 'project_set')
The related name you're using on the Project class is badly named. That related name is how you access the set of projects related to a given genre instance. So you should be using something like related_name='projects'. (As it is you've got it the wrong way around.)
Then make sure that your serializer class matches up with the related name you're using, so in both places project_set should then instead be projects.
(Alternatively you could just remove the related_name='genres' entirely and everything will work as you were expecting, as the default related_name will be 'project_set'.)

Categories