Django error: 404 Page not found on get method - python

I am trying to get serialized data from endpoint localhost:8000/v1/test/uuid, but hitting a 404 error - what is wrong with below?
views.py
from uuid in response, get site object
class Test(APIView):
def get(self, request, *args, **kwargs):
uuid = kwargs.get('uuid')
resp = {'site': None}
site = Site.objects.get(uuid=uuid)
resp['site'] = SiteSerializer(site).data
return Response(resp)
urls.py
from django.conf.urls import re_path
from rest_framework.routers import DefaultRouter
from site_config import views
router = DefaultRouter()
router.register(
r'site',
views.SiteViewSet,
basename='site')
urlpatterns = [
re_path(r'^v1/', include(router.urls)),
re_path('test/<uuid:uuid>/', views.Test.as_view(), name='test'),
]
models.py
site id as the pk
class Site(models.Model):
"""
Model that represents a Site
"""
uuid = models.UUIDField(
default=uuid.uuid4,
editable=False,
unique=True)
domain_name = models.CharField(max_length=255, unique=True)
created = models.DateTimeField(editable=False, auto_now_add=True)
modified = models.DateTimeField(editable=False, auto_now=True)
serializers.py
class SiteSerializer(serializers.ModelSerializer):
class Meta:
model = Site
fields = [
'uuid',
'domain_name'
]
FYI - the endpoint was working when the views.py was returning all Sites, but it isn't working when I try to filter on uuid.
views.py (previously working version)
class Test(APIView):
def get(self, request, *args, **kwargs):
resp = {'site': None}
site = Site.objects.all()
resp['site'] = SiteSerializer(site, many=True).data
return Response(resp)
Error Message on Browser:
Page not found (404)
Request Method: GET
Request URL: http://localhost:8000/v1/test/7c018183-c952-4040-a450-e3cb58f09745/
Using the URLconf defined in site_config.urls, Django tried these URL patterns, in this order:
^v1/ ^site/$ [name='site-list']
^v1/ ^site\.(?P<format>[a-z0-9]+)/?$ [name='site-list']
^v1/ ^site/(?P<uuid>[^/.]+)/$ [name='site-detail']
^v1/ ^site/(?P<uuid>[^/.]+)\.(?P<format>[a-z0-9]+)/?$ [name='site-detail']
^v1/ ^$ [name='api-root']
^v1/ ^\.(?P<format>[a-z0-9]+)/?$ [name='api-root']
test/<uuid:uuid> [name='test']

urls.py
As this is a routing problem the first place to have a look should be the urls.py.
Without recreating the app it looks like there are potentially three problems there:
Analysis
1. re_path
re_path is used, a regular Django path expression is provided. The django.urls documentation has some examples that speak for themselves.
2. the path itselt
The URL path starts with v1/ while the provided configuration starts with test/.
3. the order
As the re_path for ^v1/ matches anything beginning with v1/ the order in the pattern is important.
Anything that should available in that path must either be listed before the regex match, or be registered in the router.
Fix
urlpatterns = [
path('v1/test/<uuid:uuid>/', views.Test.as_view(), name='test'),
re_path(r'^v1/', include(router.urls)),
]

FYI - the endpoint was working when the views.py was returning all
Sites, but it isn't working when I try to filter on uuid.
As I do not have the breakpoint analysis for your views.py code I assume that your get method inside
class Test(APIView):
def get(self, request, *args, **kwargs):
uuid = kwargs.get('uuid')
resp = {'site': None}
site = Site.objects.get(uuid=uuid)
resp['site'] = SiteSerializer(site).data
return Response(resp)
is not getting resolved by the patterns in your urls.py or the uuid is not getting through.
If the case is former here what you can do is a direct mapping of the UUID inside the get method and avoiding the kwarg.get() by doing this
class Test(APIView):
def get(self, request, uuid, *args, **kwargs):
uuid = uuid
resp = {'site': None}
site = Site.objects.get(uuid=uuid)
resp['site'] = SiteSerializer(site).data
return Response(resp)

Related

Django Rest Framework: How to include application namespace when defining HyperlinkedRelatedField

