Django: exclude objects based on another model - python

I have a model Comment:
class Comment(models.Model):
upload = models.ForeignKey(Upload, related_name='comments', on_delete=models.CASCADE)
user = models.ForeignKey(get_user_model(), related_name='comments', on_delete=models.CASCADE)
text = models.TextField(blank=False, null=False)
date_created = models.DateTimeField(auto_now_add=True)
And I also have a model BlockedUser:
class BlockedUser(models.Model):
blocked_by = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, related_name="blocked_by")
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
date_created = models.DateTimeField(auto_now_add=True)
How can I fetch all the comments except ones written by someone who you've blocked?
queryset = Comment.objects.all().select_related('user')
queryset = queryset.exclude(user__in=BlockedUser.objects.filter(blocked_by=self.request.user))
Which obviously doesn't work like that, but I am not sure how to write it so that it does work.

You can exclude Comments from a user for which there exists a BlockedUser with blocked_by the request.user with:
Comment.objects.exclude(user__blockeduser__blocked_by=request.user)

Related

Override django's foreignkey on_delete SET_NULL function

So, I have a Comment model in a django project I am trying to make, what I want to do is to override the on_delete function of the ForeignKey
COMMENT_TYPES = (
(1, "Comment"),
(2, "Reply to a comment"))
class Comment(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
comment_text = models.CharField(max_length=80, blank=False, null=False)
id = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True,editable=False)
date_created = models.DateTimeField(auto_now_add=True)
date_edited = models.DateTimeField(auto_now=True)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
parent_comment = models.ForeignKey('self', blank=True, null=True, on_delete=models.SET_NULL)
comment_type = models.IntegerField(choices=COMMENT_TYPES, default=1)
What I want is that when I delete a comment, then all the comments that were linked to the deleted comment, their comment_type should change from 2('reply to a comment') to 1('comment'), so is there a way to override the on_delete function, SET_NULL so that I can change the value in the comment_type field?

Make migrations is not detecting many to many field in model

Following are my models:
class Message(models.Model):
sender = models.ForeignKey(
to=Profile, on_delete=models.CASCADE, related_name="sender", null=True) # This null is temporary will remove it
receiver = models.ForeignKey(
to=Profile, on_delete=models.CASCADE, related_name="receiver", null=True) # This null is temporary will remove it
text = models.TextField()
timestamp = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.text
class Meta:
ordering = ["timestamp"]
class Chat(models.Model):
conversation: models.ManyToManyField(Message) #---> This field is not being detected.
first_participant = models.ForeignKey(
Profile, on_delete=models.CASCADE, related_name="first_participant")
second_participant = models.ForeignKey(
Profile, on_delete=models.CASCADE, related_name="second_participant")
date_modified = models.DateTimeField(auto_now=True)
No matter what i do, make migrations is not detecting this many to many field. Can someone please help?
You put conversation: models.ManyToManyField(Message) instead of conversation=models.ManyToManyField(Message)

message_set of Django model

