How to pass user instance to a view in Django - django

I am making a blog app where I want to make a view that displays all the blogs of a particular user. For this I need to pass the user instance to my view as
def blogs(request,author=None,slug=None):
# If the author context has been passed then display the blogs of that author
if author:
# Displays a particular blog
if slug:
this_blog = get_object_or_404(Entry, creator = author, slug = slug)
return render_to_response('blog/blog_view.html', {'blog': this_blog,},context_instance=RequestContext(request))
# Displays all the blogs of a particular user
else:
blog_list = Entry.objects.filter(creator = author)
return render_to_response('blog/all_blogs_user.html', {'Blogs': blog_list},context_instance=RequestContext(request))
Although syntactically this is correct but now I do not how to actually pass this user context in my url. Earlier I tried passing just the user id but that does not work. Is there any other alternative to doing this thing. When I am building the url internally or redirecting to this particular view then it is fine, but how would the url look like externally. My urls.py is as
from django.conf.urls.defaults import patterns, include, url
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
from django.views.generic.simple import direct_to_template
urlpatterns = patterns('',
url(r'^$', 'blog.views.blogs', name='all_blogs'),
url(r'^(?P<author>\d+)/(?P<slug>[-\w]+)/$', 'blog.views.blogs', name='view_blog'),
url(r'^(?P<author>\d+)/(?P<slug>[-\w]+)/edit/$', 'blog.views.post_form', name='edit_blog'),
url(r'^new/$', 'blog.views.post_form', name='new_blog'),
url(r'^(?P<author>\d+)/(?P<slug>[-\w]+)/delete/$', 'blog.views.delete_blog', name='delete_blog'),
)
urlpatterns += staticfiles_urlpatterns()

It generally works like this:
urls.py
url(r'/author/(?P<slug>/$', 'author_index'),
views.py
def author_index(request, slug):
author = get_object_or_404(User, username=slug)
return render_to_response('author_index.html', {
'author': author,
}, context_instance=RequestContext(request))

You can simply access the user in the view by request.user. Similarly, you can POST data in the request object as well.

Related

Django Class-based Views - ListView if User Is Authenticated, FormView if User is Not, Same URL

When a visitor is logged out and visits my homepage, I want them to see a registration form. When the user logs in, they will be redirected back to the homepage, but it will show a listview-like view.
Is the best way to achieve this to subclass both ListView and FormView and override each method necessary to get the behavior I want? Or is there a better way? Checking if the user is authenticated in each method doesn't seem like the Django way to do this. Hoping there's a smart design pattern approach for doing this that I don't know about.
class HomepageView(ListView, FormView):
def get_template_names(self):
if self.request.user.is_authenticated:
return ['homepage/loggedin_index.html']
else:
return ['homepage/loggedout_index.html']
def get_context_data(self, **kwargs):
if self.request.user.is_authenticated:
...
else:
...
def ... and so on
My must-have requirement is that the URL for both logged-in and logged-out users must resolve to the root URL since it's a homepage.
from django.urls import path
from .views import HomepageView
app_name = 'homepage'
urlpatterns = [
path('', HomepageView.as_view(), name='index'),
]
There is also a CreateListView that do what you want. And then you can change its form to the one you want.

Page not found (404) Request Method: POST Request URL:http://127.0.0.1:8000/reg_done

from django.contrib import admin
from django.urls import path
from . import views
urlpatterns = [
path('', views.Index, name='Index'),
path('register/', views.register, name='register'),
path('login/', views.login, name='login'),
path('register/reg_done/', views.reg_done,),
]
Above is my urls.py. What I am trying is to get my reg_done page come up as after a user click on the submit button to save the regestration info. But its showing that this page not found.
I tried to change the path in form action as register/reg_done/. But then it showed the same error with register/register/reg_done.
In HTML I am giving form action the value"/reg_done", that's it.
Below is my views.py
from django.shortcuts import render
from django.http import HttpResponse
import sqlite3
# Create your views here.
def Index(request):
return render(request, 'index.html')
def register(request):
return render(request, 'register.html')
def login(request):
return render(request, 'login.html')
def reg_done(request):
name = request.POST.get('name')
mail = request.POST.get('mail')
phone = request.POST.get('phone')
psw = request.POST.get('psw')
pswr = request.POST.get('pswr')
all = [name, mail, phone, psw, pswr]
return render(request, 'reg_done.html', {'all':all})
I assume the register view handles the registration. In the form for the register.html file,
Do:
<form action="/register/reg_done" method="post">
your form fields here
</form>
if you want to go with pure HTML solution. If you want something more Django-ly, use the url template tag:
<form action="{% url 'reg_done' %}" method="post">
your form fields here
</form>
I'll advice the later to ensure you avoid "premium developer tears".
In views.py, add this to the top of the file:
from django.views.decorators.http import require_POST
Then edit the reg_done view to:
#require_POST
def reg_done(request):
name = request.POST.get('name')
mail = request.POST.get('mail')
phone = request.POST.get('phone')
psw = request.POST.get('psw')
pswr = request.POST.get('pswr')
all = [name, mail, phone, psw, pswr]
return render(request, 'reg_done.html', {'all':all})
Next, change the path for reg_done in urls.py to:
path('register/reg_done/', views.reg_done, name='reg_done'),
The problem lies in your usage of urls. You should reference the reg_done view as /register/reg_done instead of register/reg_done. The former treats it as an url relative to the domain name while the latter treats it as relative to the current page. That's why coming from the register view and going to the latter yields register/register/reg_done rather than what you want: register/reg_done.

