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

has_object_read_permission does not work with queryset.values('fields') #26

Open
divick opened this issue Jul 8, 2016 · 3 comments
Open

Comments

@divick
Copy link

divick commented Jul 8, 2016

In my get_queryset I return a query set so that only required fields are returned instead of looking up all the fields as I have around 60 columns in my table for the model. With this, the DRYRestPermission throws assertion error.

AssertionError: '<class 'api.models.MyModel'>' does not have 'has_object_read_permission' or 'has_object_retrieve_permission' defined.

My get_queryset method looks something like this:

def get_queryset(self):
        query_fields = self.request.query_params.get('fields', None)
        return MeterData.objects.values(*query_fields.split(','))
@dbkaplan
Copy link
Owner

dbkaplan commented Jul 8, 2016

Hi Divick,
Do you have either of those functions defined on your model?

Can you post your View, Serializer, Model? It may help me get a better understanding of what is going wrong.

@andhieka
Copy link

andhieka commented Jul 9, 2016

As my understanding goes, Django returns a dictionary instead of Model
object when you use .values(...) on your queryset. This explains your
exception message: there is no method has_object_read_permission() on
object ''. From Django Model official docs:

values() and values_list() are both intended as optimizations for a
specific use case: retrieving a subset of data without the overhead of
creating a model instance.

I'm not very sure how to optimise the database fetching in your case, but
maybe using pagination and making sure you use select_related and
prefetch_related for relationships will be enough to carry you through
without sacrificing features brought by Model instance.

On Saturday, 9 July 2016, David Kaplan [email protected] wrote:

Hi Divick,
Do you have either of those functions defined on your model?

Can you post your View, Serializer, Model? It may help me get a better
understanding of what is going wrong.


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
#26 (comment),
or mute the thread
https://github.com/notifications/unsubscribe/AGYTz1ScTzDpgM8_1ummsSglHcaB6eVeks5qTqTHgaJpZM4JIUFu
.

@divick
Copy link
Author

divick commented Jul 9, 2016

Hi David,
Please find the code for my Model, View and Serializer classes. Please note that for serializer I have special need to serialize only the required fields (as passed in query parameters, which is why my serializer looks more complicated then it should be).

@andhieka has rightly pointed out though why the issue is there as values/values_list return a dictionary instead of object. But I was unable to find a solution to this problem where I want to just load individual fields instead of looking up all 60+ fields.

My ViewSet class:

class MeterDataViewSet(ModelViewSet):
    queryset = MeterData.objects.all()
    serializer_class = MeterDataSerializer
    permission_classes = [Or(IsAdminUser, And(IsAuthenticated,
                                              DRYPermissions))]
    filter_class = MeterDataFilter

    """
      We want to dynamically return fields which are passed to us in the
      request via the query paramters comma separated
    """
    def get_serializer(self, *args, **kwargs):
        serializer_class = self.get_serializer_class()

        fields = None
        if self.request.method == 'GET':
            query_fields = self.request.query_params.get('fields', None)

            if query_fields:
                fields = tuple(query_fields.split(','))

        # Get the names of fields to serialize
        kwargs['context'] = self.get_serializer_context()
        kwargs['fields'] = fields

        return serializer_class(*args, **kwargs)

    def get_queryset(self):
        query_fields = self.request.query_params.get('fields', None)

        if query_fields:
            return MeterData.objects.values(*query_fields.split(','))
        else:
            return MeterData.objects.all()

My Serializer class:

class DynamicFieldsSerializerMixin(serializers.ModelSerializer):
    def __init__(self, *args, **kwargs):
        fields = kwargs.pop('fields', None)

        super(DynamicFieldsSerializerMixin, self).__init__(*args, **kwargs)

        if fields is not None:
            allowed = set(fields)
            existing = set(self.fields.keys())
            for field_name in existing - allowed:
                self.fields.pop(field_name)

class MeterDataSerializer(DynamicFieldsSerializerMixin,
                          serializers.ModelSerializer):
    datetime = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S")
    class Meta:
        model = MeterData

My model class (not showing all fields as there are around 60 of them and I have simplified my permissions for the sake of clarity.

class MeterData(models.Model):
    meter = models.ForeignKey(Meter)
    datetime = models.DateTimeField()

    # Active Power Total
    kw_total = models.DecimalField(max_digits=13, decimal_places=2, null=True)
    # Active Power R Phase
    kw_r = models.DecimalField(max_digits=13, decimal_places=2, null=True)
    # Active Power Y Phase
    kw_y = models.DecimalField(max_digits=13, decimal_places=2, null=True)
    # Active Power B Phase
    kw_b = models.DecimalField(max_digits=13, decimal_places=2, null=True)
    ...
    ...

 @staticmethod
    def has_read_permission(request):
        if request.user.is_authenticated():
            return True
        else:
            return False

    def has_object_read_permission(self, request):
        if request.user.is_authenticated():
            if request.user.is_admin:
                return True
            elif request.user.is_org_admin:
                return True
            else:
                return False

    @staticmethod
    def has_write_permission(request):
        if request.user.is_authenticated():
                return True
        else:
            return False

    def has_object_write_permission(self, request):
        if request.user.is_authenticated():
                return True
        else:
            return False

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

No branches or pull requests

3 participants