Django rest framework. Setting up dynamic routes - python-3.x

I am setting up an API for a blog. I configured the output of comments for the post
Here is a portion of my views.py with #action:
urls.py
router = DefaultRouter()
router.register('api/posts', APIPost)
urlpatterns = [
path('', include(router.urls)),
]
views.py
...
#action(methods=['get'], detail=True)
def comments(self, request, pk=None):
if request.method == 'GET':
queryset = Comment.objects.filter(post__id=pk)
serializer = CommentSerializer(queryset, many=True)
return Response(serializer.data)
return Response(status=status.HTTP_403_FORBIDDEN)
Now I can get all comments on a post at.
http://127.0.0.1:8000/api/posts/{post_pk}/comments/
The problem is that I just can't figure out how to get a separate comment at
http://127.0.0.1:8000/api/posts/{post_pk}/comments/{comment_pk}
I keep getting '404 Not Found' error

You should create another CommentViewSet. (docs)
views.py
from rest_framework import viewsets
class CommentViewSet(viewsets.ModelViewSet):
queryset = Comment.objects.all()
serializer_class = CommentSerializer
urls.py
from .views import CommentViewSet
router = DefaultRouter()
router.register("api/posts", APIPost)
router.register("api/comments", CommentViewSet)
urlpatterns = [
path('', include(router.urls)),
]
and then you can retrieve by making a request to http://127.0.0.1:8000/api/comments/{pk}.
also, in your code,
#action(methods=['get'], detail=True) it should be #action(methods=['get'], detail=False) instead because the comments action is to retrieve list of all comments. detail=True is for returning a single object.
You don't need to manually check for the if request.method == 'GET' as DRF is already doing that internally because you already specified methods=["get"].

You should define URL Path or Route to a certain Address for the comments to load .
Like you defined the APIPost model ...comment url route should be like below
router.register(r"comments", comments)

Related

DRF's not calling post() method when receiving POST request

I have a viewset like this:
class MyViewSet(CreateAPIView, RetrieveModelMixin, ListModelMixin, GenericViewSet):
queryset = MyModel.objects.all()
serializer_class = MySerializer
def post(self, request, *args, **kwargs):
import pdb; pdb.set_trace()
class MySerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = MyModel
fields = ['id', 'field1', 'field2'] #only field1 is required in the model
The GET requests for list, and retrieve works perfectly. When I make a POST request, sending the field1 I get a status 201 and a new record is added to the database, so it works too.
But my method MyViewSet.post() that should overwrite the same one from generics.CreateAPIView never gets called.
Not only that, but I've tried to add the pdb.set_trace(), literally inside the generics.CreateAPIView.post() and in the CreateModelMixin.create() functions and neither stopped once I made the POST request.
So something else is handling this POST request and inserting into the DB, I just don't know what. And how can I overwrite it, so I can customize what should be done with a post request?
PS.: Also, I don't think it's a routing problem, my urls.py:
from rest_framework import routers
from myapp.views import MyViewSet, AnotherViewSet
router = routers.DefaultRouter()
router.register(r'route_one', MyViewSet)
router.register(r'route_two', AnotherViewSet)
I think you need to use the exact class in order to use POST api.
class MyView(CreateModelMixin, ListModelMixin, generics.GenericAPIView):
queryset = MyModel.objects.all()
serializer_class = MySerializer
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
In urls.py
from django.urls import path
from .views import MyView
urlpatterns = [
path('route_one', MyView.as_view(), name="my_view_detail")
]

NoReverseMatch at / 'learning_logs' is not a registered namespace

I think i tired everything in trying to solve this problem.
I'm getting a NoReverseMatch i understand its from my "urls" but that's basically it, I was using url() instead of path().at the end of it all i just made a mess of my code.
view.py
from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.urls import reverse
from .models import Topic as TopicModel
from .forms import TopicForms
# Create your views here.
def index(request):
""""the home page for learning app"""
return render(request,'learning_logs/index.html')
def topics(request):
topics = TopicModel.objects.order_by('date_added')
context = {'topics' : topics}
return render(request, 'learning_logs/topics.html',context)
def topic(request, topic_id):
"""show a single topic ans all its entries"""
topic = TopicModel.objects.get(id=topic_id)
entries = topic.entry_set.order_by('date_added')
context = {'topic':topic, 'entries': entries}
return render(request,'learning_logs/topic.html',context)
def new_topic(request):
"""add a new topic"""
if request.method != 'POST':
#no data submitted ; create a black form
form = TopicForms
else:
#POST data submited ; process data
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('learning_log:topics'))
context = {'form': form }
return render(request,'learning_log/new_topic.html', context)
urls.py
#defins URL patterns for learning log
from django.conf.urls import url
from . import views
from django.urls import path
app_name = 'learning_log'
urlpatterns = [
#home page
path('', views.index, name ='index'),
#url(r'^$', views.index, name='index.html'),
#show topics
path('topics/',views.topics, name ='topics'),
# url(r'^topics/$',views.topics, name='topics.html'),
path('topics/<topic_id>',views.topic, name = 'topic'),
#url(r'^topics/(?P<topic_id>\d+)\$',views.topic,name='topic.html'),
path('topics/',views.new_topic, name = 'new_topic'),
#url(r'^topics/$',views.new_topic, name='new_topic.html'),
]
main urls.py
from django.contrib import admin
from django.conf.urls import include, url
from django.urls import path, include
urlpatterns = [
path('', include('learning_logs.urls')),
path('admin/',admin.site.urls),
]
please anything I'm doing wrong plus any books or tutorials i can read because i think the book im using is outdated
Your app_name inside the urls file is "learning_log" but it seems your html folders are in learning_logs. Maybe something to do with that? Also can you make sure the app_name exists in your INSTALLED_APPS?
I've done a Udemy course for Django which was good for me but they are not free if you want to learn more.
just add the include param called namespace in your main urls.py for the app.
from django.contrib import admin
from django.conf.urls import include, url
from django.urls import path, include
urlpatterns = [
path('', include('learning_logs.urls', namespace="learning_log")),
path('admin/',admin.site.urls),
]
here you have the documentation of URLs namespaces: https://docs.djangoproject.com/en/3.2/topics/http/urls/#url-namespaces
If you don't want to set the namespace you must call the url like this: reverse('topics')