How to redirect login urls depending on if the user is admin or not in Django?

I'm still new to Django. I have an admin user and a regular user who is not an admin. When admin login he should be redirected to '/admin_section' & when a regular user login he should be redirected to the '/' front page. Beyond that, it should be possible for an admin to be able to navigate to the '/' front page and see the page as a regular user can see.
I've been trying to search for an answer for this and the only thing I find is that I can use request.user.is_superuser in a view and ask whether the user is a superuser/admin or not. But the problem then becomes that admin will not have the ability to navigate to the front page ever. I have also set the login_redirect_url to "LOGIN_REDIRECT_URL = '/'" which means everytime a user login they will be redirected to the frontpage - but it should not be like that.
Here is my code so far (from the views.py file):
def home(request):
# if the user is not logged-in, show the loginpage
if not request.user.is_authenticated:
return HttpResponseRedirect('login')
# if the user is logged-in, show the frontpage
return render(request, 'mainapp/index.html')
# return the view for the admin section
def admin(request):
# if the user is logged-in & is an admin - show the admin section
if request.user.is_authenticated and request.user.is_superuser:
return render(request, 'mainapp/admin.html')
return redirect('home') # redirects to the home view
forms.py:
from django.contrib.auth.forms import AuthenticationForm
from django import forms
from django.contrib.auth import logout
from django.contrib.auth.mixins import LoginRequiredMixin, AccessMixin
# a class which act as a view - it displays the login-form
class LoginForm(AuthenticationForm, AccessMixin):
username=forms.CharField(widget=forms.TextInput(attrs={'class':'form-control'}))
password=forms.CharField(widget=forms.PasswordInput(attrs={'class':'form-control'}))
urls.py:
path('login/', views_auth.LoginView.as_view(form_class=LoginForm, redirect_authenticated_user=True), name='login'), # login-page
Create your login view inherited from the built-in login view and override the get_success_url method according to your logic.
from django.contrib.auth import views as views_auth
class LoginView(views_auth.LoginView):
form_class = LoginForm
redirect_authenticated_user = True
def get_success_url(self):
# write your logic here
if self.request.user.is_superuser:
return '/admin_section'
return '/'
urls.py
urlpatterns = [
path('login/', LoginView.as_view(), name='login'),
]
Provide the newly created view as the login URL in the settings file.
settings.py
LOGIN_URL = 'login'

Django - how to implement an example.com/username url system

