Add querystring parameters to from class based detail view with Django - python

How can I modify a class based view to add querystring parameters to the view? (So that when the view response is returned, the querystring is in the address bar?
class MyDetailView(DetailView):
"""
A detail view for retrieving a model object.
"""
model = MyModel
def some_function_to_modify_qs(self):
# do something and return modified qs for response

Not entirely sure why you’d want to do this, you could pass the values into the template instead but to answer your question the following should work.
from django.shortcuts import redirect
#inside your get method
return redirect(request.get_full_path() + “?query=string”)

Related

Control requests to view and template output in django

This is a view for get all the records in the EducationalRecord model:
def all_education_resume(request):
RESUME_INFO['view'] = 'education'
educations_resume = EducationalRecord.objects.all().order_by('-created_date')
template = 'resumes/all_resume.html'
context = {'educations_resume': educations_resume, 'resume_info': RESUME_INFO}
return render(request, template, context)
Now, if I want to write exactly this view for other models (like job resumes, research resumes , etc.),
I must another view one separately.
My question is:
How can I get a view for all these requests, so first check the URL of
the request and then do the relevant query? How can I control URL
requests in my views?
My other question is exactly the same as my first question,with this difference:
control view that must render in specific template.In other words,in
second question the ratio between the template and the view is instead
of the ratio of the view to the url or how to create a template for
multiple views (for example, for a variety of database resume
resumes, I have a template) and then, depending on which view render,
the template output is different.
I have implemented these two issues as follows:
I wrote a view for each of request!
In each view, I set the value of RESUME_INFO['view'], and then I've checked it in a template page and specified the corresponding template.
What is the best solution to these two questions?
How can I get a view for all these requests, so first check the URL of the request and then do the relevant query? How can I control URL requests in my views?
You can access request.path, or you can let the url(..)s pass a parameter with kwargs that holds a reference to the model for example, but this is usually bad design. Typically if you use different models, you will likely have to order these different as well, filter these differently, render these differently, etc. If not, then this typically indicates that something is wrong with the modeling.
You can however make use of class-based views [Django-doc], to remove as much boilerplate as posssible. Your view looks like a ListView [Django-doc], by using such view, and patching where necessary, we can omit most of the "boilerplate" code:
# app/views.py
from django.views.generic.list import ListView
class MyBaseListView(ListView):
resume_info = None
template = 'resumes/all_resume.html'
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
context['resume_info'] = {'view': self.resume_info}
return context
In the individual listviews, you then only need to specify the resume_info and the model or queryset to render it with the 'all_resume.html' template, for example:
# app/views.py
# ...
class EducationalResumeView(MyBaseListView):
queryset = EducationalRecord.objects.order_by('-created_date')
resume_info = 'education'
class OtherModelView(MyBaseListView):
model = OtherModel
resume_info = 'other_info'
So we can here use inheritance to define common things only once, and use it in multiple views. In case we need to change something in a specific view, we can override it at that level.
In the urls.py, you define such view with the .as_view() method [Django-doc]. For example:
# app/urls.py
from django.urls import path
from app.views import EducationalResumeView, OtherModelView
urlpatterns = [
path('education/', EducationalResumeView.as_view()),
path('other/', OtherModelView.as_view()),
]

How to implement method in Django REST?

Have the next Django REST question.
I have the view.
class MessageViewSet(viewsets.ModelViewSet):
serializer_class = MessageSerializer
queryset = Message.objects.filter(isread = False)
def mark_read():
queryset = Message.objects.update(isread=True)
return Response({'read':queryset})
And router in urls.py
router = SimpleRouter() router.register(r'api/get_messages', MessageViewSet)
urlpatterns = [
url(r'^$', MainView.as_view(), name='main'),
url(r'^', include(router.urls)) ]
Now i have 'get_messages' page which shows all list.
How can i implement a method which would change 'isread' value of model instanse from False to True, when I visit a 'mark_read' page?
As you can see, i tried to write method in the class. But when i'm trying to call it in urls in this way:
router.register(r'api/mark_read', MessageViewSet.mark_read),
Here comes an error.
assert queryset is not None, 'base_name argument not specified, and could ' \
AssertionError: base_name argument not specified, and could not automatically determine the name from the viewset, as it does not have a .queryset attribute.
Maybe i shouldnt use router, and rewrite view and urls in other way. If u know how to solve this problem, please answer. Thanks.
You can use detail_route or list_route decorators.
from rest_framework.decorators import list_route
class MessageViewSet(viewsets.ModelViewSet):
#list_route()
def mark_read(self, request):
queryset = Message.objects.update(isread=True)
return Response({'read':queryset})
With that mark_read method will be available at api/get_messages/mark_read. And you don't need to create separate router, just use one you created for MessageViewSet
docs reference
Since you are using a model viewset you can directly use put or patch rest method to send the desired value for the desired field as the data.
Ideally in rest get should not change model values. If you really want a different end point put the list_route or detail_route decorator on your mark_read method, and make them a valid call for only a put and/or patch call
from rest_framework.decorators import list_route
class MessageViewSet(viewsets.ModelViewSet):
#list_route(methods=['Patch', 'PUT'])
def mark_read(self, request):
queryset = Message.objects.update(isread=True)
return Response({'read':queryset})
Thanks to #ivan-semochkin and #Shaumux for replies. Advices were really helpful.
That is my route. I used detail_route instead of list_route.
#detail_route(methods=['get','put'], url_name='mark_read/')
def mark_read(self, request, pk=None):
queryset = Message.objects.filter(pk=pk).update(isread=True)
return Response({'read':queryset})
Now 'isread' value is changing wnen i visit 'mark_read' page.
Link: "api/get_messages/pk/mark_read"
Does anyone know, is it posslible to make links looking the next way:
"api/get_messages" - list, "api/mark_read/pk" - changing isread value.
Is it possible to create something like this? "api/mark_read?=pk"

In Django Rest Framework, how is the object passed to a class based view from urls.py used?

I've been following the Django Rest Framework tutorial here http://www.django-rest-framework.org/tutorial/3-class-based-views/
This code in particular is intriguing:
class SnippetList(APIView):
"""
List all snippets, or create a new snippet.
"""
def get(self, request, format=None):
snippets = Snippet.objects.all()
serializer = SnippetSerializer(snippets, many=True)
return Response(serializer.data)
I know that the url function called in urls.py returns a function like entry point to the class based view when using the as_view method. Is request the object corresponding to this?
If it is, then where does the class access it and its attributes when a GET is performed? I cannot see a reference to request in the getmethod of SnippetList.
If it is not, then what does request refer to, and how does the class based view access the data in the client's request?

How to render an html template with data from view?

I am new to django. I made a form. I want that if the form is filled successfully then django should redirect to a success page showing the name entered in the form but no parameters should be present in the url itself.
I searched on the internet and the solution I got was to redirect to url with pk as a get parameter which fetches the data and shows in the view. But I don't want to pass any thing in the url itself. and some websites say that http can't redirect with post data.
Here's my views.py
class UserRegistrationView(CreateView):
model = UserForm
template_name = 'userregistration.html'
form_class = UserForm
success_url = 'success'
def get_success_url(self):
return reverse('success',kwargs = {'name' : self.object.firstName})
and here's the template to which I want to redirect:
<h2>Congratualations for registering {{name}} </h2>
Basically what I want is that if the person fill form mentioning his/her firstName as "xyz" then the redirected success page should say that "Congratulations for registering xyz"
You can use django sessions, which I believe installed by default in 1.8
Look here
# Set a session value:
request.session["fav_color"] = "blue"
# Get a session value -- this could be called in a different view,
# or many requests later (or both):
fav_color = request.session["fav_color"]
# Clear an item from the session:
del request.session["fav_color"]
You can pass your pk via session and extract your object in another view without affecting your url.
Make sure you clean up after yourself.
Let me know if more help needed.
One of the possible ways of passing data between views is via sessions. So, in your UserRegistrationView you need to override the form_valid method as shown below.
class UserRegsitrationView(CreateView):
def form_valid(self,form):
self.request.session['name'] = self.object.firstName
return super(UserRegistrationView,self).form_valid(form)
class SuccessView(TemplateView):
template_name = "success_template.html"
def get_context_data(self,**kwargs):
context = super(SuccessView,self).get_context_data(**kwargs)
context['name'] = self.request.session.get('name')
del self.request.session['name']
return context
One more thing that you can modify in your code is that you need not declare success_url if you are overriding get_success_url

How to use current logged in user as PK for Django DetailView?

When defining URL patterns, I am supposed to use a regular expression to acquire a PK from the URL.
What if I want a URL that has no PK, and if it's not provided, it will use the currently logged in user? Examples:
visiting /user will get a DetailView of the currently logged in user
/user/edit will show an UpdateView for the currently logged in user
I tried hard-coding the pk= in the Detail.as_view() call but it reports invalid keyword.
How do I specify that in the URL conf?
My sample code that shows PK required error when visiting /user URL:
urlpatterns = patterns('',
url(r'user/$',
DetailView.as_view(
model=Account,
template_name='user/detail.html')),
)`
An alternative approach would be overriding the get_object method of the DetailView subclass, something along the line of:
class CurrentUserDetailView(UserDetailView):
def get_object(self):
return self.request.user
Much cleaner, simpler and more in the spirit of the class-based views than the mixin approach.
EDIT: To clarify, I believe that two different URL patterns (i.e. one with a pk and the other without) should be defined separately in the urlconf. Therefore they could be served by two different views as well, especially as this makes the code cleaner. In this case the urlconf might look something like:
urlpatterns = patterns('',
url(r"^users/(?P<pk>\d+)/$", UserDetailView.as_view(), name="user_detail"),
url(r"^users/current/$", CurrentUserDetailView.as_view(), name="current_user_detail"),
url(r"^users/$", UserListView.as_view(), name="user_list"),
)
And I've updated my example above to note that it inherits the UserDetailView, which makes it even cleaner, and makes it clear what it really is: a special case of the parent view.
As far as I know, you can't define that on the URL definition, since you don't have access to that information.
However, what you can do is create your own mixin and use it to build views that behave like you want.
Your mixin would look something like this:
class CurrentUserMixin(object):
model = Account
def get_object(self, *args, **kwargs):
try:
obj = super(CurrentUserMixin, self).get_object(*args, **kwargs)
except AttributeError:
# SingleObjectMixin throws an AttributeError when no pk or slug
# is present on the url. In those cases, we use the current user
obj = self.request.user.account
return obj
and then, make your custom views:
class UserDetailView(CurrentUserMixin, DetailView):
pass
class UserUpdateView(CurrentUserMixin, UpdateView):
pass
Generic views uses always RequestContext. And this paragraph in the Django Documentation says that when using RequestContext with auth app, the template gets passed an user variable that represents current user logged in. So, go ahead, and feel free to reference user in your templates.
You can get the details of the current user from the request object. If you'd like to see a different user's details, you can pass the url as parameter. The url would be encoded like:
url(r'user/(?P<user_id>.*)$', 'views.user_details', name='user-details'),
views.user_details 2nd parameter would be user_id which is a string (you can change the regex in the url to restrict integer values, but the parameter would still of type string). Here's a list of other examples for url patterns from the Django documentation.

Categories

Resources