i'm new with Django and as I read the code, I don't understand the message_set attribute of Django model(called Room):
def room(request, pk):
room = Room.objects.get(id=pk)
**room_messages = room.message_set.all()**
participants = room.participants.all()
portion of Models:
class Room(models.Model):
host = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
topic = models.ForeignKey(Topic, on_delete=models.SET_NULL, null=True)
name = models.CharField(max_length=200)
description = models.TextField(null=True, blank=True)
participants = models.ManyToManyField(
User, related_name='participants', blank=True)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
class Message(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
room = models.ForeignKey(Room, on_delete=models.CASCADE)
body = models.TextField()
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
If you define a ForeignKey from Message to Room, Django will add a relation in reverse to the from the Room model to its related Messages. By default this relation is named modelname_set with modelname the name of the origin of the model. You can specify another name by overriding the related_name=… parameter [Django-doc].
If you thus access the relation in reverse, you get all Message objects with room as there room, an equivalent query to room.message_set.all() is thus Message.objects.filter(room=room).

NameError: name 'Profile' is not defined

here is my models.py code. im trying to run the python3.8 manage.py migrate command to create the tables for the database but i keep getting this error, what could be the issue here. Profile is a class in the models.py code. if you need another part of my code please ask
from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
class Image(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null='True', blank=True)
image = models.ImageField(upload_to = 'pics/')
name = models.CharField(max_length=50,blank=True)
caption = models.CharField(max_length=250, blank=True)
likes = models.ManyToManyField(User, related_name='likes', blank=True, )
date_posted = models.DateTimeField(default=timezone.now)
class Comment(models.Model):
comment = models.TextField()
image = models.ForeignKey('Image', on_delete=models.CASCADE,related_name='comments',null='True', blank=True )
name = models.CharField(max_length=100, blank=True)
user = models.ForeignKey(Profile, on_delete=models.CASCADE, related_name='comments',null='True', blank=True )
created = models.DateTimeField(auto_now_add=True, null=True)
class Profile(models.Model):
name = models.OneToOneField(User, on_delete=models.CASCADE)
profile_picture = models.ImageField(upload_to='images/', default='default.png')
bio = models.TextField(max_length=500, default="My Bio", blank=True)
followers = models.ManyToManyField(User, related_name="followers", blank=True)
following = models.ManyToManyField(User, related_name="following", blank=True)
You are using the Profile class before defining it. Switch the order of the Comment class and Profile class. Like so:
class Profile(models.Model):
name = models.OneToOneField(User, on_delete=models.CASCADE)
profile_picture = models.ImageField(upload_to='images/', default='default.png')
bio = models.TextField(max_length=500, default="My Bio", blank=True)
followers = models.ManyToManyField(User, related_name="followers", blank=True)
following = models.ManyToManyField(User, related_name="following", blank=True)
class Comment(models.Model):
comment = models.TextField()
image = models.ForeignKey('Image', on_delete=models.CASCADE,related_name='comments',null='True', blank=True )
name = models.CharField(max_length=100, blank=True)
user = models.ForeignKey(Profile, on_delete=models.CASCADE, related_name='comments',null='True', blank=True )
created = models.DateTimeField(auto_now_add=True, null=True)
You are referencing the Profile class before this is constructed. You can make use of a string literal instead:
class Comment(models.Model):
# …
user = models.ForeignKey(
'Profile', # ← a string literal
on_delete=models.CASCADE,
related_name='comments',
null='True',
blank=True
)
# …
It might also be better to rename the field to profile, to make it clear the ForeignKey is referencing a Profile object, not a User object:
class Comment(models.Model):
# …
profile = models.ForeignKey( # ← rename to profile
'Profile',
on_delete=models.CASCADE,
related_name='comments',
null='True',
blank=True
)
# …
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.

AttributeError: Cannot use remove() on a ManyToManyField which specifies an intermediary model. Use songs.Playlist_Activity's Manager instead

I followed the documentation on figuring out how to remove an item in the manytomanyfield below but it doesn't seem to work and I am getting an attribute error. The remove method works totally fine without the intermediary model.
models.py
class Song (models.Model):
author=models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, default=1)
timestamp= models.DateTimeField(auto_now_add=True, editable=False)
songname = models.CharField(max_length=500, null=False, blank=False)
tags = TaggableManager()
def __str__(self):
return self.songname
class Playlist (models.Model):
name = models.CharField(max_length=150, null=False, blank=False)
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, default=1)
song = models.ManyToManyField(Song, through='Playlist_Activity')
class Playlist_Activity(models.Model):
song= models.ForeignKey(Song, on_delete=models.CASCADE)
playlist= models.ForeignKey(Playlist, on_delete=models.CASCADE)
timestamp= models.DateTimeField(auto_now_add=True, editable=False)
class Meta:
ordering = ('timestamp',)
Views.py
#login_required
def Playlist_Remove(request, id, P_id):
p = Playlist.objects.get(id=P_id)
s = p.song.get(id=id)
p.song.remove(s)
return redirect('account')
You can remove the intermediary instance:
p = Playlist.objects.get(id=P_id)
s = Song.objects.get(id=id)
Playlist_Activity.objects.get(song=s, playlist=p).delete()

Categories

Resources