Django REST Framework: integer fields default value not showing up in browseable API form - django-rest-framework

Using django 1.6 and rest framework 2.3.13
In model class:
class A(models.Model):
some_name = models.PositiveSmallIntegerField(default=15)
In serilizer:
class ASerializer(ModelSerializer):
class Meta:
model = A
fields = ( 'some_name' )
In view:
class AViewSet(viewsets.ModelViewSet):
queryset = A.objects.all()
serializer_class = ASerializer
But in the api form, it's showing as 0, any idea?

This problem can be solved by adding
if obj is None and self.default is not None:
return self.default
to rest_framework/fields.py
Original pull request:
https://github.com/tomchristie/django-rest-framework/pull/1248/files

Related

Incorrect view name for nested hyperlinks using drf-nested-routers

I am attempting to use drf-nested-routers to create a simple nested Django REST API given the following models:
# models.py
class Podcast(models.Model):
title = models.CharField(max_length=125)
class Episode(models.Model):
podcast = models.ForeignKey(Podcast, on_delete=models.CASCADE)
title = models.CharField(max_length=125)
Based on the readme domains/nameservers example, I have the following routers defined, expecting a URL structure like:
/podcasts[/{podcast_pk}[/episodes[/{episode_pk}]]]
# urls.py
router = routers.DefaultRouter()
router.register(r'podcasts', PodcastViewSet)
episode_router = routers.NestedDefaultRouter(
router, r'podcasts', lookup='podcast'
)
episode_router.register(
r'episodes', EpisodeViewSet, basename='podcast-episodes'
)
# serializers.py
class PodcastSerializer(HyperlinkedModelSerializer):
episodes = HyperlinkedIdentityField(
view_name='podcast-episodes-list',
lookup_url_kwarg='podcast_pk'
)
class Meta:
model = Podcast
fields = '__all__'
class EpisodeSerializer(NestedHyperlinkedModelSerializer):
parent_lookup_kwargs = {
'podcast_pk': 'podcast__pk',
}
class Meta:
model = Episode
fields = '__all__'
# exclude = ('url',) # works without reference to self
# views.py
class PodcastViewSet(viewsets.ModelViewSet):
queryset = Podcast.objects.all()
serializer_class = PodcastSerializer
class EpisodeViewSet(viewsets.ModelViewSet):
serializer_class = EpisodeSerializer
def get_queryset(self):
return Episode.objects.filter(
podcast=self.kwargs['podcast_pk'],
)
Accessing /podcasts/1/episodes/, when url is included, raises the following error:
Exception Type: ImproperlyConfigured at /podcasts/1/episodes/
Exception Value: Could not resolve URL for hyperlinked
relationship using view name "episode-detail". You may
have failed to include the related model in your API,
or incorrectly configured the `lookup_field` attribute
on this field.
Why does it not identify the correct view name, or is there something else obvious I am missing
In my case using 'id' instead of 'pk' is solved my problem.
parent_lookup_kwargs = {
'podcast_pk': 'podcast_id',
}

Django Rest Framework - Import CSV(" No file was submitted ")

I am trying to upload CSV file in Django Rest Framework using the serializer.
Below have provides the image which contains code for Model, View, and Serializer and the console output when I try to submit the CSV file.
Before validating a serializer when I check with print(serializer.initial_data) there is a file inside the serializer, but as soon as the serializer is validating it says no file was submitted.
models.py
class InventoryFile(models.Model):
shop = models.ForeignKey(Shop,on_delete=models.CASCADE)
shop_inventory = models.FileField(upload_to='inventory/')
serializers.py
class InventoryFile_Serializer(serializers.ModelSerializer):
class Meta:
model = InventoryFile
fields = ('shop_inventory',)
views.py
class InvertoryUpload(APIView):
serializer_class = InventoryFile_Serializer
parser_classes = [ MultiPartParser,FormParser ]
def post(self,request):
try:
serializer = InventoryFile_Serializer(data=request.data)
print(serializer.initial_data)
if serializer.is_valid():
print(serializer.data)
return Response("Done")
else:
print(serializer.errors)
return Response("Not Done")
except Exception as e:
return Response(str(e))
Output
System check identified no issues (0 silenced).
January 30, 2019 - 11:22:06
Django version 2.1, using settings 'hoplet.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
<QueryDict: {'inventory': [<InMemoryUploadedFile: MOCK_DATA_2.csv (application/vnd.ms-excel)>]}>
{'shop_inventory': [ErrorDetail(string='No file was submitted.', code='required')]}
[30/Jan/2019 11:22:18] "POST /uploadinv HTTP/1.1" 200 10
The key name of the file in request is inventory and the key name that the serializer is looking for is shop_inventory. They should be the same. Change one of them and it should work.
Please try in this way
urls.py
urlpatterns = [
url(r'^', include(router.urls)),
url(r'^upload_file', InvertoryUpload.as_view())
]
models.py
class InventoryFile(models.Model):
shop = models.ForeignKey(Shop,on_delete=models.CASCADE)
shop_inventory = models.FileField(upload_to='inventory/')
views.py
from rest_framework.parsers import MultiPartParser, FormParser
from rest_framework.generics import CreateAPIView
class InvertoryUpload(CreateAPIView):
serializer_class = InventoryFile_Serializer
parser_classes = [ MultiPartParser, FormParser ]
serializers.py
class InventoryFile_Serializer(serializers.ModelSerializer):
class Meta:
model = InventoryFile
fields = ('shop_inventory','shop')

Sending tags via HTTP Post to Django web api endpoint

