Is it advised or redundant to set permissions on the template AND the view?
Consider that any data manipulation to the DB is done through POST
if the following enough for permissions?
{% if perms.system.view_employee %}
<!-- content here -->
{% else %}
<h1>Sorry you do not have permission to access this page<h2>
{% endif %}
or should I also implement server side checking as well (is it redundant to do so or necessary)?
def my_view(request):
if not request.user.has_perm('polls.can_vote'):
return HttpResponse("You can't access this page")
else:
# do stuff
...
Checks in the template are server side.
Permissions checks in the template and in the view do not have the same purpose:
Checking permissions on the view will disallow the access to the entire page. You do this when this page, and the featured it embeds, is for APO. You handle ressources access.
Checking permissions in the template disallow parts of the template to be displayed. You do this when you want people to be able to access the page, but there are some stuff you don't want them to see on the page. You handle display.
In your particular example, you must set the permissions checks on the view to dissallow anybody to do this manipulation. Usually, if the views is accessed using POST their are little chances you want template permission checks because POST requests are actions by essence.
You usually will want template permissions checks if you:
have some parts of the page the person is not allowed to see (like sensitive data)
want to improve usability to show elements (menu, forms, etc) that are relevant only to its level of permission. Indeed it's useless to display a link to the admin in the menu if the person doesn't have the right to access the admin.
Related
I have a field on a Company called leave_approvers which is a ManyToManyField to Users.
The leave_approvers can approve leave of other users in the company they are a leave approver for. They also receive an email when leave is requested.
I would now like to show or hide the Approve Leave tab in the main layout based on whether the user is a leave_approver.
Is the decision to have a leave_approver field flawed as I should be using the built in authorisation or something like django-guardian. Note that I am sending an email to the leave_approvers and that would mean
Can I just make a query in the base.html to check if a user is a leave_approver. How can this be done and surely there is a performance hit?
After consideration making use of django permissions (which are added to the context via a context processor automatically) is the best route in my opinion.
Using something like this in the template:
{% if perms.foo.can_vote %}
However, in my case I cut corners and make a query for all the leave approvers in the base template which is much slower than the prebuilt perms in the context.
{% if user in user.company.leave_approvers.all %}
<li role="separator" class="divider"></li>
<li>Pending Leave Approval</li>
{% endif %}
I have a homepage, which I want to display a login form when user is not logged in or display a list of items belong to that user if he/she already logged in.
So far I came up with 2 methods:
Check whether user is authenticated in views.py and render corresponding view (in my views.py):
if request.user.is_authenticated():
return render(request, 'items.html')
else
return render(request, 'login.html')
Check directly in template and generate corresponding HTML for each case (in my index.html):
{% if user.is_authenticated %}
HTML for my items list
{% else %}
HTML for my login form
{% endif %}
Question
So which method is better for handling this? Are those methods differ much in performance? Is there any standard that we should handling these in views.py or in template itself?
I don't think there is a big performance difference. What's most important is how much you should stick to MVC pattern.
A template is meant to just display some sort of data that the view provides. Any kind of logic like deciding what kind of data to show based on requester's state should always be implemented by the view. Thus, you should move your logic into view function for the cleanness of your design.
TL;DR
Logic should be in your python code, not your template as much as possible. Due to maintenance and future-proof reasons.
Elaborate
Code quality: you can test your business logic when it's in your python not when it's in templates. The former improve your code quality and your value as a developer ;
Future-proof: you don't know which technology your application is going to use in the future, so avoiding tech-mingling will help you when upgrading it (you will be able to upgrade at different pace).
Separation of concerns principles: do you want a code that is a spaghetti plate, where you can't refactor a thing without impacting ten others?
Code legacy: you don't know who is going to work on your code neither which code you're going to work on. Don't make it hard for them (it would probably be your future self) ;
Clean code: that express itself in a single dialect is always better that mixing languages ;
Knowledge scope: front-end is often the responsibility of people with low programming skills (HTML/CSS are declarative) and you don't want them to mess with your business logic.
It depends on your html. If you want to change only a little part of your code based on the condition, check inside a template:
{% if user.is_authenticated %}
<h3>Welcome</h3>
{% else %}
Login
{% endif %}
But if items.html and login.html are different and big templates, you should definitely do the login inside your view.
I'm developing a web application with Django and we have met a dilemma about the design.
We were making one template for every screen, but right now we have detected that some parts of of the screen with the information are repeated all over the different screens. For example, when coming to show personal data of a person, you can show also another data concerning that person, but not personal data (financial data, for instance).
My intuition told me that we should look for a solution in which we could make small templates that we could compose, combine and concatenate and that we should also make different views or functions which would return its own associated template each one.
Thus, person_data() would return the rendered template showing the name, surname, address, etc... and financial_data() would return the rendered template showing the salary, bank account, etc... After that, the desirable thing would be concatenating both or inserting them in a wider template for showing all this together.
<html>
...
{# Html code here #}
...
{# person_data template #}
...
...
{# financial_data template #}
...
{# Html code here #}
...
</html>
So as always I made some research on the net and I found:
https://docs.djangoproject.com/en/dev/ref/templates/builtins/#include
a link which describes how to use include for inserting a template file in another template:
{% include "foo/bar.html" %}
And you can also use a variable from the python function with the path name or an object with render method:
{% include template_name %}
So we could use all this in this way for combining, concatenating, composing and operating on templates. We could choose the one which includes the others and passing it the context for all templates (I suppose, I didn't test anything). But I don't know if I'm well directed or if this is the best way to go. I would appreciate some advice.
I also found another interesting thread in stackoverflow talking about this:
How do you insert a template into another template?
My idea is to have small templates which are used repeatedly in different spots of the web and composing them in Unix-like style, so I would have small visual pieces that would be used once and again saving a lot of hours of writing of code.
Please some advice.
Thanks in advance
Yes, that is a correct approach. I think the best solution is to combine {% include %} and {% extend %}, which will allow you to inherit from a base template (via extend), and include parts you want from other templates (via include).
You'd end up having a base template, a template for the header, the footer, parts of the body etc.
You might also want to read more about it here and here
I have a website running Django whose main domain is example.com. What I want to achieve is to behave in a different way when an user access from example2.com (specifically loading custom CSS).
I understand that I have to make some changes to the web server and that is not a problem. My question is focused on how to accomplish this with Django.
There is something called Django sites that could be useful for this, but I am not sure if this is an overkilling feature for such a "simple" thing. However I am aware that multiple changes would be needed (paths, cookies domain, etc), so... is this the recommended way to do it?
It's a pretty simple thing to accomplish. You have a few different options.
Checking the HTTP_HOST straight from a template
A very simple approach would be from a template to check the request.META dictionary's value for the HTTP_HOST key.
{# Anything other than port 80, HTTP_HOST will also include the port number as well #}
{% ifequal request.META.HTTP_HOST 'example2.com' %}
<!-- your css imports here -->
{% endifequal %}
Remember, this is set by the client though, so if you were doing anything else that was security-sensitive, this would NOT be the approach to use. Just for loading some CSS though, it would be fine.
Custom middleware
Another option would be to create custom middleware and check this same object from there. Basically the same process but you'd probably want to do something like set an extra key on the request object
In some file.. yourproject/someapp/middlware.py
class DomainCheckMiddleware(object):
def process_request(self, request):
if request.META['HTTP_HOST'] == "example2.com":
request.IS_EXAMPLE2 = True
else:
request.IS_EXAMPLE2 = False
return None
In your settings.py
MIDDLEWARE_CLASSES = (
# whatever middleware you're already loading
# note: your middleware MUST exist in a package that's part of the INSTALLED_APPS
'yourproject.someapp.DomainCheckMiddleware'
)
In your template
{% if request.IS_EXAMPLE2 %}
<!-- load your css here -->
{% endif %}
This is more legwork, and pretty much does the same thing, but you could easily apply some extra tests to see if you're in debug mode or just accessing over localhost:8000 and still set IS_EXAMPLE2 to true, without making your templates more difficult to read.
This also has the same downfall mentioned previously.
https://docs.djangoproject.com/en/dev/topics/http/middleware/
Using the sites framework
Using the sites framework is only valid if you have enabled it (django.contrib.sites) enabled, which it no longer is by default and is overkill for your purposes. You can see an example of how that would work from this answer though:
How can I get the domain name of my site within a Django template?
We have a large Django application made up of a large number of different views (some of which contain forms). As with most large applications, we use a base layout template that contains the common layout elements across the applications (mainly a header and a footer), which the templates for all of our views extend.
What we are looking to do is create a universal search box in our application, accessible on every page, which allows users to perform searches across the entire application, and want to place the search box inside the header, which involves placing a form inside our base layout template. This means that every view in our application will need to be able to handle the submission of this search form. Once this search form is submitted, we will need to redirect the user to another view containing the search results.
However, we are struggling to come up with a pattern to handle this. Does anyone know of functionality built into Django that will help us to build this? Failing that, can anyone suggest a good strategy for modifying our application so that we can handle this use-case without having to modify a large number of existing views (which we don't have the resources to do at the moment)?
Please note that the focus of this question is intended to be the best way to handle the submission of a form which appears in every view, and not strategies for implementing a universal search algorithm (which we have already figured out).
Ideas Explored So Far
Our first idea was to create a base View class that implements handling the universal search form submission, and have each of our views extend this. However, this is not possible because we already have views that inherit from a number of different Django view classes (TemplateView, ListView, FormView and DeleteView being some examples), and to be able to build our own common view class would mean either writing our own version of these Django view classes to inherit from our own view base class, or re-writing a large number of our views so they don't use the Django view classes.
Our next idea was to implement a mixin that would handle the universal search form submission, in an attempt to add this functionality to all our views in a way that allows us to continue using the different Django view classes. However, this brought to light two new problems: (a) how could we do this without modifying each of our views to become a form view, and (b) how can we do this in a way that allows the form handling logic to play nicely when mixed in to existing FormViews?
This seems like such an obvious question that maybe I'm overlooking something. But as others have said your universal search form should not make a POST request to the view that rendered the current page.
Each html form has an action attribute. The attribute of your search form should point towards an URL. Probably something like /search. That url would have a view behind it that handled the POST request from the form and returned the search results. Django has URL template tags to make this easy. {% url 'myapp.views.search' %} will give you the correct url for the search view function if it lived inside the views module in myapp. So the relevant bit of html in your base template would be something like:
<form action="{% url 'myapp.views.search' %}">
<input type="text" name="qs" placeholder="Search">
</form>
If you are planning on displaying the search results on a new page there is absolutely no need to return JSON or anything like that. Just have a search view that looks like this
def search(request):
query = request.POST.get('qs', '')
results = SomeModel.objects.filter(name=query) # Your search algo goes here
return render(request, 'search_results.html', dict(results=results))
Instead of handling the form submission on every view of the application, you can implement a separate view (endpoint), which handles all the search queries. (an endpoint which returns JSON result) since you dont want to add overhead of rendering the whole page with that view. So the search query (which client side AJAX performs to the webserver) will return JSON response, and the Javascript can render that response. This way you can keep the search view isolated from the rest of the views. (Django REST will be helpful in this case)
And this search form will be included in your base template, so your search box is accessible from the entire application, and it submits to the same view. And the AJAX function will handle the server response for rendering it.
It seems like you just need to create another SearchView which takes the query and displays the results. I am not sure if the results have to be displayed differently depending on which page the search has been performed from but it does not seem like.
The form would not have anything to do with the other views. You could just hard code it in the base template.