Adding start separate page in django app - python

I want to add a separate homepage in my Django app.
If a user is logged in to show him all the content.
If the user is not logged in to show him the starting page and a link to login.
The solution is based on the code below does not always pass the exam.
{% if user.is_authenticated %}
//Something
{% else %}
//Something
{% endif %}
My view:
class Start(TemplateView):
template_name = "dashboard/start.html"

You can override the get_template_names() method of the view and render different templates for anonymous and logged users:
class Start(TemplateView):
def get_template_names(self):
if self.request.user.is_authenticated():
return ['dashboard/dashboard.html']
return ['dashboard/start.html']

Related

How to call a verification function from views to templates?

I have a function to check if the user is a staff:
class VerificateUser():
def allowed_user(request):
if request.user.is_staff:
return True
In my template, I’m going to show this section only for staff users, but this is not working.
{% url if not allowed_user %}
<h1>
Welcome to the show
</h1>
If do something like it, works:
```html
{% if not request.user.is_staff %}
<h1>
Welcome to the show
</h1>
But I need to use a view function to clean my code because I’m probably going to add more conditionals.
Since you are using a class-based view then I would suggest updating the context dictionary which you could use in the html template to determine whether the user is allowed or not. For example, Within the views.py.
class VerificateUser():
# Update the context
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# Call the allowed_user() and return whatever value, passing that value it to the context variable
context['allowed_user'] = self.allowed_user()
return context
# Checking if the user is allowed here
def allowed_user():
if self.request.user.is_staff:
return True
return False
Now within the html file, you can reference that allowed_user from the context variable.
{% if allowed_user %}
<h1>Hi, you are allowed to see here...</h1>
{% endif %}
That should do the trick.
You can do this sort of thing in many ways, but simply you can do by the following way-
{% if request.user.is_authenticated %}
<p>Welcome,{{request.user.first_name}} </p>
{% endif %}
request object is by default available in all of your Django templates context.

In Django, how do I restrict is_staff member to access a URL?

In my web, user and admin user both login from frontend. Now I want to do that some of URLs are accessed by public user only. Is_staff user not access that URL. How do I do that?
Updated:
Can I use any decorator for this?
If you want to use a decorator, you can use the user_passes_test. First define a test function that checks that the user is not a staff member.
def is_not_staff(user):
return not user.is_staff
You can change the function to check user.is_authenticated (user.is_authenticated() in Django <=1.9) as well, if you don't want anonymous users to be able to access the view.
Then use user_passes_test with your test function to decorate the view you wish to protect.
#user_passes_test(is_not_staff)
def non_staff_view(request):
...
You can simply inherit LoginRequiredMixin and create your own custom access mixin as below:
class AccessMixin(LoginRequiredMixin):
def dispatch(self, request, *args, **kwargs):
if not request.user.is_authenticated or request.user.is_staff:
return self.handle_no_permission()
return super().dispatch(request, *args, **kwargs)
Now you just need to inherit AccessMixin in your view as below:
class HomePageView(AccessMixin, TemplateView):
login_url = <login-url>
...
...
So anonymous user and staff user won't be able to access the content of the page.
You can also mention the same in your base template html
Consider you have created a base.html which extends content block and you can add permission as below:
Ex.
base.html
{% if user.is_authenticated %}
{% if user.is_staff %}
<h3>Not allowed to access this page</h3>
{% else %}
{% block content %} {% endblock %}
{% endif %}
{% endif %}
this way when you extend base.html in your template all the content you write within {% block content %} {% endblock %} will only be rendered for non-staff logged in user.

How would you setup a "context" type object in django

In Rails if I want to setup a "context" which is basically objects that every view will need like the user object for a logged in user, or say a store/account/location object, how would I have this available on every view in the django framework?
In Rails I would do something like this:
class BaseController
before_action :setup_context
def setup_user
#user = # load user from db
#location = # load location for user
end
end
class HomeController < BaseController
def index
# I now can use the variables #user and #location
end
end
Does Django have these types of events that I can load objects and use them in all my views?
You can write your own context processor:
Study :
https://docs.djangoproject.com/en/dev/ref/templates/api/#writing-your-own-context-processors
http://www.b-list.org/weblog/2006/jun/14/django-tips-template-context-processors/
If I understand your question correctly, I think you're trying to do something like this. I'm still fairly inexperienced with Django myself, so take this with a grain of salt.
Basic example:
views.py
from django.shortcuts import render
from exampleapp.models import User # User object defined in your models.py
def index(request):
context = { 'users': User.objects.all() }
return render(request, 'exampleapp/example.html', context)
example.html
{% if users %}
{% for user in users %}
<p>{{ user.name }}</p>
{% endfor %}
{% else %}
<p>No users.</p>
{% endif %}
My apologies if I've missed the mark on your question.

Separate admin page for one-to-many objects

I have the following model:
class Campaign:
...
class Location:
...
campaign = models.ForeignKey(Campaign)
I normally would edit the locations using a tabular inline, but because the number of Locations is very high I would like to move the management of the locations to another page. It should pretty much do the same as normal Admin page, except it should only display Locations for the selected campaign and when adding a new Location, it should be automatically attached to the right Campaign. To access the Location Admin page a link in the Campaigns list should be clicked.
What would be the right way to do this? Are there other options?
There is no out of the box solution for your problem, but it is pretty easy to do.
I would register Locations as a separate model admin object like this:
from django.contrib import admin
from models import Location
class LocationAdmin(EnhancedModelAdminMixin, admin.ModelAdmin):
list_filter = 'campaign',
admin.site.register(Location, LocationAdmin)
This way you will have admin interface where you can filter your locations by campaigns.
To have a direct access to Location on Campaign model admin I would use https://github.com/charettes/django-admin-enhancer
Auto selecting a filtered campaign on new Location create form it is a bit more trickier... But my approach would be to add a query parameter to Add new Location button and then catch it when initializing create form, to define initial value of field campaign.
First of all create a template on let's say your_app/admin/change_list.html, which looks like this:
{% extends "admin/change_list.html" %}
{% load i18n admin_static admin_list %}
{% load admin_urls %}
{% block object-tools %}
{% if has_add_permission %}
<ul class="object-tools">
{% block object-tools-items %}
<li>
<a href="{% url cl.opts|admin_urlname:'add' %}{% if is_popup %}?_popup=1{% if selected_campaign %}&selected_campaign={{ selected_campaign }}{% endif %}
{% elif selected_campaign %}?selected_campaign={{ selected_campaign }}{% endif %}"
class="addlink">
{% blocktrans with cl.opts.verbose_name as name %}Add {{ name }}{% endblocktrans %}
</a>
</li>
{% endblock %}
</ul>
{% endif %}
{% endblock %}
Then append your LocationAdmin class to look like this:
class LocationAdmin(EnhancedModelAdminMixin, admin.ModelAdmin):
list_filter = 'campaign',
list_display = 'location_name', 'campaign'
change_list_template = 'your_app/admin/change_list.html'
def changelist_view(self, request, extra_context=None):
if 'campaign__id__exact' in getattr(request, request.method):
selected_campaign = getattr(request, request.method)['campaign__id__exact']
if not extra_context:
extra_context = {'selected_campaign': selected_campaign}
else:
extra_context['selected_campaign'] = selected_campaign
return super(LocationAdmin, self).changelist_view(request, extra_context)
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == 'campaign':
if 'selected_campaign' in getattr(request, request.method):
kwargs['initial'] = getattr(request, request.method)['selected_campaign']
return db_field.formfield(**kwargs)
return super(LocationAdmin, self).formfield_for_foreignkey(
db_field, request, **kwargs
)
So what we are doing here is we are overriding modeladmins changelist_view function just to add additional context variable of current 'selected_campaign'.
Then we adding it as a query parameter on Add new Location button.
Finaly we are using model admins formfield_for_foreignkey function to dynamically define initial value of campaign field based on parameter received with request when user clicks on Add new location.
Cheers! Do not forget to up-vote this answer if you feel it was helpful ;)

user auth template tags not working-Django

I used django-registration app. Everything goes fine. User gets registered with email verification but when user logs in and is redirected to mainpage the auth template tags such as {% if user.is_authenticated %} returns false.
I am having this in my login.html
<input type="hidden" name="next" value="/" />
After login I want to redirect the user to main page and in mainpage.html
{% if user.is_authenticated %}
<p>Welcome, {{ user.username }}. Thanks for logging in.</p>
{% else %}
<p>Welcome, new user. Please log in.</p>
{% endif %}
but user.is_authenticated returns false here. What might be the problem here? Thanks
Try using {% if request.user.is_authenticated %} instead. It's entirely possible that user isn't being passed into the context dictionary within the view. If the object is not found within the template, it will just skip to the else portion of the block. Rendering templates are strange in django, as what would normally be an exception, is swallowed.
Can you show us the code for the view which handles the URL '/'? I think this is where your problem lies, rather than in your use of django-registration.
Does this view put user in the context? If you want to use it in the template, you're going to have to put it in. If you want to use request in the context, then you need to make sure that you pass an instance of RequestContext as the context rather than just a standard context object.
Here's what worked for me.
Suppose your main page gets processed by a view in views.py
from django.shortcuts import render_to_response
def mainpage(request):
return render_to_response('mainpage.html')
You need to add RequestContext to include to user object. Change your view to
from django.shortcuts import render_to_response
from django.template import RequestContext
def mainpage(request):
return render_to_response('mainpage.html', context_instance=RequestContext(request))

Categories

Resources