I am trying to send tags to my web application, using Django Rest Framework and Django Taggit. I tried to adapt the approach from here, but no luck so far. Here is my try:
models.py:
class Tool(models.Model):
name = models.CharField(max_length=100)
tags = TaggableManager(blank=True)
created = models.DateTimeField(auto_now_add=True)
def get_tags_display(self):
return self.tags.names()
serializers.py:
class ToolSerializer(TaggitSerializer, serializers.ModelSerializer):
name = serializers.CharField(max_length=100)
tags = serializers.Field(source='get_tags_display')
class Meta:
model = Tool
fields = ('tool_id', 'name', 'tags')
views.py:
class ToolList(generics.ListCreateAPIView):
queryset = Tool.objects.all()
serializer_class = ToolSerializer
def perform_create(self, serializer):
if 'tags' in self.request.data:
self.objects.add(*self.request.data['tags'])
return super(ToolList, self).perform_create(self, serializer)
using httpie:
http --form POST http://127.0.0.1:8000/tools/ name="Hammer" tags:='["new", "heavy"]'
Am I going in the right direction?

Django rest framework generic view for multiple models

Is there a way of creating a generic view to be used by several different models? I have many models in my project and do not want to have to create a view and serializer for each of them.
Assume this is a simple solution but I have spent hours googling with no results.
Within the Django REST framework API guide Generic views Examples the following code snippet is shown:
url(r'^/users/', ListCreateAPIView.as_view(model=User), name='user-list')
Which suggests this is possible but the example does not seem to be complete (or my understanding is not complete).
This is my attempt:
url.py
url(r'^foomodel/', views.GenericViewSet.as_view(model = Foomodel) ),
views.py
class GenericViewSet(generics.ListAPIView):
model = User # this is over ridden by the url
queryset = model.objects.all()
serializer_class = BaseSerializer
ordering_fields = '__all__'
serializers.py
class BaseSerializer(serializers.ModelSerializer):
class Meta:
model = None
And of cause this fails as the serializer does not like model = None or any variation that I can think of.
Any suggestions as to how this should be addressed?
A solution would be overriding the get_serializer_class method of the ViewSet.
The model field in the view will be fine as you override it in the url, as you said, what I would do is build the serializer class on the fly.
class GenericViewSet(generics.ListAPIView):
queryset = model.objects.all()
def get_serializer_class(self):
class BaseSerializer(serializer.ModelSerializer):
class Meta:
model = self.model
return BaseSerializer
Hope this helps!
To recap the intention is to create a reusable view that can be used for many models without having to repeat a heap of code. This leaves very little code in Django to create a backed API for many Django models. I am using this for ember.js
urls.py
from myapp import models as mymodels
url(r'^cs/(?P<strmodel>[A-Za-z]+)/(?P<id>[0-9]+)/', views.GenericViewSet.as_view({'get': 'retrieve', 'post':'update', 'delete':'destroy' }, application = mymodels ) ),
url(r'^cs/(?P<strmodel>[A-Za-z]+)/', views.GenericViewSet.as_view({'get': 'list','post': 'create' }, application = mymodels ) ),
Worth noting that I have several apps and there is a different set of URL's to access them. The model being accessed is passed as strmodel
views.py
class GenericViewSet(viewsets.ModelViewSet):
def __init__(self, application):
self.application = application
def initialize_request(self, request, *args, **kwargs):
self.model = getattr(self.application, self.kwargs['strmodel'] )
request = super(viewsets.ModelViewSet, self).initialize_request(request, *args, **kwargs)
return request
strmodel = None
application = None
model = User
lookup_field = 'id'
def get_queryset(self):
return self.model.objects.all()
def get_serializer_class(self):
class BaseSerializer(serializers.ModelSerializer):
class Meta:
model = self.model
return BaseSerializer
Hope this helps :)

Django 1.3 CreateView, ModelForm and filtering fields by request.user

I am trying to filter a field on a ModelForm. I am subclassing the generic CreateView for my view. I found many references to my problem on the web, but the solutions do not seem to work (for me at least) with Django 1.3's class-based views.
Here are my models:
#models.py
class Subscriber(models.Model):
user = models.ForeignKey(User)
subscriber_list = models.ManyToManyField('SubscriberList')
....
class SubscriberList(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=70)
....
Here is my view:
#views.py
class SubscriberCreateView(AuthCreateView):
model = Subscriber
template_name = "forms/app.html"
form_class = SubscriberForm
success_url = "/app/subscribers/"
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.user = self.request.user
return super(SubscriberCreateView, self).form_valid(form)
Here is my original form for adding a Subscriber, with no filter:
#forms.py
class SubscriberForm(ModelForm):
class Meta:
model = Subscriber
exclude = ('user', 'facebook_id', 'twitter_id')
Here is my modified form, attempting to filter, but doesn't work:
#forms.py
class SubscriberForm(ModelForm):
class Meta:
model = Subscriber
exclude = ('user', 'facebook_id', 'twitter_id')
def __init__(self, user, **kwargs):
super(SubscriberForm, self).__init__(**kwargs)
self.fields['subscriber_list'].queryset = SubscriberList.objects.filter(user=user)
If I change this modified form as so:
def __init__(self, user=None, **kwargs)
It works - It brings me NO subscriber lists. But any way I try to pass the request user, I invariably get a a name "request" or name "self" not defined error.
So, how can I modify my code to filter subscriber_list by the request.user, and still use Django 1.3's CreateView.
I see you've been posting this question in various places.. and the way I found that is because I was trying to figure out the same thing. I think I just got it working, and here's what I did. I overwrote get_form() from FormMixin to filter a specific form fields queryset:
class MyCreateView(CreateView):
def get_form(self, form_class):
form = super(MyCreateView,self).get_form(form_class) #instantiate using parent
form.fields['my_list'].queryset = MyObject.objects.filter(user=self.request.user)
return form

Resources