Filter a list of comments

i want to retrieve all comments for each post and put all allowed_departments from each comment in a list

i want to check in the list if the current logged in user profile department is in the list of allowed #departments for that post, then the user can view the post, below are my models and list views i have tried.

class Post(models.Model):
    id = models.BigAutoField(primary_key=True)
    title = models.CharField(max_length=100)
    # from_office = models.ForeignKey(Department, related_name='from_posts', blank=True, null=True, on_delete=models.CASCADE)
    to_office = models.ForeignKey(Department, related_name='to_posts', blank=True, null=True, on_delete=models.CASCADE)
    from_office = models.CharField(max_length=15, default=None)
    # content = models.TextField()
    content = RichTextField(blank=False, null=False)
    date_posted = models.DateTimeField(default=timezone.now)
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    comments = models.ManyToManyField('Comment', related_name='post_comments', blank=True)  # ManyToMany relationship to Comment
    # file = models.FileField(blank=True, null=True)
    file = models.FileField(upload_to='', blank=True, null=True)  # Specify the upload_to parameter


class Comment(models.Model):
    post = models.ForeignKey(Post, related_name="post_comments", on_delete=models.CASCADE)
    name = models.CharField(max_length=255)
    body = RichTextField(blank=True, null=True)
    date_added = models.DateTimeField(auto_now_add=True)
    # New field to store the list of departments that can access the post
    # departments = forms.ModelMultipleChoiceField(queryset=Department.objects.all(),widget=forms.CheckboxSelectMultiple,required=False)  # Make it optional if needed
    allowed_departments = models.ManyToManyField('Department', related_name='allowed_posts')
.

class Profile(models.Model):
    id = models.BigAutoField(primary_key=True)
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    image = models.ImageField(default='default.jpg', upload_to='profile_pics')
    department = models.ForeignKey(Department, on_delete=models.SET_NULL, null=True, blank=True)
class PostListView(LoginRequiredMixin, ListView):
    model = Post
    template_name = 'blog/home.html'
    context_object_name = 'posts'
    ordering = ['-date_posted']
    paginate_by = 5

    def get_all_allowed_departments(self, post):
        comments = post.post_comments.all()
        all_allowed_departments_ = set()

        for comment in comments:
            allowed_departments_manager = comment.allowed_departments
            departments = allowed_departments_manager.all()
            all_allowed_departments_.update(departments)

        return all_allowed_departments_

    def get_queryset(self):
        user_profile = get_object_or_404(Profile, user=self.request.user)
        user_department = user_profile.department
        

        # Filter posts based on author's department or the current user
        queryset = Post.objects.filter(
            Q(author__profile__department=user_department) | Q(author=self.request.user)
        ).order_by('-date_posted')

        
        return queryset
        


class TableHomeView(LoginRequiredMixin, ListView):
    model = Post
    template_name = 'table_home.html'
    context_object_name = 'posts'
    paginate_by = 10  # Set the number of posts per page

    def get_queryset(self):
        # Filter the posts based on the specified conditions
        return Post.objects.filter(
            models.Q(author=self.request.user) |  # Check if the user is the author
            models.Q(to_office=self.request.user.profile.department) |  # Check if user's department is the same as 'to_office'
            models.Q(author__profile__department=self.request.user.profile.department)  | # Check if user's department is the same as the author's department
            models.Q(comments__allowed_departments=self.request.user.profile.department)  # Check if user's department is in the allowed departments
        ).distinct()

    def get(self, request, *args, **kwargs):
        # Override the get method to perform additional checks if needed
        if not self.request.user.is_authenticated:
            raise Http404("You do not have permission to view this page.")
        return super().get(request, *args, **kwargs)

