accessing context data in a class - python

I want to use DeleteView for different cases instead of rewriting a new function for every case. So I thought I pass the model as an argument in the URL and then select which delete to use by overriding the get_context_data function. My problem is how to access the context variable:
views.py:
class PDelete(DeleteView):
template_name='kammem/delete.html'
if context['model']=='Person':
model=Person
success_url=reverse_lazy('personer')
elif context['model']=='Concert':
model=Concert
success_url=reverse_lazy('concert')
def get_context_data(self,**kwargs):
context=super().get_context_data(**kwargs)
context['model']=self.kwargs['model']
return context
urls.py
path('pdelete/<int:pk>/<str:model>',PDelete.as_view(),name='pdelete'),
The problem is that the context variable is undefined in the class. Any suggestions?

What you pass through url,is accessible via self.request.kwargs in your class methods.
You should implement the if conditions in one of your class methods,preferably delete method.
Also don't forget to delete the object when you are overriding delete method.

Related

How are the function/methods defined inside a class Based Views CBV are called?

I have been learning the Django framework for 3-4 months but there is 1 thing that bugs me the most and I am unable to find a satisfactory answer yet.When we define the functions/methods inside a Class based views, do they get called automatically when some object is created? Like we use
#action(detail=False)
def recent_users(self, request):
recent_users = User.objects.all().order_by('-last_login')
page = self.paginate_queryset(recent_users)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(recent_users, many=True)
return Response(serializer.data)
How this method will be executed? DO we have to make an object and call like obj.method?
And how those get() get_queryset() methods work given with the Class Based Views?? How do they process the data from models?
and one last question would be the mixture of these both.
Can I create a new method inside a ClassBasedView? If yes, How do I execute it ? Say in return and render data inside a template ?
Please do not provide any link. I just want to know in simple English terms. If anybody knows, it'll be very helpful.
When referencing a class based view in the path (url prior to 2.X) function we call the as_view class method. Looking at the source code will show that this essentially defines a function view that calls a class based view's dispatch method.
What this means is that the entry point in a class based view is the dispatch method. All other methods are called somewhere down the line from dispatch. The methods immediately called by dispatch are all going to be named according to HTTP methods (E.G. get, post, delete).
This is the typical path for a view inheriting from TemplateView.
as_view returns a function that calls dispatch.
dispatch calls get or, if request.method isn't GET, the http_method_not_allowed method.
get calls get_context_data and passes that as an argument to render_to_response.
render_to_response calls get_template_names and passes that as an argument to TemplateResponse.
You can define any method you want on your class based view, but it won't be called unless you call it somewhere that is already being called.
One common modification is to add something to get_context_data.
def get_context_data(self, **kwargs):
kwargs.setdefault('recent_users', self.recent_users())
return super().get_context_data(**kwargs)
def recent_users(self):
# self.request is accessible here.
...
https://ccbv.co.uk/ is a helpful resource for writing class based views. I reference that site all the time while I'm writing class based views.

create custom methods in django class base views