django.urls.exceptions.NoReverseMatch: Reverse for 'home' not found. 'home' is not a valid view function or pattern name

I have a problem where my url is seen as an invalid url. None of my URLS are working for my Django Application. I have made the mistake of using the same secret key that I used for another application. Here is a picture of my error message, url page, and my views.
Error Message
urls.py
views.py
from django.shortcuts import render
from home.models import Products
#This is the store view
def home(request):
return render(request,'home.html')
#This is the About Us page view
def AboutUs(request):
return render(request,'AboutUs.html')
#This is the Long Arm Services View
def LongArmServices(request):
return render(request,'LongArmServices.html')
#This is the product View
def product(request):
return render(request,'product.html')
urls.py:
from django.urls import path
from . import views
from django.http import HttpResponse
app_name='home'
urlpatterns = [
path('',views.home,name='home'),
path('about_us/',views.AboutUs,name='AboutUs'), path('long_arm_services/',views.LongArmServices,name='LongArmServices'),
path('product/',views.product,name='product'),
]
Your urls.py specify an app_name = 'home', so that means you need to prefix the name of the view with the app_name and a colon (:). So you should rewrite the marked part in the template to:
href="{% url 'home:home' %}"

DRF Newbie - Stuck in small mistake kindly assist

I created 1 API its all working fine from all ends.
I created 2nd API the DRF headings title showing the headings of old api where i am doing mistake kindly assist.
serializers.py
from rest_framework import serializers
from .models import Brand, Category
class BrandSerializer(serializers.ModelSerializer):
class Meta:
model = Brand
fields = (
'id',
'name',
'slug',
'icon',
'featured_image',
'url'
)
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = (
'id',
'name',
'slug',
'featured_image',
)
products.url
router = routers.DefaultRouter()
router.register(r'', BrandViewSet)
router.register(r'', CategoryViewSet)
urlpatterns = [
path('', include(router.urls)),
]
product.view
class CategoryViewSet(viewsets.GenericViewSet, mixins.RetrieveModelMixin, mixins.ListModelMixin):
"""
API endpoint that allows sites to be viewed or edited
"""
queryset = Category.objects.all()
serializer_class = CategorySerializer
There is no error but in brower when i run the API url it shows brand list instead of category list,
The problem is that you have the views registered to the same endpoint. So it resolves the first one it finds.
So do the register to different endpoints like this:
router = routers.DefaultRouter()
router.register(r'brands', BrandViewSet)
router.register(r'categories', CategoryViewSet)
urlpatterns = [
path('', include(router.urls)),
]
So you can access brands via 127.0.0.1:8000/brands and categories via 127.0.0.1:8000/categories

How can I list all the nodes in my database?

I'm trying to create a simple model Node and a simple web page that shows all of my nodes in a list. But it seems not working and everytime I change the code I got a new error. So I gave up and came to here.This is what I did:
I created a Node model:
class Node(models.Model):
ID = models.DecimalField(max_digits=9, decimal_places=6)
nb_solenoid = models.DecimalField(max_digits=9, decimal_places=6, null=True, blank=True)
connexion = models.CharField(max_length=255)
def get_absolute_url(self):
return reverse("node:index", kwargs={"id": self.id})
with this form:
class NodeForm(forms.ModelForm):
ID = forms.DecimalField(initial=0)
nb_solenoid = forms.DecimalField(initial=1)
connexion = forms.CharField(required=False,
widget=forms.Textarea(
attrs={
"placeholder": "type of connexion"
}))
class Meta:
model = Node
fields = [
'ID',
'nb_solenoid',
'connexion'
]
And this is my views.py:
def index(request):
queryset = Node.objects.all()
context = {
"object_list": queryset
}
return render(request, "node/index.html", context)
This is my code in urls.py:
urlpatterns = [path('', views.index, name='index')]
When I call this url: http://localhost:8000/node I get this error now:
NoReverseMatch at /node
Reverse for 'index' with keyword arguments '{'id': 1}' not found. 1 pattern(s) tried: ['node$']
What is a NoReverseMatch error and how do I fix my problem? Let me say that I'm a Django beginner developer.
Thank you.
The issue is that your named url path node:index takes no arguments (presumably because that view is just listing out all the nodes, not a specific node), yet your model's get_absolute_url is trying to reverse the pattern with a kwarg of id. The core problem is your get_absolute_url method; however, you really probably also would benefit from just using class based generic views:
urls.py:
urlpatterns = [
path('nodes/', NodeList.as_view(), name="node-list"),
path('node/<id>/', NodeDetail.as_view(), name="node-detail")
]
view.py:
from django.views.generic import ListView, DetailView
from .models import Node
class NodeList(ListView):
model = Node
class NodeDetail(DetailView):
model = Node
models.py:
class Node(models.Model):
<snip>
def get_absolute_url(self):
return reverse("node-detail", kwargs={"id": self.id})
I really should have mentioned, documentation for class based generic views are at: https://docs.djangoproject.com/en/2.1/topics/class-based-views/generic-display/

Resources