Get context from another CBV with Django - python

I would like to get your help in order to use context from a Django CBV in another CBV through get_context_data().
Objective:
Basically, I have a django ListView() with pagination. I pick up the current page in get_context_data(). Then, I would like to edit an object, so I'm going to UpdateView().
When I post the edit, it should return to the previous pagination. For example, if the object was on page 32, after the POST request, I need to be redirected to page 32.
My code:
class DocumentListView(AdminMixin, CustomListSearchView):
""" Render the list of document """
def get_context_data(self, **kwargs):
context = super(DocumentListView, self).get_context_data(**kwargs)
actual_page = self.request.GET.get('page', 1)
if actual_page:
context['actual_page'] = actual_page
return context
class DocumentFormView(CustomPermissionRequiredMixin, DocumentListView, UpdateView):
def get_current_page(self, **kwargs):
context = super(DocumentListView, self).get_context_data(**kwargs)
actual_page = context['actual_page']
return actual_page
def get_context_data(self, **kwargs):
context = super(DocumentFormView, self).get_context_data(**kwargs)
print(self.get_current_page())
...
return context
def post(self, request, pk=None):
...
return render(request, 'app/manage_document_form.html', context)
Issue:
I don't overcome to get the actual_page in my class DocumentFormView.
I got this issue :
AttributeError: 'DocumentFormView' object has no attribute 'object'
I tried to add in my post() function :
self.object = self.get_object()
But it doesn't solve the issue.
Do you have any idea ?

Related

any direct method to Access dynamic url in post method

