Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DRF Integration #210

Open
StanGirard opened this issue Dec 21, 2020 · 7 comments
Open

DRF Integration #210

StanGirard opened this issue Dec 21, 2020 · 7 comments
Labels

Comments

@StanGirard
Copy link

StanGirard commented Dec 21, 2020

ANSWER ON THIRD COMMENT

Hello guys,

Thanks a lot for this outstanding work.

I'm trying to integrate dj-organization into my DRF project and I'm having a bit of an issue. I'm struggling to filter the results the view sends back based on the user organization. I'm fairly new to Django and I'm having difficulties integrating it with DRF.

Here is my code.

My Organization

from django.db import models
from organizations.models import Organization

# Create your models here.

class Website(Organization):
    url = models.CharField(max_length=200)

My Model which references the org

import datetime
from django.db import models
from django.utils import timezone
from org.models import Website

class Extractor(models.Model):
   Org = models.ForeignKey(Website, related_name='extractor', on_delete=models.CASCADE)
   extractor_type = models.TextChoices('Extractor', 'HEADERS IMAGES LINKS')
   url = models.CharField(max_length=200)
   result = models.JSONField(blank=True, null=True)
   type_audit = models.CharField(blank=True, choices=extractor_type.choices, max_length=20)
   task_id = models.CharField(max_length=50, blank=True, null=True)
   status_job = models.CharField(max_length=30, blank=True, null=True)
   begin_date = models.DateTimeField(blank=True, null=True)

   def __repr__(self):
       return '<Audit {}>'.format(self.url)

And my view for the Extractor Model

Extractor view

class ExtractorViewSet(viewsets.ModelViewSet):
    permission_classes = [permissions.IsAuthenticated]
    """
    API endpoint that allows users to be viewed or edited.
    """
    queryset = Extractor.objects.order_by('-begin_date')
    serializer_class = ExtractorSerializer
    filter_backends = [DjangoFilterBackend,filters.OrderingFilter]
    filterset_fields = ['type_audit', 'status_job']
    ordering_fields = ['id', 'type_audit', 'begin_date']

My question is as follow:

Where do I filter the Extractor object based on the user in the request.user so that he only sees the extractor for his organization ?

I know this isn't an Issue as per say, but I'll be interested to add the answer in your documentation and an How To for others :)

Thanks a lot. Have a great day

@StanGirard
Copy link
Author

StanGirard commented Dec 21, 2020

I've looked into old issues to try to find an answer.
I've compiled an answer but now I get a 404 on my route when I add this change:
I've added the Mixins Organization and MembershipRequired and changed the get_queryset method.

Not Found: /api/extractor/
[21/Dec/2020 12:49:06] "GET /api/extractor/?ordering=id&page=1&page_size=10 HTTP/1.1" 404 1797

Extractor View

from extractor.models import Extractor
from rest_framework import viewsets
from rest_framework import filters
from rest_framework import permissions
from django_filters.rest_framework import DjangoFilterBackend

from extractor.serializers import ExtractorSerializer
from rest_framework import permissions
from org.models import Website
from organizations.views.mixins import MembershipRequiredMixin, OrganizationMixin

class ExtractorViewSet(MembershipRequiredMixin, OrganizationMixin,viewsets.ModelViewSet):
    permission_classes = [permissions.IsAuthenticated]
    """
    API endpoint that allows users to be viewed or edited.
    """
    
    queryset = Extractor.objects.order_by('-begin_date')
    serializer_class = ExtractorSerializer
    filter_backends = [DjangoFilterBackend,filters.OrderingFilter]
    filterset_fields = ['type_audit', 'status_job']
    ordering_fields = ['id', 'type_audit', 'begin_date']

    def get_queryset(self):
        return self.queryset.filter(org=self.get_organization())
        

I'm pretty sure there is something that I don't understand, and I'm probably a few lines of code away from the answer 😄

@StanGirard
Copy link
Author

StanGirard commented Dec 21, 2020

Answer

For people trying to integrate Django Organizations with Django Rest Framework (DRF) here is a working implementation of filtering results based on the user in the request.

Organization model

from django.db import models
from organizations.models import Organization

# Create your models here.

class Website(Organization):
    url = models.CharField(max_length=200)

Models

I added a custom manager for the for_user method

import datetime
from django.db import models
from django.utils import timezone
from org.models import Website

class ForUser(models.Manager):
    def for_user(self, user):
        org = Website.objects.filter(users=user)
        return self.get_queryset().filter(org__in=org.values_list('id', flat=True))
class Extractor(models.Model):
    Org = models.ForeignKey(Website, related_name='extractor', on_delete=models.CASCADE)
    extractor_type = models.TextChoices('Extractor', 'HEADERS IMAGES LINKS')
    url = models.CharField(max_length=200)
    result = models.JSONField(blank=True, null=True)
    type_audit = models.CharField(blank=True, choices=extractor_type.choices, max_length=20)
    task_id = models.CharField(max_length=50, blank=True, null=True)
    status_job = models.CharField(max_length=30, blank=True, null=True)
    begin_date = models.DateTimeField(blank=True, null=True)

    objects = ForUser()
    

    def __repr__(self):
        return '<Audit {}>'.format(self.url)
        

View

And then I overloaded the get_queryset method in my view.

from extractor.models import Extractor
from rest_framework import viewsets
from rest_framework import filters
from rest_framework import permissions
from django_filters.rest_framework import DjangoFilterBackend
from extractor.serializers import ExtractorSerializer
from rest_framework import permissions
from org.models import Website

class ExtractorViewSet(viewsets.ModelViewSet):
    permission_classes = [permissions.IsAuthenticated]
    """
    API endpoint that allows users to be viewed or edited.
    """
    serializer_class = ExtractorSerializer
    filter_backends = [DjangoFilterBackend,filters.OrderingFilter]
    filterset_fields = ['type_audit', 'status_job']
    ordering_fields = ['id', 'type_audit', 'begin_date']
    
    def get_queryset(self):
        return Extractor.objects.for_user(self.request.user).order_by('-begin_date')

I hope this will help somebody 😄 It isn't very hard but this was my first time using django.

Thanks @bennylope for this awesome project.

@StanGirard
Copy link
Author

Please let me know if you have a better solution 😄

@obvionaoe
Copy link

Hi @bennylope , is there any way to integrate this, sort of out of the box with DRF? As I'm pretty happy with the way this package handles everything already, and it'll be a bit of a hassle to "redo" most of the logic to integrate with DRF.

@marqpdx
Copy link

marqpdx commented Jul 8, 2022

i think a way to go about this is to build a DRF layer that simple is annexed to the current code, meaning there's no need to change current code at all.

For example, one could (i'm already thinking in this direction), start with one view, say displaying one's groups after authentication, and create a DRF endpoint for that. One would likely need to extend the existing view for this functionality, run that view through a serializer, codify and endpoint, add in the DRF code... none of which seems hard, just a bit methodical and time-consuming. All the DEF endpoints could extend existing views and/or just re-use some of the view code in a DRF way.

I may try this, and will post back if it's bears fruit.

@obvionaoe
Copy link

@marqpdx Seems like a good idea!

@obvionaoe
Copy link

Any updates @marqpdx ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants