I'm converting some django views to be class based, and so far loving the flexibility.
Most of my views subclass from a parent view ClubView. Each subclassed view that needs to handle a post() method override needs to have access to the corresponding club value.
This value is in the URL, so the request variable has it. However, is there a way for me to grab this value, and fetch the corresponding club object outside of the post() method? like a pre-post() method or something. Mainly because I don't want to copy/paste club = Club.objects.get(...
A more general question -- in what order do all the methods execute in? Django's documentation on this seems lacking.
This DjangoProject page on Generic Display Views seems to be the most helpful, imo.
It covers both ListView and DetailView and explains in detail the methods executed in a class-based display view -- Here's an example of DetailView methods called:
setup()
dispatch()
http_method_not_allowed()
get_template_names()
get_slug_field()
get_queryset()
get_object()
get_context_object_name()
get_context_data()
get()
render_to_response()
Actually, you're really doing it upside down. Instead of a central ClubView, it's more flexible to have one view class for each of the individual actions/pages. E.g., you might have something like this:
class ClubListView(ListView):
model = Club
class ClubDetailView(DetailView)
model = Club
# etc...
This way you only need to override specific functionality unique to each of those actions, by defining a particular method on the view class which does what you need. E.g. you need to filter the possible Clubs in the ClubListView dynamically, based on something from the request? Just override the ClubListView.get_queryset method to apply the appropriate filter.
If there is some really peculiar behaviour that needs to be applied to all the views, it depends on what this behaviour really is about: if it's related to this specific model, it should probably best be defined in the model itself, or perhaps its manager; and if it's really something specific to the views, you should write and extend a mixin along with the actual view class.
dispatch is called before post - or, for that matter, get depending on the request. Overriding it should let you set extra information.
The docs lack detail - I didn't really get it until I read the source. But the source is nicely readable except for being spread across multiple files.
You could write a get_club method in your parent class. You can then use this in your subclasses, and you don't have to repeat the logic.
Related
I am learning Django out of pure passion and I seem to have trouble understanding some core principles of Django that really give me headackes and i tried searching online and reading the docs but i don't seem to fully understand. I'll just simply shoot the questions and try to be clear . I apologise for anything stupid I say . I am just trying to get my knowledge straight.
1. What is a "request"?
OK, so I am thinking of a GET request for a webpage but online i see python code like self.request.user.is_superuser and i am thinking of an User object fetched and displayed to the template to which i can apply User methods. It is clearly more to this request than i already know.
2. CBV's built in methods. The get methods. How do they execute? In what order.
I noticed programmers override these methods sometime . If i redefine more than one method in a CBV i start getting weird behaviour.
For example if i declare and redefine 2 methods in a Detail View get_object() and get_queryset() which of them will be executed first after calling the view? Being a method it should be called somehow in order to execute but i don't know the order how these methods are called for a CBV if there is more than one. Probably i should only define one of them, not both.
3. Queryset. Is it a list?
I have an ideea what querysets are and that you can apply filters to them but what do they return? Do they return objects of the model i am querying?.
OK so, if i have a DetailView CBV and override the get_queryset() method will this return on object and pass it to my template?. Here I am using a filter but what if am not using a filter. What will the CBV return? Will it return the entire set of objects?
class UserDetailView(LoginRequiredMixin,DetailView):
context_object_name='user_detail'
model=models.User
template_name='basicapp/user_detail.html'
def get_queryset(self, *args, **kwargs):
qs = super().get_queryset(*args, **kwargs)
if not self.request.user.is_superuser:
qs = qs.filter(pk=self.request.user.pk)
return qs
4. Can you kindly recommend a Udemy course, video course or book where querysets, CBV methods and ORM are explained clearly?
Preferably video cause it makes so much difference when i see the code working
The thing is I understood how the MVT mechanism works but these class built in methods and overriding them gives me a lot of problems . I never encountered them before and when i start using them I feel like as if i am walking in the dark .
Sorry for the long post.
Thanks
What is a request?
It is a HttpRequest object [Django-doc]. This is an object that contains data about the request the client made to the server. For example this contains an attribute .method [Django-doc] that contains a string like 'GET', 'POST', 'PATCH', etc. that specifies the request method used.
but online i see python code like self.request.user.is_superuser and I am thinking of an User object fetched and displayed to the template to which I can apply User methods.
One can install middleware [Django-doc], this is tooling that pre-processes the request, or post-processes the response. Normally the AuthenticationMiddleware [Django-doc] is added in the settings.py file by default. This will add an extra attribute .user to the request that lazily loads the user that has been logged in. If you would remove this middleware, the .user attribute will no longer exist.
CBV's built in methods. The get methods. How do they execute? In what order.
That depends on the specific class-based view. The documentation however specifies how most methods are performed. For example for a ListView [Django-doc], the documentation mentions the method flowchart:
Method Flowchart
setup()
dispatch()
http_method_not_allowed()
get_template_names()
get_queryset()
get_context_object_name()
get_context_data()
get()
render_to_response()
It also links to the methods that explain what these are doing.
In essence, each class-based view can have methods like get, post, put, patch, etc. Based on the method of the request, the request is dispatched to the method with the same name.
Queryset. Is it a list?
No. A QuerySet is an object that more or less represents a query that you can perform on the database. QuerySets are lazy. That means that as long as you do not iterate over them or for example call len(…) over these, they will not make that query. If you iterate, etc. over these, they will make a query to the database, and then you iterate over the result of the query. The results are normally wrapped in model objects (unless you use functions like values(…) [Django-doc] or values_list(…) [Django-doc].
Can you kindly recommend a Udemy course, video course or book where querysets, CBV methods and ORM are explained clearly?
It might help to start with the Django tutorials. These go step-by-step over the architecture of Django. The documentation on the QuerySet API explains how you can make querysets. The page on Query expressions gives examples on how to make more advanced queries. Finally the Django documentation also has a page on class-based views.
I am now using Class Based View in my Django application and it helps me a lot to develop faster.
I still have a question about the best way to implement the following:
I have some information in my database I need to always have in almost every template I have (except the template where user is not logged in).
What is the good method to make this using Django ? Is it okay to create a class based view with a custom query in the .get() method?
Thank you :)
There are various different ways to do this.
If you are consistently using class-based views everywhere, you could create a common base class with a custom get_context_data method that adds your specific data to the context dictionary.
But the more usual ways of solving this problem are nothing to do with class-based views, but apply to all sorts of views. They are custom template tags and context processors.
For me, a context processor is probably the best bet: as long as you ensure that your template is rendered with RequestContext (which it will be if you use any view that inherits from TemplateView) then your extra data will always be added to the template context.
I want to add a few drop down boxes for properties of related objects to the list view (or whatever localhost:8000/admin/my_site/my_item is called) but I can't find any way to inline a custom form there.
The best I can do so far is set choices for a field on this object and then percolate them to the sub-objects, but I think there has to be a better way.
Use a Mixin overriding get_context_data, in it load the form and inject it to the context, then override your get method in your view and manipulated the data provided.
I can't provide more since I don't know what exactly is your example.
Being a newb I'm trying to work out what belongs where. I've got a ListView to list all users in the system, and it includes a get_queryset method -something along the lines of:
def get_queryset(self):
users = []
for user in User.objects.all():
a_user = {}
a_user['username'] = user.username
a_user['full_name'] = user.get_full_name()
a_user['num_of_friends'] = len(user.friends.all())
a_user['phone_num'] = user.get_profile().phone_num
a_user['has_subscription'] = bool(Subscription.objects.filter(subscriber=self.request.user))
users.append(a_user)
return users
So rather than returning a queryset of users I'm making this dictionary out of various chosen attributes of each user, and what a template designer gets is limited to only what I think they should have.
Is it better practice to instead pass user objects to the template, and let the template writer get whatever they need from them? I suppose the answer is Yes.
But, when it comes to the a_user['has_subscription'] line above, I assume the answer becomes No?
The way you've done it is totally fine. I've found it to be useful to separate my templates from my model by explicitly providing the information needed by the template in the view, which is essentially what you've done. It's a little bit weird to not be returning an actual queryset from a method called get_queryset, but I've also come to the conclusion based on criticisms like this that class-based views as they are currently implemented in Django should be considered a means to an end, as opposed to a dogmatic way of organizing your view code. The abstraction simply isn't as clean as say, the Django ORM.
If you really wanted something a little slicker, you could try using the values method to narrow your queryset, with an annotation to add in the subscription count. But there's probably not much point.
It depends on what you're trying to do with the array 'users'. Someone editing the template can only style and display the data in a certain way. The get_queryset function can provide the data for the template.
I am working on an app which would enable a preview function for a model. Models marked as preview-able would allow for changes to be made in the Django admin interface and previewed on site using the same view as would an object of that type normally use to render itself, but rendered instead with the new (unsaved) object in it's place.
This is a pretty easy task to do in a bespoke fashion when you know the views or templates ahead of time. But I want this to be reusable and simple.
What I Was Thinking
My idea would be to apply the resolve() urls function to the existing (saved) object's get_absolute_url() value to discover the view used dynamically. Then call that view, get the returned HTTPResponse and alter it in some fashion before returning it myself.
The Problem
It seems that by the time the HTTPResponse is returned by the object's natural view the HTML has already been rendered by the template engine.
So I guess the question is: Is there a way to get at a HTTPResponse before the template is rendered and alter the context variables before that happens.
If not then could the same idea be implemented in another fashion. Would using middleware change anything (your still working with a HTTPResponse object there as well).
Thanks,
Marcus
P.S. If you come up with a radically different methodology to solve this problem, I will be sure to attribute that concept to you in the app documentation (despite it being a small app right now).
It is not trivially possible no, the easiest way would actually be to write your own template context processor that checks for example if something like GET['preview'] is set, then sets dictionary values based on some other GET or POST data. Furthermore when other variables are added it should make sure these don't overwrite the existing values set by this method (otherwise the view would override it anyway with some other data).
One remark however: completely unintrusive behaviour will often lead to erroneous behaviour. If the view does not know of this preview functionality and e.g. it expects a valid id or redirects to an error page, your preview won't work (as you don't really have a valid id). Choosing for views that know of this preview functionality is indeed some more work but will certainly be correct. You could try to make it more generic by using decorators or callable view classes (which can be derivable from some generic base) instead of view methods.
A completely different approach that is only slightly 'view' intrusive, I assume you do not want to save the model so it doesn't show up in public listings. An approach could be to add a 'preview' field and use managers to restrict lookups, so something like this:
class NoPreviewManager(models.Manager):
def get_query_set(self):
return super(MyModelManager, self).get_query_set().filter(preview=False)
class MyModel(models.Model):
... #other fields
preview = models.BooleanField()
objects = NoPreviewManager()
allobjects = models.Manager()
In all normal views you can just use MyModel.objects so previews won't be listed. In the object-specific view you use MyModel.allobjects to also enable defailed views of previews. This way you don't have to do weird view hijacking things, but you should take care preview objects get cleaned up if they aren't promoted to real objects. Note that you can also combine many of this logic into a base class.