I'm using
Django: 2.0
Djanfo REST Frameword: 3.8.2
drf-nested-routers: 0.90.2
My contacts/views.py
class ContactViewSet(viewsets.ModelViewSet):
serializer_class = ContactSerializer
permission_classes = (IsAuthenticated,)
def get_queryset(self):
return Contact.objects.filter(user=self.request.user)
class ContactPhoneNumberViewSet(viewsets.ModelViewSet):
serializer_class = ContactPhoneNumberSerializer
permission_classes = (IsAuthenticated,)
def get_queryset(self):
print(self.kwargs)
phone_numbers = ContactPhoneNumber.objects.all()
return phone_numbers
and app/urls.py
from rest_framework_nested import routers
from contacts.views import ContactViewSet, ContactPhoneNumberViewSet
router = routers.SimpleRouter()
router.register(r'contacts', ContactViewSet, 'contacts')
contact_router = routers.NestedSimpleRouter(router, r'contacts', lookup='contact')
contact_router.register(r'phone_number', ContactPhoneNumberViewSet, base_name='contact-phone-numbers')
api_urlpatterns = [
path('', include(router.urls)),
]
urlpatterns = [
path('api/', include(api_urlpatterns)),
url(r'^admin/', admin.site.urls),
]
using this setup, I'm able to access
/api/contacts/ # <= list all contacts
/api/contacts/<pk>/ # <= contact detail
But on trying to access
/api/contacts/<pk>/phone_number/ # <= list all phone numbers
It is giving Page Not Found error.
I also tried passing <phone_number_pk> but still Page not Found error is received.
api_urlpatterns = [
path('', include(router.urls)),
path('', include(contact_router.urls)),
]
you also need to register nested urls separately
Related
i am getting this error, which was not there previously , having trouble to rectify help needed in this
class MeterSerializer(serializers.HyperlinkedModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name="meter_reading:meters-list")
customer_reports = CustomerReportSerializer(source='customerreport_set', many=True,read_only=True)
class Meta:
model = Meter
fields = ['number','customer_reports','customer','url']
class CustomerReportSerializer(serializers.ModelSerializer):
meter_no = serializers.SerializerMethodField(method_name='meter_num')
customer_name = serializers.SerializerMethodField(method_name='cust_name')
customer_number = serializers.SerializerMethodField(method_name='cust_number')
class Meta:
model = CustomerReport
fields = ('meter_no','meter','customer_name','date','customer_unit','unit_rate','bill_amount','consumer_number','customer_number','pending_units',)
routers.py
router.register('customer', CustomerViewSet)
router.register('meters',MeterViewSet,basename='meters')
router.register('issues',IssueViewSet)
router.register('customereport',CustomerReportViewSet,basename='customerreport')
# router.register('users',UserViewset)
urlpatterns = router.urls
urls.py
urlpatterns = [
path('', include(router.urls)),
path('api-auth/', include('rest_framework.urls', namespace='rest_framework')),
path('meter_access/', MeterAccess.as_view(),name='meter_access'),
]
I am newbie in Django. So this might be a trivial question.
I have been been building urlpatterns as following
router = DefaultRouter()
router.register('posts', views.PostViewSet)
urlpatterns = [
path('', include(router.urls))
]
This creates URLs like api/posts and so on.
Now, I am trying to add a voting model to this.. For which I want to create URL like
api/posts/<id>/vote
But I don't want to create a path like
urlpatterns = [
path('', include(router.urls)),
path('posts/<int:pk>/vote', views.SomeView)
]
Is there a way to do this via router.register way?
First You will define default router same way as you defined.
router = DefaultRouter()
router.register('posts', views.PostViewSet, basename='posts')
urlpatterns = [
path('', include(router.urls))
]
Then define Serializer class as you needed.
from rest_framework import serializers
from .models import Post
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = '__all__'
Now define the custom method of vote inside PostViewSet with Allowed HTTP methods.
from rest_framework.response import Response
from rest_framework import viewsets, status
from rest_framework.decorators import action
from .models import Post
from .serializers import PostSerializer
class PostViewSet(viewsets.ModelViewSet):
queryset = Post.objects.all()
serializer_class = PostSerializer
#action(detail=True, methods=['Get'])
def vote(self, request, pk=None):
queryset = Post.objects.filter(pk=pk)
serializer = PostSerializer(queryset, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
Now you will be able to access the vote with your desired URL as api/posts/<pk>/vote
I want to get a model instance using URL as http://127.0.0.1:8000/db/User/email (i.e. using email as a query) and not by http://127.0.0.1:8000/db/User/1/. How to approach this.
Model:
class Employee(models.Model):
firstname = models.CharField(max_length=100)
email = models.CharField(max_length=100)
serializers.py
class EmployeeSerializers(serializers.ModelSerializer):
field = NestedSerializers()
class Meta:
model = Employee
fields = '__all__'
def create(self, validated_data):
#overwrite this method for writable nested serializers.
view.py:
class UserView(viewsets.ModelViewSet):
queryset = Employee.objects.all()
serializer_class = EmployeeSerializers
urls.py:
router = routers.DefaultRouter()
router.register('User', views.UserView)
urlpatterns = [
path('', views.index, name='index'),
path('/', include(router.urls))
]
Is it possible to do using ModelViewSet?
I see you are using DRF viewset. If you only ever want to use the email and not the id then you can override the the retrieve function of the viewset like so:
from django.shortcuts import get_object_or_404
class UserView(viewsets.ModelViewSet):
queryset = Employee.objects.all()
serializer_class = EmployeeSerializers
def retrieve(self, request):
employee = get_object_or_404(
self.queryset,
email=self.kwargs['email']
)
serializer = self.serializer_class(employee)
return Response(serializer.data)
urls
router = routers.DefaultRouter()
router.register('^User/(?P<email>.+)/$', views.UserView)
urlpatterns = [
path('', views.index, name='index'),
path('/', include(router.urls))
]
retrieve is functionality already provided in the viewset class
I would like to get the details of my submodules on a route with multiple parameters.
My existing routes right now are:
http://localhost:8000/api/module/ - Gets all modules
http://localhost:8000/api/module/1/ - Gets all modules and connected submodules
I would like to do http://localhost:8000/api/module/1/submodules/1 which will get the details of the submodules. How should i do this using class based views?
Below is my existing code:
Views.py
class CourseModuleViewSet(viewsets.ModelViewSet):
queryset = CourseModule.objects.all()
serializer_class = CourseModuleSerializer
def retrieve(self, request, pk=None):
coursemodule = CourseModule.objects.get(id=pk)
submodule = SubModule.objects.filter(submodule_module_id=pk)
serializer = SubModuleSerializer(submodule, many=True)
response = {'message': 'Sucess!',
'result': serializer.data}
return Response(serializer.data, status=status.HTTP_200_OK)
Serializers.py
class CourseModuleSerializer(serializers.ModelSerializer):
class Meta:
model = CourseModule
fields = ['class_id', 'coursemodule_title', 'coursemodule_date_created',
'coursemodule_last_modified', 'coursemodule_created_by']
class SubModuleSerializer(serializers.ModelSerializer):
submodule_module_id = CourseModuleSerializer(many=False)
class Meta:
model = SubModule
fields = ['submodule_module_id','submodule_title', 'submodule_date_created', 'submodule_last_modified',
'submodule_created_by']
urls.py
router = routers.DefaultRouter()
router.register('module', CourseModuleViewSet)
urlpatterns = [
path('', include(router.urls)),
]
You could use drf-nested-routers.
You would need to include an extra NestedRouter in you urls.py like this:
router = routers.DefaultRouter()
router.register(r'module', CourseModuleViewSet)
sub_modules_router = routers.NestedSimpleRouter(router, r'module', lookup='module')
sub_modules_router.register(r'submodules', SubModuleViewSet, base_name='module-submodules')
urlpatterns = patterns('',
url(r'^', include(router.urls)),
url(r'^', include(sub_modules_router.urls)),
)
And then you can create a SubModuleViewSet like this:
class SubModuleViewSet(viewsets.ModelViewSet):
def get_queryset(self):
return SubModule(submodule_module_id =self.kwargs['module_pk'])
serializer_class = SubModuleSerializer
i have a website with django.
this is the project urls.py:
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^', include('accounts.urls')),
url(r'^login/$', LoginView.as_view(), name='login'),
url(r'^register/$', RegisterView.as_view(), name='register'),
url(r'^logout/$', logout_view, name="logout")
]
and this is the accounts.urls:
from . import views
urlpatterns = [
url(r'(?P<username>[\w]+)/$', views.Profile.as_view(), name='profile_cbv'),
]
and this is Profile model:
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, related_name='profile', verbose_name='user', on_delete=models.CASCADE)
name = models.CharField(max_length=30, verbose_name='name')
family = models.CharField(max_length=50, verbose_name='family')
and at last, this is the Profile class-based view:
class Profile(View):
def get(self, request, username=None):
profile = get_object_or_404(Profile, user__username=username)
print(profile)
pass
for example, i go to below url:
localhost:8000/ivan/
it raises below error:
AttributeError at /ivan/
type object 'Profile' has no attribute 'model'
if I pass a correct or an incorrect username with url to view, all the times, it raises that error.
what's the problem?
When you call get_object_or_404(Profile, ...), it takes Profile not as your model, but as your view. That's why you receive that error.
Try renaming class Profile(View) to class ProfileView(View):
from . import views
urlpatterns = [
url(r'(?P<username>[\w]+)/$', views.ProfileView.as_view(), name='profile_cbv'),
]
And in your views.py:
class ProfileView(View):
def get(self, request, username=None):
profile = get_object_or_404(Profile, user__username=username)
print(profile)
pass
It looks like a name issue in the views. Your view class name is the same as the model class. Import the Model class as something else. For example:
from .models import Profile as ProfileModel
Then call the model that way in the view.