First, a side note: When you’re posting code (or config files) here, please enclose the code between lines of three backtick - ` characters. This means you’ll have a line of ```, then your code, then another line of ```. This forces the forum software to keep your code properly formatted. (I’ve taken the liberty of editing your original post for this.

Second, try to keep the titles to a reasonable length. There’s no need to describe your entire issue in the title.

Please clarify, which view are you looking for assistance with? What is the specific problem you’re having with it? You’re showing two different views here - to avoid confusion, let’s address one at a time.

Are you getting an error? If so, post the complete error with the traceback.

If you’re just getting incorrect results, please describe what you’re getting and how it doesn’t match what you’re looking to get.

I am using PostListView
I am getting incorrect result.

Below is an explanation of how the page works.

Every post has one or no comment and if you are commenting you can select more than one allowed department, so every comment has one or more list of allowed departments. i want to put all allowed departments from each comment under a post into a single list then check if the user profile department is in the this new list then he/she can view that particular post.

queryset = Post.objects.filter(
            Q(author__profile__department=user_department) | Q(author=self.request.user)
        ).order_by('-date_posted')

the above code is working perfectly, i want to add another filter based on the above description. but cant get it right. thanks.

Thank you very much for you kind guidance. i will take note next time.

I’m still not clear on what you’re looking to do here.

You wrote:

To try and rephrase for my understanding:

You are creating a list of Post.

Each Post has zero or more Comment related to it.

You only want to show a Post if it has at least one Comment, where that Comment is related to the Department that the current User is related to.

Is this correct?

If so, you don’t need to create a list of the Department being related to by the Comment. This should all be part of your query. (Or is there another reason why you want to build a list of Department?

Question:
If the Post has no related Comment, is the Post to be shown in the list or not?

You are creating a list of Post. YES

Each Post has zero or more Comment related to it. YES

while commenting user must choose department or departments like in the following screenshot

with this each comment will have a list of allowed department/departments, so i want to retrieve all those departments for each comment under that post and put them in a list , so user will only be able to view that particular post if his profile department is equal to any department in newly created list of all allowed department under the post .

You only want to show a Post if it has at least one Comment, where that Comment is related to the Department that the current User is related to. NO

If the Post has no related Comment, is the Post to be shown in the list or not? YES IF THE USER IS THE AUTHOR OR USER IS IN SAME DEPARTMENT WITH THE AUTHOR OR USER SATISFY THE ABOVE CRITERIA I DESCRIBE ABOVE ELSE THE POST SHOULD NOT BE SHOWN TO THE USER.

Again to reconfirm.

A User may see a post if:

  • The User is the author
  • The User and the author are in the same department
  • The User is in the department assigned to any Comment assigned to the Post.
  • The User is in the department identified by the Post.to_office field

So what you’ve got for your query in TableHomeView would appear to be correct. You could use that same query in PostListView

If you are not getting the intended results, then I would check the data in the various tables to ensure that what you’re seeing (or not seeing) is what’s expected.

So assuming I’m understanding the objective, I guess what I’m not understanding is what you want for PostListView that is different from TableHomeView.

YES TO ALL WHAT YOU HAVE LISTED ABOVE BUT STILL EVEN THE TableHomeView IS NOT GIVEN ME THE RIGHT RESULT. THE TWO VIEWS ARE TO SERVE SAME PURPOSE. IF ANYONE OF THEM WORKS I AM 100% OK.

BELOW IS MY DETAIL VIEW AND IT WORKS PERFECTLY, I WANT TO REFLECT SAME CONDITIONS ON MY POSTLISTVIEW.

class PostDetailView(DetailView):
    model = Post
    template_name = 'blog/post_detail.html'

    # Define a method to retrieve context data for rendering the template
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        pk = self.kwargs["pk"]

        form = CommentForm()
        post = get_object_or_404(Post, pk=pk)
        comments = post.post_comments.all()  # Use related name 'post_comments' for comments

        context['post'] = post
        context['comments'] = comments
        context['form'] = form
        
        return context
    
    def get_all_allowed_departments(self):
        post = self.get_object()
        comments = post.post_comments.all()
        all_allowed_departments_ = set()

        for comment in comments:
            allowed_departments_manager = comment.allowed_departments
            departments = allowed_departments_manager.all()
            all_allowed_departments_.update(departments)

        return all_allowed_departments_
    
    # Override the GET method to check if the user is the author
    def get(self, request, *args, **kwargs):
        self.object = self.get_object()
        post = self.object
        user = self.request.user

        all_allowed_departments_ = self.get_all_allowed_departments()
        # Check if the user is the author of the post
        if user == post.author or user.profile.department in all_allowed_departments_ or user.profile.department == post.author.profile.department or post.to_office == user.profile.department:
            return super().get(request, *args, **kwargs)
        else:
            # Redirect the user to the home page or any other desired URL
            return redirect('permission_denied')  # Replace 'home' with the name of your home page URL pattern
        
    # Define a POST method to handle comment submissions
    def post(self, request, *args, **kwargs):
        form = CommentForm(request.POST)
        self.object = self.get_object()
        context = super().get_context_data(**kwargs)

        post = Post.objects.filter(id=self.kwargs['pk'])[0]
        comments = post.post_comments.all()  # Use related name 'post_comments' for comments

        context['post'] = post
        context['comments'] = comments
        context['form'] = form

        if form.is_valid():
            name = form.cleaned_data['name']
            email = form.cleaned_data['email']
            content = form.cleaned_data['content']

            comment = Comment.objects.create(
                name=name, email=email, body=content, post=post  # Use 'body' instead of 'content'
            )

            form = CommentForm()
            context['form'] = form
            return self.render_to_response(context=context)

        return self.render_to_response(context=context)

You’ll need to provide a test case showing why it’s not working - show some sample data that demonstrates what isn’t showing up that should (or what’s showing up that shouldn’t).

You might want to work with some simplified models as well to produce this, it’ll be easier that way.

Also, please stop with the all caps. It makes your posts difficult to read.

sorry for the caps, it’s a technical issue from my computer.
this is my very first app ever, I don’t really understand testing that I can write one for this app especially my get_allowed_departments function, that’s why I am out here looking for help, and I just want to give my boss something to start with. this problem is the only thing stopping me from giving the app to him as that particular condition is the heart of the whole app.

or since my detail view is working as I wanted, is there a way to redirect all users that satisfy all the conditions in the detail view to the detail page?

You have commented a couple times that the existing query is not working.

You need to provide detailed information about what is not working. (Just saying that it isn’t working doesn’t provide any information to us to help identify the cause of the issue. Now, while I may have some ideas as to what may not be working, I’ll need more information to be sure.)

  • Are you seeing data that you don’t think you should be seeing? If so, then we’d need to see at least one of those rows, along with all the related data, to try and figure out why you’re seeing it.

  • Are you not seeing data that you expect to see? Then we’d also need to see at least one row that you think should be showing up, but isn’t.

Are you seeing data that you don’t think you should be seeing? If so, then we’d need to see at least one of those rows, along with all the related data, to try and figure out why you’re seeing it. No

Are you not seeing data that you expect to see? Then we’d also need to see at least one row that you think should be showing up, but isn’t. Yes

below is what a user who satisfy any of the requirement in listview should see

as u can see from the screenshot above TESTING_2 is the author so he can view post and view it details like below

he is in modernization Department so every user in modernization department should be able to view and see the detail just like him in the pictures above. example testuser below

when adding comment to the post i select another 2 departments (RISK MANAGEMENT and MODERNIZATION) that should be able to view and see detail of the post

but none of the users from either department can view the post but they all can see the detail of the post , see below.

I want the two departments added and any other that may be added in another comment under this same post to be able to view the post.

So the next step would be to verify in the database that the relationships you are expecting to see actually exist in the tables.

Showing screen displays here are illustrative, but don’t really show the data that is involved.

For example, if you know a specific post that you’re expecting a specific user to see - but they aren’t seeing it, then the output from the following SQL statements would verify that they are supposed to see that post. (Note, these aren’t the exact SQL statements, you’ll have to identify the real table names and columns to use. They are intended to illustrate the type of information that would be useful and are not exact commands to be entered directly.)

select id, title, to_office, author from post where id = <whatever id for the target post>
select post, comment from comment_post where post = <same id as above>
select comment, department from comment_department where comment in (<list of comment ids from above)
select id, "department name"? from department where id in (departments from the previous list)

It’s also useful to explore the queries you’re trying to use in the Django shell to see what you’re going to get.

For example, take your original query:

Then try each of these clauses individually.
e.g.,

a_user = <the user you are assuming is logged in>
Post.objects.filter(author=a_user)
Post.objects.filter(to_office=a_user.profile.department)
Post.objects.filter(author__profile__department=a_user.profile.department)
Post.objects.filter(comments__allowed_departments=a_user.profile.department)

By looking at the output from each of these, you can see what Post would be seen for each condition. If you know which condition you expect a Post to satisfy, and it doesn’t show up, then you know where you need to dig deeper.