I am trying to implement on my website a simple and friendly address system.
What i'm thinking about is when the user logged in, his username will be displayed in the address bar.
www.example.com/username1 (for home page profile)
www.example.com/username1/about/
www.example.com/username1/gallery/
www.example.com/username2 (for home page profile)
www.example.com/username2/about/
www.example.com/username2/gallery/
And additionally if anyone enter the address www.example.com/username1, will be shown the profile of user1.
I already implemented a register/Login system using Django-Allauth
mySite/urls.py
url(r'^accounts/', include('allauth.urls')),
home/urls.py
url(r'^$', views.index),
home/views.py
def index(request):
return render_to_response('home/index.html', context_instance=RequestContext(request))
I tried to follow some examples like Facing problem with user profile url scheme like example.com/username in django
But i dont have this thing working yet. I dont understand what to do :(
Please, give some advise.
Add the following url as the last item of the mySite/urls.py:
urlpatterns = patterns('',
...
url(r'^(?P<username>\w+)/', include('userapp.urls')),
)
Then the username parameter will be passed to the views of your userapp:
userapp/urls.py:
from userapp import views
urlpatterns = patterns('',
url(r'^$', views.profile, name='user_profile'),
url(r'^about/$', views.about, name='user_about'),
url(r'^gallery/$', views.gallery, name='user_gallery'),
)
userapp/views.py:
def profile(request, username):
user = get_object_or_404(User, username=username)
return render(request, 'userapp/profile.html', {'profile_user': user})
def about(request, username):
...
def gallery(request, username):
...
It's almost perfect, but i have a bug. Let me explain. When i login (my login system is: django-allauth) on the http://127.0.0.1:8000/accounts/login/ i return to http://127.0.0.1:8000 with an error 404.
I am not getting the http://127.0.0.1:8000/username/ with the template, when the login botton is clicked.
The instalation of django-allauth require adding to the settings.py
LOGIN_REDIRECT_URL = '/'
How can i redirect to http://127.0.0.1:8000/username/ and show the correct template?
1. Regarding
How can i redirect to
Based on the answer from https://stackoverflow.com/a/20143515/4992248
# settings.py:
ACCOUNT_ADAPTER = 'project.your_app.allauth.AccountAdapter'
# project/your_app/allauth.py:
from allauth.account.adapter import DefaultAccountAdapter
class AccountAdapter(DefaultAccountAdapter):
def get_login_redirect_url(self, request):
return 'request.user.username' # probably also needs to add slash(s)
Would be better to use get_absolute_url, ie return 'request.user.get_absolute_url'. In this case you need to do:
# 1. Add `namespace` to `yoursite/urls.py`
urlpatterns = patterns('',
...
url(r'^(?P<username>\w+)/', include('userapp.urls', namespace='profiles_username')),
)
# 2. Add the code below to the Users class in models.py
def get_absolute_url(self):
# 'user_profile' is from the code shown by catavaran above
return reverse('profiles_username:user_profile', args=[self.username])
2. Regarding
show the correct template
catavaran wrote correct urls which leads to views.profile, so in view.py you need to write:
from django.shortcuts import render
from .models import UserProfile # import model, where username field exists
from .forms import UserProfileForm # import Users form
def profiles(request, username):
user = get_object_or_404(UserProfile, username=username)
return render(request, 'home/profiles.html', {'user_profile_form': user})
In template (i.e. profiles.html) you can show user's data via {{user_profile_form.as_p}}

Django view doesn't display model value - Django 1.5

I created a very simple example code using Django, but cannot get model value to be displayed on my page:
----------------------------- home/models.py
from django.db import models
class Home(models.Model):
msg = models.CharField(max_length=100)
#classmethod
def create(cls, msg):
home = cls(msg=msg)
# do something with the book
return home
home = Home.create("Hello World!")
------------------------------------home/views.py
from django.views.generic import TemplateView
from project.models import Home
class IndexView(TemplateView):
model = Home
template_name = 'home/index.html'
------------------------------------------ templates/home/index.html
{{ home.msg }}
this is a test page. I am expecting to see this....
------------------------------------------- urls.py
from django.conf.urls.defaults import patterns, include, url
from django.contrib import admin
from django.views.generic import TemplateView
admin.autodiscover()
urlpatterns = patterns('',
# Home pagetentacl.urls
url(r'^$', TemplateView.as_view(template_name='home/index.html')),
# Uncomment the admin/doc line below to enable admin documentation:
# url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
# Uncomment the next line to enable the admin:
url(r'^admin/', include(admin.site.urls)),
)
-------------------------------------- result page on browser:
this is a test page. I am expecting to see this....
I don't want to have DB access for my example. I want my model returns "hello world" string. home.msg on index.html doesn't return anything. What is missing here?
You're not giving the template an instance of Home. You need to create one and pass it to the template as a Context, in the form {'msg': msg}.
EDIT: Adding some code
First of all, you should create your instance of home in your view. I've never used TemplateViews, so I'm going to use a regular view method instead.
def IndexView(request):
home=Home.create("Hello World!")
return render(request, 'index.html', {'home': home},)
As #Daniel rightly points out, you're not giving your template an instance of Home to work with.
If you want to use class-based views, subclass TemplateView and override get_context_data():
class IndexView(TemplateView):
template_name = "home/index.html"
def get_context_data(self, **kwargs):
context = super(HomePageView, self).get_context_data(**kwargs)
context["home"] = Home.create("Hello World!")
return context
And make sure your urls.py is using IndexView.as_view() - your version above is just referencing the generic TemplateView.
The fact that you added a model field to your subclass of TemplateView makes me think you're confusing it with DetailView. See the documentation for the difference.