1

I've got a model "Assignment" that I want to be able to update through the api.

Updated per comments

urls.py

router = routers.DefaultRouter()
router.register(r'assignments', views.AssignmentList, base_name='Assignments')

urlpatterns = [
    url(r'^api/v1/', include(router.urls)),
    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
]

serializers.py

class AssignmentSerializer(serializers.ModelSerializer):
class Meta:
    model = Assignment
    fields = (
        'id', 'company', 'farm', 'sensor', 'name', 'location', 'notes', 'units', 'max_height', 'frequency',
        'interval', 'max_threshold', 'min_threshold', 'notify', 'last_alert_time', 'last_alert_water_level')

views.py

class AssignmentList(viewsets.ModelViewSet):
serializer_class = AssignmentSerializer
pagination_class = None

def get_queryset(self):
    queryset = Assignment.objects.all()
    company_id = self.request.query_params.get('company_id', None)
    sensor_id = self.request.query_params.get('sensor_id', None)
    if company_id is not None:
        queryset = Assignment.objects.filter(company_id=company_id)
    if sensor_id is not None:
        queryset = Assignment.objects.filter(sensor_id=sensor_id)
    return queryset

Currently my view allows for easy filtering based on two of the fields, 'company_id' and 'sensor_id'. This allows for easy access of the data in json. Unfortunately I can't figure out how to POST back even with the built in API form. I would like to be able to filter down to a single instance and edit a single field, let's say "assignment.name" for now.

It's my understanding that...

The actions provided by the ModelViewSet class are .list(), .retrieve(), .create(), .update(), .partial_update(), and .destroy(). (DRF Docs)

So what do I need to do to leverage them to edit a model instance via url? Or honestly just edit one period. I've been running in circles trying different Mixins, views (UpdateAPIView, RetrieveUpdateAPIView etc.) and this question in particular Stack Overflow: Django Rest Framework update field.

Jon
  • 432
  • 2
  • 6
  • 20
  • You don't need to do anything. The ViewSet already does everything you need to support this. – Daniel Roseman Nov 13 '17 at 20:13
  • Well then how do I use it? The built in form will not validate because it lacks the foreign keys 'company_id', 'farm_id', and 'sensor_id'. Why it lacks those is another question entirely. – Jon Nov 13 '17 at 20:18

1 Answers1

1

Why you're lacking the required foreign key fields is entirely the question.

The reason is that presumably your fields are called company, farm and sensor, not company_id etc. Because the underlying database fields are called company_id and so on, DRF detects them as read-only properties on the model and so allows you to specify those names in the fields tuple without showing an error, but doesn't display the field in the browsable API. Change the fields tuple to include the actual names of the Django fields.

Note also that since you're using HyperlinkedModelSerializer, DRF it expects a linked ViewSet for those related models. If you don't have those defined, chnage it to a basic ModelSerializer.

Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
  • Thanks for following that lead. The API was serializing all fields previously, but those were missing from the form. Now those fields render with selects full of "Company/farm/sensor object". So it's not really usable (nothing to differentiate between objects), but selecting them will allow the form to post. How would I go about selecting an instance to edit? – Jon Nov 13 '17 at 20:54
  • Define a `__str__` method on those models (or `__unicode__` if you're still using Python 2.7) - this is the same principle as for the admin site. – Daniel Roseman Nov 13 '17 at 20:54
  • Could you elaborate a bit on that? Maybe add an example to your answer above? I'm just not sure what you mean by "Define a `__str__` method on *those* models". I'm just trying to edit a field of an instance of a model. – Jon Nov 13 '17 at 21:05
  • In order for the related instances of Company to show useful representations, you need a method on that Company model that returns that representation - and the same for Sensor and Farm. See [the docs](https://docs.djangoproject.com/en/1.11/ref/models/instances/#str). – Daniel Roseman Nov 13 '17 at 21:13
  • Really appreciate that tip! I gave each object a str to differentiate it. I was doing some pretty awful jinja and workarounds to solve that in forms previously. So now I've got the .list(), .create(), actions working. How do I use .retrieve(), .update(), .partial_update(), and .destroy() ? – Jon Nov 13 '17 at 21:40