I am running: Django==2.0.6 / python==3.6.5 / django-allauth==0.36.0
I have not touched this project in several weeks. I upgraded a number of packages before starting this round of development.
I can currently create a new user account and verify the email address used as the username. The user model is "extended" in that I use the email address for the username and have a "Profile" class to hold additional interesting fields.
I was once able to create a new account, verify the email address and be taken to a form to fill out that additional interesting info. Now, after email verification there is a noticable pause and then I am told that I have ben redirected too many times.
My urls.py looks like:
from django.urls import path, re_path
from .views import index
from .views import profile
urlpatterns = [
re_path(r'^', index, name='index'),
path('Profile/<uuid:account_number>/edit', profile.Update.as_view(), name="profile-update"),
path('Profile/<uuid:account_number>/delete', profile.Delete.as_view(), name="profile-delete"),
path('Profile/create', profile.Create.as_view(), name="profile-create"),
]
The Profile CBV is:
import django.contrib.messages as messages
from allauth.account.decorators import verified_email_required
from django.contrib.auth.models import User
from django.shortcuts import get_object_or_404
from django.shortcuts import redirect
from django.shortcuts import render
from django.utils.decorators import method_decorator
from django.views.generic import CreateView, UpdateView, DeleteView
from Members.forms.profile import ProfileForm
from Members.models.profile import Profile
import datetime
#method_decorator(verified_email_required, name='dispatch')
class Create(CreateView):
model = Profile
template_name = 'Members/profile.html'
form_class = ProfileForm
success_url = 'Members/index.html'
def get(self, request, *args, **kwargs):
return render(request, self.template_name, {
'profileForm': self.form_class(),
'profileState': "create"
})
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
profile = form.save(commit=False)
profile.user = self.request.user
profile.save()
my_render = render(request, self.success_url, {
'profile': profile,
'profileState': "display"
})
else:
#
# form has issues. send it back to the create form to fix.
my_render = render(request, self.template_name, {
'profileForm': form,
'profileState': "editForCreate"
})
return my_render
#method_decorator(verified_email_required, name='dispatch')
class Update(UpdateView):
pk_url_kwarg = "account_number"
model = Profile
template_name = 'Members/profile.html'
form_class = ProfileForm
success_url = 'Members/index.html'
def get(self, request, *args, **kwargs):
profile = Profile.objects.get(account_number=self.kwargs[self.pk_url_kwarg])
form = ProfileForm(instance=profile)
return render(request, self.template_name, {
'profileForm': form,
'profileState': "edit"
})
def post(self, request, *args, **kwargs):
profile = Profile.objects.get(account_number=self.kwargs[self.pk_url_kwarg])
form = ProfileForm(request.POST, instance=profile)
if form.is_valid():
profile = form.save(commit=False)
profile.user = request.user
profile.dateModified = datetime.datetime.now()
profile.save()
my_render = render(request, 'Members/index.html', {
'profile': profile
})
else:
#
# form has issues. send it back to the create form to fix.
my_render = render(request, self.template_name, {
'profileForm': form,
'profileState': "editForUpdate"
})
return my_render
#method_decorator(verified_email_required, name='dispatch')
class Delete(DeleteView):
pk_url_kwarg = "account_number"
model = Profile
# form_class = ProfileForm
success_url = "account/login.html"
def get(self, request, *args, **kwargs):
try:
#
# I can't believe django does not honor on_delete cascade.
# Have to roll your own. Tsk
owner = self.request.user
profile = get_object_or_404(Profile, account_number=self.kwargs[self.pk_url_kwarg])
user_pk = profile.user.pk
profile.delete()
get_object_or_404(User, pk=user_pk).delete()
messages.success(request, "The user is deleted")
except User.DoesNotExist:
messages.error(request, "User does not exist")
# except IntegrityError:
# messages.error(request, "DB IntegrityError")
return redirect("accounts/login/")
How do you go about debugging this? Ive tried setting breakpoints in PyCharm but they are ignored or ar in the wrong places.
in your urls.py you need to add $ in order to close your regular expression
urlpatterns = [
re_path(r'^$', index, name='index'),
]
Related
How would one go about creating a user-profile page that other users can view without being able to edit the profile unless they are the user?
The thing I'm trying to work out is how the url routing would work, is it best practice to store a user's profile on a profile/ or <user_id> page and then load in the individual user's data like recent posts using the username or id passed through the url?
Also would this be handled by the one view and template and just use {% if request.user == profile.user %} to display things like edit profile etc?
my problem is any user can edit for others there profiles when he edit url
for example my id is www.test.com/profile/44/ and other user have this id www.test.com/profile/40/
okay ,, now when i edit the link to be 40 not 44 i can access and edit the second user ! how to fix that
models.py :
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
email_confirmed = models.BooleanField(default=False)
#receiver(post_save, sender=User)
def update_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
instance.profile.save()
def __str__(self):
return self.user
urls.py :
from django.urls import path
from blog_app.views import ProfileView
urlpatterns = [
path('profile/<int:pk>/', ProfileView.as_view(), name='profile'),
]
forms.py :
# Profile Form
class ProfileForm(forms.ModelForm):
# constructor of the UserForm, not Meta
def __init__(self, *args, **kwargs):
super().__init__(*args,**kwargs)
self.fields['username'].widget.attrs.update({'class':'form-control','placeholder':' Enter your username in English ','style': 'font-size:19px;text-align: center;'})
class Meta:
model = User
fields = [
'username',
'first_name',
'last_name',
'email',
]
views.py:
# Edit Profile View
class ProfileView(UpdateView):
model = User
form_class = ProfileForm
success_url = reverse_lazy('home')
template_name = 'user/commons/profile.html'
def get(self, request, *args, **kwargs):
form = self.form_class()
return render(request, self.template_name, {'form': form})
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
user = form.save(commit=False)
user.is_active = False # Deactivate account till it is confirmed
user.save()
current_site = get_current_site(request)
subject = 'Activate Your MySite Account'
message = render_to_string('user/emails/account_activation_email.html', {
'user': user,
'domain': current_site.domain,
'uid': urlsafe_base64_encode(force_bytes(user.pk)),
'token': account_activation_token.make_token(user),
})
user.email_user(subject, message)
messages.success(request, ('Please Confirm your new email to change email.'))
return redirect('login')
return render(request, self.template_name, {'form': form})
html page :
<button type="button" id="submit"> <a href="{% url 'profile' user.id %}" > edit profile info </a></button>
You can override the get_object() method to always return the currently logged on user from request.user, then you will not need to provide "pk" variable in your path.
Implement get_object() in your view
class ProfileView(UpdateView):
model = User
form_class = ProfileForm
success_url = reverse_lazy('home')
template_name = 'user/commons/profile.html'
def get_object(self, queryset=None):
return self.request.user
Then configure the path without pk
urlpatterns = [
path('profile/me/', ProfileView.as_view(), name='profile'),
]
Note that you should use login_required() decorator or LoginRequiredMixin on that view to avoid anonymous users accessing this view.
Main problem:
When user is at this url http://127.0.0.1:8000/8/, so group_id is already in url of his current page, he must choose group_id that he wants to assign task, if I do fields = ['title', completed'] in forms.py user can't choose group_id but he needs to. I have primary key but I don't know where to apply it in views
P.S.:
IndexView from views.py has no problem in it and works fine, also get method in GroupView works fine to. Anything works fine but user needs to choose a group that he want's to assign tasks
forms.py:
from django import forms
from .models import *
class AddTaskForm(forms.ModelForm):
class Meta:
model = Task
fields = '__all__'
class AddGroupForm(forms.ModelForm):
class Meta:
model = Group
fields = '__all__'
models.py
from django.db import models
from django.utils import timezone
class Group(models.Model):
title = models.CharField(max_length=255)
def __str__(self):
return self.title
class Task(models.Model):
title = models.CharField(max_length=255)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
completed = models.BooleanField(default=False)
def __str__(self):
return self.title
views.py
from django.shortcuts import render, redirect
from django.views import generic
from django.http import HttpResponse, HttpResponseRedirect
from django.urls import reverse
from .models import *
from .forms import *
class IndexView(generic.ListView):
template_name = 'tasks/index.html'
form_class = AddGroupForm
model = Group
def get_queryset(self):
return self.groups.order_by('title')
def get(self, request):
self.groups = Group.objects.all().order_by('title')
form = self.form_class(request.GET)
return render(request, self.template_name, {'form': form, 'groups': self.groups})
def post(self, request):
form = self.form_class(request.POST)
if form.is_valid():
form.save()
return redirect('/')
return render(request, self.template_name, {'form': form, 'groups': self.groups})
class GroupView(generic.ListView):
template_name = 'tasks/group.html'
form_class = AddTaskForm
model = Task
def get_queryset(self):
return self.tasks.order_by('-completed', 'title')
def get(self, request, pk):
self.group_id = pk
self.tasks = Group.objects.get(pk=pk).task_set.all()
form = self.form_class(request.GET, pk)
return render(request, self.template_name, {'form': form, 'tasks': self.tasks})
def post(self, request, pk):
form = self.form_class(request.POST)
if form.is_valid():
form = form.save(commit=False)
form.group_id = pk
form.save()
return HttpResponseRedirect(reverse('tasks:group', args=[pk]))
urls.py
from django.urls import path
from . import views
app_name = 'tasks'
urlpatterns = [
path('', views.IndexView.as_view(), name = 'index'),
path('<str:pk>/', views.GroupView.as_view(), name = 'group'),
]
Once you have the id in the url, you may use it in the form valid method. This is the place to add information befor writing to the DB:
def form_valid(self, form):
form.instance.group= Group.objects.get(pk=self.kwargs['pk'])
return super().form_valid(form)
By the way: Your url might be <int:pk> (not str) as automated generated pks are integer. And you may provide a better name for your parameter. Like <int:group_pk>
This makes your code more readable: self.kwargs['group_pk']
I am new to django, I migrated my models, the database is working fine, i can see the data that I added by the manage.py shell. But I cant add Data from my webApp. When I wrote text on the fields and press the submit button it gave me this error NOT NULL constraint failed: sms_post.author_id
Thanks for helping..
models.py files
from django.db import models
from django.contrib.auth.models import User
THE_GENDER = [
("Monsieur", "Monsieur"),
("Madame", "Madame")
]
class Post(models.Model):
name = models.CharField(max_length=100)
email = models.CharField(max_length=100)
gender = models.CharField(max_length=8, choices=THE_GENDER)
number = models.CharField(max_length=100)
author = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.name
forms.py files
from django import forms
from .models import Post
from crispy_forms.helper import FormHelper
class post_form(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(post_form, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
class Meta:
model = Post
fields = ["name", "email", "gender", "number"]
views.py files
from django.shortcuts import render
from django.http import HttpResponse
from .forms import post_form
from django.contrib.auth.decorators import login_required
#login_required
def home(request):
form = post_form(request.POST or None)
if form.is_valid():
form.save()
context = {
"form": form
}
return render(request, "sms/home.html", context)
You did not set the author of the instance in your for to a User object. You can do this with:
from django.shortcuts import redirect
#login_required
def home(request):
if request.method == 'POST':
form = post_form(request.POST)
if form.is_valid():
form.instance.author = request.user
form.save()
return redirect('name-of-view')
else:
form = post_form()
context = {
'form': form
}
return render(request, 'sms/home.html', context)
In order to implement the Post/Redirect/Get pattern [wiki], in case of a successful POST request, you should make a redirect, for example to the same view. You thus can here replace 'name-of-view' with the name of a view to redirect to.
I am trying to achieve two different views: one for registration purpose and one for login purpose.
Now, the registration process works perfectly but the authentication process does not.
Here's the code:
in forms.py the first form called UserForm is used to sign up users, the second form called LoginForm is used to log in users.
from django.contrib.auth.models import User
from django import forms
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput)
class Meta:
model = User
fields = ['first_name', 'last_name', 'username', 'email', 'password']
class LoginForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput)
class Meta:
model = User
fields = ['username', 'email', 'password']
in views.py
from django.shortcuts import render, get_object_or_404, redirect
from .models import Step, Cycle, Program, MotorSetting, GeneralSetting
from django.views import generic
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.core.urlresolvers import reverse_lazy
from django.contrib.auth import authenticate, login
from django.views.generic import View
from .forms import UserForm
from .forms import LoginForm
class UserFormView(View):
form_class = UserForm
template_name = 'programs/registration_form.html'
# display blank form
def get(self, request):
form = self.form_class(None)
return render(request, self.template_name, {'form': form})
#process form data
def post(self, request):
form = self.form_class(request.POST)
if form.is_valid():
#storing the data but NOT SAVING them to db yet
user = form.save(commit=False)
#cleaning and normalizing data
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user.set_password(password)
#saving to db
user.save()
#if credentials are correct, this returns a user object
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
return redirect('programs:index')
return render(request, self.template_name, {'form': form})
class LoginFormView(View):
form_class = LoginForm
template_name = 'programs/login_form.html'
# display blank form
def get(self, request):
form = self.form_class(None)
return render(request, self.template_name, {'form': form})
#process form data
def post(self, request):
form = self.form_class(request.POST)
if form.is_valid():
#storing the data but NOT SAVING them to db yet
user = form.save(commit=False)
#if credentials are correct, this returns a user object
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
return redirect('programs:index')
return render(request, self.template_name, {'form': form})
in app/urls.py
from django.conf.urls import include, url
from . import views
app_name = 'programs'
urlpatterns = [
#register page
url(r'^register/$', views.UserFormView.as_view(), name='register'),
#login page
url(r'^login/$', views.LoginFormView.as_view(), name='login'),
]
The registration process goes smoothly, the authentication/login does not. When I fill in the form to login and press send, nothing happens apart from the form getting blank again.
Is there any error I'm not seeing in the code?
Many thanks!
my views.py:
from django.http import HttpResponse
from django.shortcuts import render, render_to_response
from django.contrib.auth import login, authenticate
from django.contrib.auth.models import User
from django.shortcuts import render
from django.views.generic import View
from .forms import LoginForm, RegistrationForm
class Login(View):
form_class = LoginForm
initial = {'key': 'value'}
template_name = 'web/login.html'
def get(self, request):
form = self.form_class(initial=self.initial)
return render(request, self.template_name, {'form': form})
def post(self, request):
if request.method == 'POST':
form = self.form_class(initial=self.initial)
if form.is_valid():
email=form.cleaned_data['email']
password=form.cleaned_data['password']
auser = User.objects.get(email=email)
username = auser.username
buser = authenticate(username, password)
if buser:
if buser.is_active:
login(request, buser)
return HttpResponse('Good to Go...')
else:
return HttpResponse('your account is disabled...')
else:
print "Invalid login details: {0}, {1}".format(email, password)
HttpResponse('invalid login details...')
else:
return HttpResponse('Form is not valid!')
else:
form = self.form_class()
Here above I'm trying to login a user using email as unique field in class based views. But It raises 'Form is not valid!' as I specified in my views. I don't know what's going wrong with it exactly. Please Help me how to fix it?
Thanks in Advance
You need to change the post method of this class:
def post(self, request):
if request.method == 'POST':
form = self.form_class(data=self.request.POST)
if form.is_valid():
.....