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.
Related
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.
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.
I have some functions like:
has_delete_permission,
has_add_permission,
get_actions,
formfield_for_foreignkey
get_queryset
Etc are the built-in ModelAdmin functions which I am using in almost all the ModelsAdmin's in my project.
How to create a common/reusable class which include these functions and reuse in the other ModelAdmin classes?
How to pass the reference of the Model or the ModelAdmin class to the common class?
What should be the file structure to be maintained, in case this has to be used for many apps in a project.
Some direction will be great help.
Thanks.
I'd recommend using Python's class's multiple inheritance to achieve this. It would look something like this:
from django.contrib import admin
from .models import Banana
class MyAdminMixin:
def has_delete_permission(self, obj):
# Your code goes here
def has_add_permission(self, obj):
# Your code goes here
class BananaModelAdmin(MyAdminMixin, admin.ModelAdmin):
# Now your admin has access to the methods in MyAdminMixin
model = Banana
For some more information on using mixins with class-based views, take a look at the Django docs on the subject. Hope this helps!
I am looking for some way to define some wrapper that is called before i call to Model.objects.all().
I want whenever i call, Model.objects it call my method (wrapper) and then return the objects back to the query.
Lets take an example:
MyModel.objcts.filter(name="Jack")
Wrapper:
def mymodelWrapper(self):
return self.objects.annotate(size=Sum('id', field='order_size_weight*requested_selling_price'))
I want to run annotate in the background and also want to apply the filter.
I Know what i want to achieve, its the code i am looking for how to do that.
What you are talking about is perfectly doable with Django by using a custom model manager:
class MyModelManager(models.Manager):
def get_query_set(self):
return super(MyModelManager, self).get_query_set().annotate(size=Sum('id', field='order_size_weight*requested_selling_price'))
class MyModel(models.Model):
objects = MyModelManager()
# fields
Also see other similar topics:
Is it possible to override .objects on a django model?
Override djangos's object.all() with the request data
Django custom model managers
I have my page where I have my posts list, and I also want to have sidebar with suggestions. I used generic ListView for my posts, and needed to pass suggestions somehow so I used extra_context which should(?) work like that according to few examples I've read, but in template there is no 'suggestions' object.
class PostList(generic.ListView):
model = models.Post
paginate_by = 10
context_object_name = 'mj'
def get_queryset(self):
return models.Post.objects.filter(user = self.request.user)
def extra_context(self):
return {'suggestions':models.Pla.objects}
I don't have experience in django so maybe there is better way to pass suggestions for sidebar. Maybe it's possible to do this with wrapping view function since I want to have suggestions..
Class-based views don't use extra_context the way the older function-based generic views did. Instead, the usual way to do this is with a custom get_context_data call as shown in the docs:
https://docs.djangoproject.com/en/dev/topics/class-based-views/generic-display/#adding-extra-context
The example in the docs is almost exactly what you're trying to do. You may want to follow its example further and pass in a queryset (models.Pla.objects.all()) rather than the manager object (models.Pla.objects).