My django application has a namespace defined in the app_name variable, in urls.py.
It seems like this namespace needs to be specified in the view_name argument of HyperlinkedRelatedField for HyperlinkedRelatedField to successfuly retrieve the relevant url router.
To avoid repeating this namespace, I'd like to import the namespace into the serializers module. However I get an import error when doing so.
extract from my app/urls.py:
...
app_name = 'viewer'
...
api_router = DefaultRouter()
api_router.register('year', api_views.YearViewSet, 'api_year')
api_router.register('month', api_views.MonthViewSet, 'api_month')
...
urlpatterns = [
...
path('api/', include(api_router.urls)),
]
api_views.py
...
class YearViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericViewSet):
queryset = Year.objects.all().order_by('-date')
serializer_class = YearSummarySerializer
lookup_field = 'slug'
def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
serializer = YearDetailSerializer(instance=instance)
return Response(serializer.data)
#action(detail=True)
def months(self, request, *args, **kwargs):
serializer = YearMonthsSerializer(instance=self.get_object(), context={'request': request})
return Response(serializer.data)
...
serializers.py
...
from .urls import app_name
...
class YearMonthsSerializer(serializers.HyperlinkedModelSerializer):
month_set = serializers.HyperlinkedRelatedField(
many=True,
read_only=True,
view_name= app_name + ':api_month-detail',
lookup_field='slug'
)
class Meta:
model = Year
fields = ['month_set']
...
When I manually enter the app_name ('viewer') the serializer works as intended, however when I try to import app_name from .urls, python throws an ImportError
ImportError: cannot import name 'app_name' from 'cbg_weather_viewer.viewer.urls'
I don't understand why I get this import error as I already use relative imports models, views, etc. successfully.
I don't understand what I am doing wrong. What should I do instead?
Edit
I understand that I cannot include url as it will create a circular reference.
After doing some research, it seems that the request contains the app_name value as documented here: https://docs.djangoproject.com/en/2.2/ref/urlresolvers/#django.urls.ResolverMatch
However, I don't know how to access the request directly in the YearMonthSerializer class. I could retrieve it using self.request in a class method, but not directly from the class itself. Any suggestion?
Temporary solution
I have deported the app namespace to the apps.py module and imported it both urls.py and serializers.py as follow:
apps.py
app_namespace = 'viewer' # Used in urls
urls.py
from .apps import app_namespace
app_name = app_namespace
serializers.py
from .apps import app_namespace
def get_view_name(view_name):
return f'{app_namespace}:{view_name}'
...
month_set = serializers.HyperlinkedRelatedField(
many=True,
read_only=True,
view_name= get_view_name('api_month-detail'),
lookup_field='slug'
)
put namespace in the path when you include URLs like this
without namespace don't retrieve app_name
try this
urlpatterns = [
...
path('api/', include(api_router.urls,namespace="viewer")),
]
The documentation of the restframework states following, which worked for me:
You may use include with an application namespace:
urlpatterns = [
path('forgot-password/', ForgotPasswordFormView.as_view()),
path('api/', include((router.urls, 'app_name'))),
]
Or both an application and instance namespace:
urlpatterns = [
path('forgot-password/', ForgotPasswordFormView.as_view()),
path('api/', include((router.urls, 'app_name'), namespace='instance_name')),
]
See Django's URL namespaces docs and the include API reference for
more details.
Pay attention to the double parenthese with the include statement in the first example:
include((router.urls, 'app_name'))

TypeError: delete() missing 1 required positional argument: 'pk' django

i have a view in my django app which looks like following
class DeployedContractsList(APIView):
def get_Contract(self, address):
contracts = DeployedContracts.objects.all()
if address:
contracts = contracts.filter(
Q(deployed_contract_address__iexact=address)
)
return contracts
def get(self, request, email, format=None):
service_providers = self.get_queryset(email)
serializer = DeployedContractsSerializer(service_providers, many=True)
return Response(data=serializer.data)
def delete(self, request, pk, format=None):
item = self.get_Contract(address=pk)
item.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
and i have configured my app urls in following way
router = DefaultRouter()
urlpatterns = [
url(r'^(?P<email>[\w.%+-]+#[A-Za-z0-9.-]+\.[A-Za-z]{2,4})/$', views.DeployedContractsList.as_view()),
url(r'^(?P<pk>)/$', views.DeployedContractsList.as_view()),
url(r'^', views.DeployedContractsList.as_view())
]
and project's urls.py i have following configurations
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^deployedcontracts', include('deployedcontracts.urls')),
]
but upon making a delete request by http://127.0.0.1:8000/deployedcontracts/0xe9114368611e9f20cf46b76aa33319fc0ce0b585/ i am getting following error
despite the fact i have attached pk in request url i.e 0xe9114368611e9f20cf46b76aa33319fc0ce0b585 as it can be seen in my url. Any help is appreciated.
You forgot to add regular expression to url patern:
url(r'^(?P<pk>[\w-]+)/$', views.DeployedContractsList.as_view()),

