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'),
]
Related
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 want to use slug as my pk by using lookup_field.
The error I have is "Could not resolve URL for hyperlinked relationship using view name "service-detail".
I figured that if I use generic view(ListAPIView or RetrieveAPIView), it'll work because in urls I can set up a simple route like path('services/slug/').
But I would like to know if there is a way of doing this with Viewsets. Which means how can I set up the urls (Default Router instead of Simple Router) to handle this?
serializers.py
class ServiceSerializer(serializers.HyperlinkedModelSerializer):
title = serializers.CharField(required=True)
slug = serializers.SerializerMethodField(read_only=True)
description = serializers.CharField(required=False)
price = serializers.IntegerField(required=True)
service_image = ServiceImageSerializer(many=True)
class Meta:
model = Service
fields = ('url', 'slug', 'title', 'description', 'price', 'service_image')
lookup_field = 'slug'
extra_kwargs = {
'url': {'lookup_field':'slug'}
}
def get_slug(self, instance):
return slugify(instance.vendor.username + "-" + instance.title)
views.py
class ServiceViewSet(viewsets.ModelViewSet):
queryset = Service.objects.all()
serializer_class = ServiceSerializer
lookup_field = 'slug'
urls.py
router = routers.DefaultRouter()
router.register('categories', CategoryViewSet)
router.register('services', ServiceViewSet)
router.register('images', ServiceImageViewSet)
urlpatterns = [
path('', include(router.urls)),
]
I decided to not use Viewsets anymore and using this instead:
views.py
class ServiceListAPIView(ListCreateAPIView):
queryset = Service.objects.all()
serializer_class = ServiceSerializer
class ServiceDetailAPIView(RetrieveUpdateDestroyAPIView):
queryset = Service.objects.all()
serializer_class = ServiceSerializer
lookup_field = 'slug'
urls.py
urlpatterns = [
path('', include(router.urls)),
path('services/', ServiceListAPIView.as_view(), name='service-list'),
path('services/<slug>/', ServiceDetailAPIView.as_view(), name='service-detail'),
]
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'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
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.