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.
Related
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'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.
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.
My situation is as follows.
I have a django app that is a CMS, and this one app generates page content and menus.
There is 'default' view that generates all the page content. One of the fields of the main model is designed to limit the visibility of pages depending on the setting:
'internal' (limited to users on our network),
'worldwide' (viewable by the www) and now, I would like to add an extra value
'secure', which would limit viewing only to those who are logged in to the site.
I dont think #login_required would work, as it only works on whole functions.
We want the author or editor to be able to set this flag, rather than code a special function; and there will be instances where a page migrates from 'internal' to 'secure' then to 'worldwide' - so ideally the urls should stay the same.
What is the best way to go about this?
thanks in advance... patrick
As you want the flag set on your object, I'm assuming that flag can't be read until you're already within the view (i.e. you won't be storing it in something accessible by the request object, like a session), so that precludes custom decorators. You could choose to go with something a bit crude but workable like this:
if (val=="internal" and inrange(request.META['REMOTE_ADDR'])) or (val=="secure" and request.user.is_authenticated()) or val=="worldwide":
return render_to_response .... etc.
else:
return HttpResponseForbidden()
Substituting your model values, and writing the inrange function, naturally.
The more sophisticated approach, though, would be to write custom middleware and use the process_view() function. See the docs for more details.
While I am studying the new django docs on class-based views, I notice this example code:
# forms.py
from django import forms
class ContactForm(forms.Form):
name = forms.CharField()
message = forms.CharField(widget=forms.Textarea)
def send_email(self):
# send email using the self.cleaned_data dictionary
pass
The fact of seeing send_email as a method of ContactForm really annoys me. I have always thought form methods should be for validation purpose and methods that consume forms (like send_email in this case) should be in the views layer. Am I missing anything here? Or should the example be corrected?
There is no correct answer for this one. It really depends on your coding style. Using a form for more than just validation is as valid as doing this method in the view.
The above example has some kind of advantage though. Lets say you have one model and you want to use different forms (with different logic) for it. Instead of putting the logic in the view and check which form is now used it probably better to put this logic on the form level.
The first time I got the same weird feeling was when I encountered the LoginForm from django.contrib.auth that also verifies that the user's browser is capable of working with cookies aside from managing the credentials passed in.
Personally, I agree with you. I'm more inclined to think that the view should be the responsible actor for performing the action of sending the email rather than the form and that send_email should be a method defined in the view.
But, then again, you can easily observe how a lot of us use Django differently or have a different approach to solving the same problems. Due to the fact that we have different concerns in mind when developing our applications, it's quite possible we have a different understanding of how certain framework components are meant to be used, which is a bit of a moot point. In the end, what's important to acknowledge is that it's possible to delegate some of the heavy-lifting from the view to the form in a manner that's well-defined.
There is nothing wrong with the example. For any but the simplest of cases, your form will contain only cleaning methods; most forms do extra validation and other actions. In the end, it is just a Python class and you can do whatever you would like in it; there is no "rule" except maybe DRY.
We have form methods that validate against external services, call other procedures and trigger workflows. For such complicated logic, it is best to embed it in to the form class as it increases reusability of the code. Developers working on the view simply use the form class as a library and don't have to worry about exotic validation requirements. In this case, it actually promotes DRY.
When we have to update the logic we only update the form class's "private" methods (those prefixed with _). This keeps the "public" interface (documented by django) intact and all view code using that form doesn't have to be updated.