I want to use generic class base views using django 1.9
What i am trying to understand that
from django.views.generic import CreateView
from braces.views import LoginRequiredMixin
from .models import Invoice
class InvoiceCreateView(LoginRequiredMixin,CreateView):
model = Invoice
def generate_invoice(self):
...
return invoice
now i want to bind this custom method to url. How can i achive this?
I know using function base view its simple but i want to do this using class base views.
Help will be appreciated.
Yes, this is the main issue to grasp in CBV: when things run, what is the order of execution (see http://lukeplant.me.uk/blog/posts/djangos-cbvs-were-a-mistake/).
In a nutshell, every class based view has an order of running things, each with it's own method.
CBV have a dedicated method for each step of execution.
You would call your custom method from the method that runs the step where you want to call your custom method from. If you, say, want to run your method after the view found that the form is valid, you do something like this:
Class InvoiceCreateView(LoginRequiredMixin,CreateView):
model = Invoice
def generate_invoice(self):
... do something with self.object
return invoice
def form_valid(self,form):
self.object = form.save()
self.generate_invoice()
return super(InvoiceCreateView,self).form_valid(form)
So you have to decide where your custom method should run, and define your own method on top of the view generic method for this step.
How do you know what generic method is used for each step of executing the view? That the method the view calls when it gets the initial data for the form is def get_initial? From the django docs, and https://ccbv.co.uk/.
It looks complex, but you actually have to write very few methods, just where you need to add your own behaviour.

Is it okay to set instance variables in a Django class based view?

I trying out Django's class based views (CBVs).
class BlahView(TemplateView):
template_name = 'blah/blah.html'
def get_context_data(self, **kwargs):
#code...
def get(self, request, **kwargs):
#more code...
Now, I know that I can get the request params from self.request. Now say I want to parse these request params and store them within the class. Can I store those in self.xxx? Now, obviously based on how classes work, this seems straightforward.
But I can't make out the flow of control, looking at the definition of View (superclass of TemplateView). The source mentions as_view() to be the 'entry-point'
I thought of setting my instance variables at the beginning of get_context_data() but that doesn't seem right to do initialization there.
Can I define an __init__() for my CBV?
If so, will there be threading issues or something where multiple page-accesses possibly work with a global instance of my parsed data?
I know this sounds a bit messy, but I'm just a bit confused with the code flow in CBVs.
According to the source of django.views.generic.base.View.as_view:
on django startup, as_view() returns a function view, which is not called
on request, view() is called, it instantiates the class and calls dispatch()
the class instance is thread safe
According to the source of django.views.generic.base.View.__init__, the request object is out of scope at this point so you can't parse it in your own constructor overload.
However, you could parse the request and set class view instance attributes in an overload of django.views.generic.base.View.dispatch, this is safe according to the source:
class YourView(SomeView):
def dispatch(self, request, *args, **kwargs):
# parse the request here ie.
self.foo = request.GET.get('foo', False)
# call the view
return super(YourView, self).dispatch(request, *args, **kwargs)
#jpic provided a great answer. Inspired from it, I would like to reference the following blog post where the author claims that:
... We cannot override view, as doing so would require overriding
as_view(). Overriding dispatch() is appealing (and what I did
originally when I presented this talk) because it offers a single
simple place to do so, but this defies the logic of dispatch().
Instead, it is best to call set_account() in overrides of both get()
and post(). ...
Therefore, one can override the get or post methods and set any self.whatever variables. It feels somehow cleaner.

Overriding Django's RelatedManager methods

Django's ForeignRelatedObjectsDescriptor.create_manager(...) function dynamically creates the RelatedManager classes and subsequently initializes an instance of the dynamically created class.
If I wanted to override the RelatedManager.add(...) method, how would I do it?
The RelatedManager classes are created in file: django/db/models/fields/related.py.
An example of how I'd like to use a custom RelatedManager is...
class Record(Model):
string = CharField()
class Managed(Model):
record = ForeignKey('Record')
boolean = BooleanField()
def view_function(...):
record = Record(string='Example')
record.save()
record.managed_set.add(Managed(boolean=True)) # How to override add()?
Any suggestions would be appreciated.
I'm not sure what you need the override for - the default queryset already does what you want.
But to answer the question, you can define a custom Manager on the model and set use_for_related_fields=True to ensure it gets used as the automatic manager. See the documentation on controlling automatic Manager types.
I think I am having the same problem.
I have a custom manager that overrides self._db and get_query_set() to route it to different databases.
I dynamically created a model class, and has its _default_manager set with my custom manager.
This works for the class itself, but not for related field (foreign or many2many), even though I did set sets use_for_related_fields = True.
For related field, appending db_manager(dbname) (for example, record.managed_set.db_manager(dbname)) can fix all() method, but not for add() method.
To understand what I mean, see this django ticket: http://code.djangoproject.com/ticket/13358
I think it works for all(), but not add().
RelatedManager.add() calls RelatedManager._add_items() which calls Manager.bulk_create().
So if you extend Manager.bulk_create(), you might be able to achieve what you are after.

How do we override the choice field display of a reference property in appengine using Django?

The default choice field display of a reference property in appengine returns the choices
as the string representation of the entire object. What is the best method to override this behaviour? I tried to override str() in the referenced class. But it does not work.
I got it to work by overriding the init method of the modelform to pick up the correct fields as I had to do filtering of the choices as well.
The correct way would be to override the __unicode__ method of the class, like:
def __unicode__(self):
return self.name
where name is the value that you want to display.

Categories