Django: Class Based View accessing URL variables - python

My urls.py has an entry:
urlpatterns = [
url(r'^results/(?P<query>).+', views.ResultsView.as_view(), name="results"),
]
which matches to the corresponding Class Based View:
class ResultsView(TemplateView):
template_name = os.path.join(APPNAME, "results.html")
def dispatch(self, request, *args, **kwargs):
query = kwargs['query']
print("HERE: " + str(json.dumps(kwargs, indent=1)))
print(self.kwargs['query'])
print(self.kwargs.get('query'))
print(kwargs['query'])
print(kwargs.get('query'))
if query is None:
return redirect('/')
return super(ResultsView, self).dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = super(ResultsView, self).get_context_data(**kwargs)
print("HERE: " + str(json.dumps(kwargs, indent=1)))
print(self.kwargs['query'])
print(self.kwargs.get('query'))
print(kwargs['query'])
print(kwargs.get('query'))
...
# This is just here to test if 'query' is set
def get(self, request, query):
print(query)
I'm trying to get the value of the query variable that is set in urls.py. However, after trying various solutions I found on other SO posts (as you can see from all the print statements), nothing is working.
I'm fairly sure my urls.py is set up properly, because the request resolves to the correct page (results/), but all attempts to print the query entry of the dict return an empty string, and json.dumps(kwargs, indent=1)) prints this:
HERE: {
"query": ""
}
What am I doing wrong?

Just copy my comment as an answer. You missed pattern part in url's regular expression. Try to change url to this:
url(r'^results/(?P<query>[\w.-]+)', views.ResultsView.as_view(), name="results")

Related

How to move some code from post method to a separate method in Django views

I have a class that take some info from a form, make some changes to it. And than saves it into database
At the moment all the logic is in the post method. And I want to make the code more structured and I want to put some part of it to a separate method. Is it possible? If so, how can I do it?
here is my code:
class AddSiteView(View):
form_class = AddSiteForm
template_name = 'home.html'
def get(self, request, *args, **kwargs):
form = self.form_class()
return render(request, self.template_name, { 'form': form })
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
site_instanse = form.save()
url = request.POST.get('url', '')
if url.endswith('/'):
url = url + "robots.txt"
else:
url = url + "/robots.txt"
robot_link = Robot(
site = site_instanse,
link = url,
)
robot_link.save()
pk = Robot.objects.get(site=site_instanse)
return redirect('checks:robots', pk.id)
return render(request, self.template_name, { 'form': form })
I want to make 2 changes to it:
The 1st thing I want to do is to move this part of code to a separate method
if url.endswith('/'):
url = url + "robots.txt"
else:
url = url + "/robots.txt"
And the 2nd thing I want to do is to move this part of code also in a separate method
robot_link = Robot(
site = site_instanse,
link = url,
)
robot_link.save()
pk = Robot.objects.get(site=site_instanse)
return redirect('checks:robots', pk.id)
The reason is that I will be adding more functions here. And I don't want to have it all in post method. If it is possible, please, help me. I've already tried several ways of solving this problem, but they didn't work
Thank you
There is nothing special about Django preventing you from using plain python functions. So, if you know how to define methods and functions, you should take the same approach. For example, the first part can be the function
def get_robots_url(url):
if url.endswith('/'):
url = url + "robots.txt"
else:
url = url + "/robots.txt"
return url
Then you call the extracted function in the same place
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
site_instance = form.save()
url = request.POST.get('url', '')
url = get_robots_url(url)
....
You can also define a function inside the class - a method, to group the code. For the 2nd part:
class AddSiteView(View):
...
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
site_instanse = form.save()
url = request.POST.get('url', '')
url = get_robots_url(url)
return self.create_robot(site_instanse, url)
return render(request, self.template_name, { 'form': form })
def create_robot(self, site_instance, url):
robot_link = Robot(
site = site_instanse,
link = url,
)
robot_link.save()
pk = Robot.objects.get(site=site_instance)
return redirect('checks:robots', pk.id)

django rest framework detail_route not working in get method

I defined a viewset using ModelViewSet as follow
I tried to redefine the GET method to do something like getting something from celery . but this part of code just won't work , it acts just like a standard API and didn't do what I wrote in the get_job_detail function.
How should I correctly define the "detail_route" function.
views.py
class JobViewSet(viewsets.ModelViewSet):
queryset = job.objects.all()
serializer_class = JobSerializer
#detail_route(methods=['get'])
def get_job_detail(self, request, pk=None):
# print('these part wont proceed')
job_item = self.get_object()
if job_item.isReady or job_item.isSuccessful:
return Response(self.serializer_class(job_item).data)
celeryjob = sometask.AsyncResult(pk)
celeryjob.get()
if celeryjob.state == 'SUCCESS':
job_item.state = celeryjob.state
job_item.result = celeryjob.result
job_item.isReady = True
job_item.isSuccessful = True
job_item.save()
if celeryjob.state == 'FAILURE':
job_item.state = celeryjob.state
job_item.result = celeryjob.result
job_item.isReady = True
job_item.isSuccessful = False
job_item.save()
return Response(self.serializer_class(job_item).data)
urls.py
from django.conf.urls import url, include
from apply_api import views
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'job',views.JobViewSet)
urlpatterns = [
url(r'^', include(router.urls)),
]
now your correct url is: /job/<pk>/get_job_detail if you want just: /job/<pk> you don need to use #detail_route just rename your method to the def retrieve(self, request, *args, **kwargs): more details retrievemodelmixin one of the part class of the modelviewset

Django: No reverse match