in views.py
class ProcessMessage(TemplateView):
template_name = 'chat/chat.html'
def get_object(self):
id=self.kwargs.get('pk')
obj=None
if id is not None:
obj= User.objects.get(pk=id)
return obj
def get(self, request, pk=None,*args, **kwargs):
obj=self.get_object()
print(obj,pk)
super(ProcessMessage, self).get(request, *args, **kwargs)
return render(request, self.template_name, {'form': ChatForm()})
def post(self, request, pk=None,*args, **kwargs):
obj=self.get_object()
pk=pk
print(pk)
print('obj is',obj)
form = ChatForm(data=request.POST)
# log = logging.basicConfig(level=logging.DEBUG)
# print('post from index')
if form.is_valid():
//////something////
in urls.py
app_name = 'chatbot'
urlpatterns = [
path('demo', views.ProcessMessage.as_view(), name='index'),
path('<uuid:pk>/demo', views.ProcessMessage.as_view(), name='index'),
]
I am getting the value of obj and pk inside get method but I want those value inside post method also(getting value None currently)
I need id/pk from URL in def Post method to get user information(no I don't want to use request.user)
Your template shows that you are submitting the form to a URL without a pk:
{% url 'chat:index' %}
You should include the pk when reversing the URL, e.g.
{% url 'chat:index' pk %}
You'll need to include the pk in the template context, e.g.
return render(request, self.template_name, {'form': ChatForm(), 'pk': pk})
I see that you are using the same view ProcessMessage for /demo/ and /<pk>/demo/. I would recommend using a different view for both URLs, I think it would help avoid issues like this.

How to remove put from a pre written view in django

I have the following view:
class ReadClass(generics.RetrieveUpdateDestroyAPIView):
queryset = MyCModel.objects.all()
serializer_class = MySerializer
def post(self, request, *args, **kwargs):
''' defined my post here'''
I know retrieveupdatedestroyapiview doesn't have post in it. And I have created my own post in the view here and on the front end, I see both post and put! Is there any way to remove the put.
Or is there any other way to do it better, I tried using ListCreateApi view. The problem with that is while it gives me the post functionality, it lists all the values, while I am looking for a specific pk. I cannot see any other generic view that gives me get and post functionality.
EDIT
I have added the edit as requested, try and except might seem unnecessary here at the moment, but I will add more functionality later on.
class ReadClass(generics.GenericAPIView, mixins.CreateModelMixin, mixins.RetrieveModelMixin):
queryset = MyCModel.objects.all()
serializer_class = MySerializer
def post(self, request, *args, **kwargs):
try:
s1 = MySerializer.objects.get(mRID=kwargs["pk"])
serializer = MySerializer(s1, data=request.data)
except MySerializer.DoesNotExist:
pass
if serializer.is_valid():
if flag == 0:
pass
else:
serializer.update(s1,validated_data=request.data)
else:
return Response(serializer.errors)
urlpatterns = [path('temp/<int:pk>', ReadClass.as_view(), name = " reading"),]
DRF has mixins for List, Create, Retrieve, Update and Delete functionality. Generic views just combine these mixins. You can choose any subset of these mixins for your specific needs. In your case, you can write your view like this, if you only want Create and Retrieve functionalty:
class ReadClass(GenericAPIView, CreateModelMixin, RetrieveModelMixin):
queryset = MyCModel.objects.all()
serializer_class = MySerializer
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
This would provide default functionality for post and get requests. If you prefer, you can override post method like you did in your example to customize post requset behavior.
You can read more about mixins and generic views here

How to return an empty form in ModelFormMixin

DetailStory subclasses DetailView and ModelFormMixin thus presenting the DetailView of a certain story and a form at the end. However, on filling the form and submitting the data, the data is saved in the databases but it is still shown on the form (in addition to the one now displayed on the DetailView). How do I present an empty form after submitting it? (Here is the code sample)
class DetailStory(DetailView, ModelFormMixin):
model = Story
template_name = 'stories/detail_story.html'
context_object_name = 'detail'
form_class = CommentForm
def get(self, request, *args, **kwargs):
self.object = None
self.form = self.get_form(self.form_class)
return DetailView.get(self, request, *args, **kwargs)
def post(self, request, *args, **kwargs):
self.object = None
self.form = self.get_form(self.form_class)
if self.form.is_valid():
obj = self.form.save(commit=False)
obj.user = self.request.user
obj.memoir = self.get_object()
self.object = obj.save()
return self.get(request, *args, **kwargs)
def get_object(self):
item_id = crypt.decode(self.kwargs['story_id'])[0]
obj = get_object_or_404(Story, Q(privacy='public') | Q(user_id=self.request.user.id), pk=item_id)
return obj
get_form uses the request data to construct the form as per the docs
If the request is a POST or PUT, the request data (request.POST and request.FILES) will also be provided.
So simply don't make your post function go back through the get, just have it redirect to your required place or do anything differently to pointing it at the get function.
return redirect('mynamespace:story_detail', story_id=self.object.pk)
You may wish to read this answer for a list of technical details you should consider whilst making your application. In particular,
Redirect after a POST if that POST was successful, to prevent a refresh from submitting again.

Django: How to provide context into a FormView get() method (also using request param)

I'm trying to provide some additional context into the get() method in my FormView. I need get() because I need to run some logic first, check for a potential redirect. I also need access to the request object (because I need to check session data). Can't figure out how to do it. Simplified code below..
Attempt 1:
class LoginView(FormView):
template_name = 'members/login.html'
form_class = LoginForm
def get(self, request):
# check if to redirect
if self.request.session.get('user'):
return redirect('/dashboard/')
# render page with extra context
else:
context = super(LoginView, self).get(request)
context['message'] = self.request.session['message']
return context
No errors, but context does not come through in the template.
Attempt 2:
class LoginView(FormView):
template_name = 'members/login.html'
form_class = LoginForm
def get_context_data(self, request, **kwargs):
# check if to redirect
if self.request.session.get('user'):
return redirect('/dashboard/')
# render page with extra context
else:
context = super(LoginView, self).get_context_data(**kwargs)
context['message'] = self.request.session['message']
return context
Getting TypeError: get_context_data() takes exactly 2 arguments (1 given)
P.S. This work relates to a workaround Django's buggy messages middleware which seems to be working locally flawlessly but on live (Heroku) is not 100% reliable, renders on some pages only. Ugh, frustration setting in...
Ditch the request argument to the get_context_data method. You should also use the dispatch method to check if the user is logged in.
class LoginView(FormView):
template_name = 'members/login.html'
form_class = LoginForm
def dispatch(self, *args, **kwargs):
"""Use this to check for 'user'."""
if request.session.get('user'):
return redirect('/dashboard/')
return super(LoginView, self).dispatch(*args, **kwargs)
def get_context_data(self, **kwargs):
"""Use this to add extra context."""
context = super(LoginView, self).get_context_data(**kwargs)
context['message'] = self.request.session['message']
return context

Django Class Based View: retrieve lastly viewed entry

I am fairly new to CBV and I have the following question:
I see that there is CreateView that would show you the "empty" form to create a new database entry and there is UpdateView that would show you the form for the existing entry for update.
What I need is some kind of mix of it: present the user with the form for the lastly viewes/updated entry, but if the database has no entries yet (e.g. new user), present the user with a default ("empty") form.
So, there are 2 points here:
Have a model that contains lastly viewed/updated entry per user: what should this model be?
Have a view that allows to present forms as specified above. Is there a generic or semi-generic way to do that in Django? What kind of CBV should I be using?
Thanks.
I haven't tested this so I'm not sure if this will work.
from django.views.generic.edit import ModelFormMixin, ProcessFormMixin
class MyView(ModelFormMixin, ProcessFormMixin):
def get(self, request, *args, **kwargs):
try:
self.object = MyModel.objects.latest("id")
except MyModel.DoesNotExist:
self.object = None
return super(MyView, self).get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
try:
self.object = MyModel.objects.latest("id")
except MyModel.DoesNotExist:
self.object = None
return super(MyView, self).post(request, *args, **kwargs)

Categories

Resources