Adding/Removing url patterns from django during runtime

For example I have a url in my urls.py-
url(r'^my-url/$', views.my_view)
Now on a particular action from views, I want to remove this url from urlpatterns and add a new url during runtime. Is it possible, if so, how?
Changing url handler during runtime is not best practice instead you could have the checkpoint in db and handle all the incoming request
models.py
class Version(models.Model):
version_number = models.IntegerField()
is_latest = models.BooleanField(default=False)
urls.py
url(r'^handler/(?P<version>\d+)/$', views.handler)
views.py
from django.shortcuts import get_object_or_404
def handler(request, version):
obj = get_object_or_404(Version, version_number=4)
if obj.is_latest:
return render(request,'base.html')
else:
return render(request, 'old.html')
Above code authorise only version 4 ( /handler/4 )

How to convert a Django ListView to work on the admin site?

I have a list view (for the admin site) that uses a template as follows:
class UserImageListPendingView(ListView):
model = UserImage
queryset = UserImage.objects.filter(status=ImageBase.PENDING)
template_name = 'userimage_list_pending.html'
context_object_name = 'userimage_list'
paginate_by = 5
#method_decorator(staff_member_required)
def dispatch(self, *args, **kwargs):
return super(UserImageListPendingView, self).dispatch(*args, **kwargs)
Although this works there are problems with putting the URL in urls.py:
urlpatterns = [
url(r'^admin/app/pendinguserimages/?$', login_required(
UserImageListPendingView.as_view()),
name='pendinguserimages'),
...
]
...as this stops the redirection working properly.
I did try to define the URL through admin.py:
def get_admin_urls(urls):
def get_urls():
return patterns('',
url(r'^app/pendinguserimages/?$',
UserImageListPendingView.as_view(), name='pendinguserimages'),
url(r'^app/checkuserimage/(?P<pk>[0-9]+)/?$',
userimage_check, name='checkuserimage'),
...
) + urls
return get_urls
admin_urls = get_admin_urls(admin.site.get_urls())
admin.site.get_urls = admin_urls
... but there was an error when reversing the checkuserimage URL.
How would I go about converting this view to fit in better with the admin site, but still use the template?
I didn't need to rewrite the ListView afterall. After defining the URLs in admin.py instead of in urls.py, all I needed to do was put "admin:" in front of the name when reversing the URL in the template, as follows:
check

How can I receive GET/POST value beside TemplateView class

I'm leaning Python to develop a website. I use Django framework to develop. To create a VIEW using django.views.generic.base.TemplateView.
So I wanna to get value 'user_name' and 'mail' from URL, but don't know how to do that! I cannot import request within this view.
Here is Views.py:
from django.views.generic.base import TemplateView
class MainView(TemplateView):
template_name = 'guestbook/main_page_1.html'
def get_context_data(self, **kwargs):
#I wanna to get value 'user_name' and 'mail' from URL...
name = request.GET.get("user_name") #temp
email = request.GET.get("mail") #temp
context = super(MainView, self).get_context_data(**kwargs)
context['var1'] = name
context['var2'] = email
return context
Here is Urls.py:
from django.conf.urls import patterns, url
from guestbook.views import MainView
urlpatterns = patterns('',
url(r'^$', MainView.as_view(), name='main'),
)
Anybody can help me to do this!
Thanks all!
Request is available in get_context_data() as self.request:
def get_context_data(self, **kwargs):
name = self.request.GET.get("user_name")
email = self.request.GET.get("mail")
...

Categories