def test_post_request_for_api_view(self):
data = {
"email": self.user.email,
}
url = self.reverse('users:the_api', self.user.pk)
response = self.json_post(data, url=url)
self.mock.assert_called_once_with(self.user)
data2 = json.loads(response.content.decode('utf-8'))
self.assertEqual(data2, {
'booking_order': ['ABCDEFGHIJKL'],
'transaction_total': '20000.00'
})
urls.py
urlpatterns = [
url(
regex=r'^$',
view=views.UserListView.as_view(),
name='list'
),
url(
regex=r'^~redirect/$',
view=views.UserRedirectView.as_view(),
name='redirect'
),
url(
regex=r'^(?P<username>[\w.#+-]+)/$',
view=views.UserDetailView.as_view(),
name='detail'
),
url(
regex=r'^~update/$',
view=views.UserUpdateView.as_view(),
name='update'
) ,
url(
regex=r'^the_api/$',
view = views.UserApiView.as_view(),
name='the_api'
),
]
views.py
class UserApiView(APIView):
authentication_classes = authentication.TokenAuthentication ###Am assuming you're authenticating via a token
def get(self, request):
"""
Get user based on username.
Am getting only the username since that's the only field used above.
:param request:
:param format:
:return:
"""
details = User.objects.all()
serializer = UserSerializer(details, many=True)
return Response(serializer.data )
def post(self, request, format=None):
"""
Create a new user instance
:param request:
:param format:
:return:
"""
serializer = UserSerializer(request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors)
As much as i understand how reverse works in Django, i believe for the above test to pass, i only need to have a the_api url in my urls.py.
However, the test does not pass even with that.
As such, i would love to know what the right thing to do is.
How do i get the test to run?
The error i keep getting is:
django.urls.exceptions.NoReverseMatch: Reverse for 'the_api' with arguments '(1,)' and keyword arguments '{}' not found. 1 pattern(s) tried: ['users:the_api/$']
Do you have accepted argument in your url? Looking at your code you should have following entry in your urls.py file:
url(r'the_api/(\d+)/$', your_view, name="the_api")
May be you should paste your url entry too and the corresponding view so that we can look deeper into the issue.

Django - Getting parameters from URL

I am passing the parameters in URL to my view like this:
127.0.0.1:8000/cars/?model_number=13375
and getting it like this:
class GetCarDetails(View):
def get(self, *args, **kwargs):
model_number = "";
if request.GET.get('model_number'):
model_number = request.GET.get('model_number')
But I want to pass it now like this:
127.0.0.1:8000/cars/13375/
And I want Django to treat the 13375 like model number
You need to define it at the url's:
url(r'^cars/(?P<pk>[0-9]+)/$', views.GetCarDetails.as_view(), name="getcardetails"),
And in your views:
class GetCarDetails(View):
...
def get_context_data(self, **kwargs):
context = super(GetCarDetails, self).get_context_data(**kwargs)
context["model_number"] = self.kwargs['pk'];
return context
As told by #Anentropic in comments, more detailed info here

django class based view got an error: 'get_context_data() keywords must be strings'

I am doing migration on a django site, I rewrote the list_object view to class based view which inheritated from django.views.generic.ListView, but I got error when I create get_context_data method
My code here:
class ForumView(ListView):
context_object_name = 'forum'
template_name = 'forum/thread_list.html',
paginate_by = FORUM_PAGINATION
def get_queryset(self):
try:
f = Forum.objects.for_groups(self.request.user.groups.all()).select_related().get(slug=self.kwargs['slug'])
except Forum.DoesNotExist:
raise Http404
return f.thread_set.select_related().all()
def get_context_data(self, **kwargs):
try:
f = Forum.objects.for_groups(self.request.user.groups.all()).select_related().get(slug=self.kwargs['slug'])
except Forum.DoesNotExist:
raise Http404
form = CreateThreadForm()
child_forums = f.child.for_groups(self.request.user.groups.all())
extra_context = {
'forum': f,
'child_forums': child_forums,
'form': form,
'login': {
'reason': _('create a new thread'),
'next': f.get_absolute_url(),
},
'section': 'forum',
}
context = super(ForumView, self).get_context_data(**kwargs)
for key in extra_context:
context[key] = extra_context[key]
return context
and url.py
url(r'^thread/(?P<thread>[0-9]+)/$', ThreadView.as_view(), name='forum_view_thread'),
but the django return a debug page with:
Exception Value: get_context_data() keywords must be strings
Python Version: 2.7.3
Django Version: 1.5.2
Request URL: http://localhost:8000/forum/thread/1/
Exception Location: /Library/Python/2.7/site-packages/django/views/generic/list.py in get_context_data, line 116
traceback:
/Library/Python/2.7/site-packages/django/core/handlers/base.py in get_response
response = callback(request, *callback_args, **callback_kwargs) ...
/Library/Python/2.7/site-packages/django/views/generic/base.py in view
return self.dispatch(request, *args, **kwargs) ...
/Library/Python/2.7/site-packages/django/views/generic/base.py in dispatch
return handler(request, *args, **kwargs) ...
/Library/Python/2.7/site-packages/django/views/generic/list.py in get
context = self.get_context_data(object_list=self.object_list) ...
/Users/foulwall/Dropbox/mldata/forum/views.py in get_context_data
context = super(ThreadView, self).get_context_data(**kwargs) ...
/Library/Python/2.7/site-packages/django/views/generic/list.py in get_context_data
return super(MultipleObjectMixin, self).get_context_data(**context) ...
Anyone with a solution? thanks~
I suspect that one of the kwargs that you are sending to get_context_data is not a simple string object. This could be passed through as the key in a kwargs dictionary. Perhaps it is a lazy or a translatable string?
Something similar happened to the person that asked this question. If it the same issue, I suggest you ensure that the variable name is indeed a simple string. Unicode chars in variable names are odd, but acceptable btw.

Categories

Resources