I am using django 1.7 with mongoengine. I have created a class Projects :
class Projects(Document):
user = ReferenceField(User, reverse_delete_rule=CASCADE)
p_name = StringField(max_length=70, required=True)
author = StringField(max_length=70, required=True)
url = StringField(max_length=200, required=True)
short_discription = StringField(max_length=100, required=True)
long_discription = StringField()
logo_url = StringField(max_length=200, required=False)
logo = ImageField(size=(250, 250, True))
tags = TaggableManager()
def __unicode__(self):
return self.p_name
def save(self, *args, **kwargs):
self.p_name = self.p_name
return super(Projects, self).save(*args, **kwargs)
def get_absolute_url(self):
return reverse('view_project', args=[self.p_name])
def get_edit_url(self):
return reverse('update', args=[self.id])
def get_delete_url(self):
return reverse('delete', args=[self.id])
and i am referencing and storing user in my mongodb through my views :
class new_project(CreateView):
model = Projects
form_class = NewProjectForm
success_url = reverse_lazy('registered')
def get_template_names(self):
return["new_project.html"]
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.user = self.request.user
self.object.save()
return super(new_project, self).form_valid(form)
and mongodb JSON format looks like this :
"user" : ObjectId("54db3e5d7818f4253e5da0db"),
I want to to create user profile where they can see their all projects, for that i created a view :
class UserProjectsListView(ListView):
model = Projects
context_object_name = "project"
def get_template_names(self):
return ["view_user.html"]
def get_queryset(self):
return self.model.objects.filter(user=self.kwargs['pk'])
and my urls.py :
url(r'^new_project/', new_project.as_view(),name='new_project'),
url(r'^project/(?P<pk>[\w\d]+)', view_project.as_view(), name='view_project'),
url(r'^user/(?P<pk>[\w\d]+)/$', UserProjectsListView.as_view(), name='detail'),
The problem with this is that i have to use the object id only in my url, but want to use username instead. Because on the template it renders only username not the object id.
Does anyone know how to use username in urls instead of object id, because rendering object id on template would not be good for security purpose also.
my user creation form :
class UserCreationForm(forms.Form):
error_messages = {
'duplicate_username': _("A user with that username already exists."),
'duplicate_email': _("A user with that email already exists."),
'password_mismatch': _("The two password fields didn't match."),
}
username = forms.RegexField(label=_("Username"), max_length=30,
regex=r'^[\w.#+-]+$',
help_text=_("Required. 30 characters or fewer. Letters, digits and "
"#/./+/-/_ only."),
error_messages={
'invalid': _("This value may contain only letters, numbers and "
"#/./+/-/_ characters.")})
email = forms.EmailField(label=_("Email"), max_length=254,
help_text=_("Required valid email. 254 characters or fewer."),
error_messages={
'invalid': _("This value may contain only valid email address.")})
password1 = forms.CharField(label=_("Password"),
widget=forms.PasswordInput)
password2 = forms.CharField(label=_("Password confirmation"),
widget=forms.PasswordInput,
help_text=_("Enter the same password as above, for verification."))
def clean_username(self):
# Since User.username is unique, this check is redundant,
# but it sets a nicer error message than the ORM. See #13147.
username = self.cleaned_data["username"]
try:
User._default_manager.get(username=username)
except User.DoesNotExist:
return username
raise forms.ValidationError(
self.error_messages['duplicate_username'],
code='duplicate_username',
)
def clean_email(self):
# Since User.username is unique, this check is redundant,
# but it sets a nicer error message than the ORM. See #13147.
email = self.cleaned_data["email"]
try:
User._default_manager.get(email=email)
except User.DoesNotExist:
return email
raise forms.ValidationError(
self.error_messages['duplicate_email'],
code='duplicate_email',
)
def clean_password2(self):
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError(
self.error_messages['password_mismatch'],
code='password_mismatch',
)
return password2
def save(self):
user = User._default_manager.create_user(
username=self.cleaned_data['username'],
email=self.cleaned_data['email'],
password=self.cleaned_data["password1"])
return user
I also want to get data from three tables and i have used dev instead of class:
def UserProjectsListView(request, pk):
return render_to_response('view_user.html', {
'tuorial' : Tutorial.objects.filter(user=pk),
'question' : Question.objects.filter(user=pk),
'project': Project.objects.filter(user=pk),
})
P.S. Thanks in advance.
If MongoEngine can't simulate joins, it is very simple to do this in two separate queries:
def get_queryset(self):
user = User.objects.get(username=self.kwargs['username'])
return self.model.objects(user=user.id)
Related
good day!A separate page was created to change the password, when you enter the password and repeat it and click on the "change password" button, a duplicate key value violates unique constraint "core_user_username_key" error appears
DETAIL: key (username) = already exists
how to solve this error?
forms.py
class CallcenterPasswordChange(forms.ModelForm):
password1 = forms.CharField(widget=forms.PasswordInput(), label='Новый пароль')
password2 = forms.CharField(widget=forms.PasswordInput(), label='Повтор нового пароля')
def clean(self):
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError(
self.error_messages['password_mismatch'],
code='Повтор нового пароля не совпадает',
)
return self.cleaned_data
class Meta:
model = User
fields = ('username', 'first_name', 'last_name', 'password1', 'password2')
views.py
class CallcenterPasswordChangeView(AbsCallcenterView):
template_name = 'callcenter/password_change.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
patient_pk = kwargs.get('patient_pk')
patient = get_object_or_404(Patient, pk=patient_pk)
initial_data = model_to_dict(patient.user)
context['form'] =CallcenterPasswordChange(initial=initial_data)
context['patient_pk'] = patient_pk
context['patient'] = patient
return context
def post(self, request, **kwargs):
context = super().get_context_data(**kwargs)
patient_pk = kwargs.get('patient_pk')
patient = get_object_or_404(Patient, pk=patient_pk)
form = CallcenterPasswordChange(request.POST)
context['form_user'] = form
context['patient'] = patient
if form.is_valid():
form.save()
else:
return render(request, template_name=self.template_name, context=context)
This isn't what you want to do at all. What this is trying to do is to create a completely new user.
What's more, the password1 and password2 fields are not associated with the actual password field in the model; plus, there is nothing that takes care of hashing the password.
What you actually want is a standard (non-model) form with just those two fields, and then to set the password of the current user.
So the form is just:
class CallcenterPasswordChange(forms.Form):
password1 = forms.CharField(widget=forms.PasswordInput(), label='Новый пароль')
password2 = forms.CharField(widget=forms.PasswordInput(), label='Повтор нового пароля')
def clean(self):
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError(
self.error_messages['password_mismatch'],
code='Повтор нового пароля не совпадает',
)
return self.cleaned_data
and in the view, you do:
form = CallcenterPasswordChange(request.POST)
if form.is_valid():
request.user.set_password(form.cleaned_data['password1'])
request.user.save()
return redirect('somewhere')
However, you should also note that Django includes a password change form and view already.
problem solved!
class CallcenterPasswordChangeView(AbsCallcenterView):
template_name = 'callcenter/password_change.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
patient_pk = kwargs.get('patient_pk')
patient = get_object_or_404(Patient, pk=patient_pk)
initial_data = model_to_dict(patient.user)
context['form'] = CallcenterPasswordChange(initial=initial_data)
context['patient'] = patient
return context
def post(self, request, **kwargs):
context = super().get_context_data(**kwargs)
patient = Patient.objects.get(pk=context['patient_pk'])
form = CallcenterPasswordChange(request.POST)
context['form'] = form
if form.is_valid():
patient.user.set_password(form.cleaned_data['password1'])
patient.user.save()
success_url = reverse_lazy('callcenter:patients')
return HttpResponseRedirect(success_url)
I'm using a view to create new users in Django. And then I have another view to log them in.
But when I create a user, and I try to log in with authenticate(username=username_post, password=password_post), I get None, so it displays in the template 'Wrong username or password.'.
In my database, I see new registers every time I create a new user. However, as the password is encrypted, I can't say if the problem is the login view, or the register view.
However, the super user that I created through the command line after I first installed django, is able to login with no problem, so that makes me thing that the problem is when I create the user.
These are my Login and Register views:
class Login(View):
form = LoginForm()
message = None
template = 'settings/blog_login.html'
def get(self, request, *args, **kwargs):
if request.user.is_authenticated():
return redirect('settings:index')
return render(request, self.template, self.get_context())
def post(self, request, *args, **kwargs):
username_post = request.POST['username']
password_post = request.POST['password']
user = authenticate(username=username_post, password=password_post)
if user is not None:
login(request, user)
return redirect('settings:index')
else:
self.message = 'Wrong username or password.'
return render(request, self.template, self.get_context())
def get_context(self):
return {'form': self.form, 'message': self.message}
class Register(CreateView):
success_url = reverse_lazy('settings:login')
model = User
template_name = 'settings/blog_register.html'
form_class = RegisterForm
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.set_password(self.object.password)
self.object.save()
return HttpResponseRedirect(self.get_success_url())
And these are my forms:
class LoginForm(forms.Form):
username = forms.CharField(max_length=20, label='Username')
password = forms.CharField(label='Password', widget=forms.PasswordInput())
class RegisterForm(forms.ModelForm):
username = forms.CharField(max_length=20, label='Username')
password1 = forms.CharField(label='Password', widget=forms.PasswordInput(),
error_messages={'required': 'Required field.',
'unique': 'Username already used.',
'invalid': 'Not valid username.'})
password2 = forms.CharField(label='Retype password', widget=forms.PasswordInput(),
error_messages={'required': 'Required field.'})
email = forms.EmailField(error_messages={'required': 'Required field.',
'invalid': 'Invalid email.'})
def clean(self):
clean_data = super(RegisterForm, self).clean()
password1 = clean_data.get('password1')
password2 = clean_data.get('password2')
if password1 != password2:
raise forms.ValidationError('Passwords are different.')
return self.cleaned_data
def clean_email(self):
email = self.cleaned_data.get('email')
username = self.cleaned_data.get('username')
if email and User.objects.filter(email=email).exclude(
username=username).exists():
raise forms.ValidationError('Email already used.')
return email
class Meta:
model = User
fields = ('username', 'password1', 'password2', 'email')
Please, let me know if you need more info.
You don't have a field called 'password' in your form - you just have 'password1' and 'password2' - so nothing is saved to the model object's actual password field. So, when you do self.object.set_password(self.object.password), you're actually setting a blank password.
Instead, you should get the value from your form's password1 field:
self.object.set_password(self.form.cleaned_data['password1'])
I am creating a form for a custom user type. But each time I submit the form to test it, it returns an error that says the unicode object has no attribute get error.
forms.py:
class RegistrationForm(forms.ModelForm):
"""
Form for registering a new account.
"""
password1 = forms.CharField(widget=forms.PasswordInput,
label="Password")
password2 = forms.CharField(widget=forms.PasswordInput,
label="Password (again)")
class Meta:
model = Student
fields = ('firstname', 'lastname', 'email', 'password1', 'password2', 'is_second_year')
def clean(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password2
def save(self, commit=True):
user = super(RegistrationForm, self).save(commit=False)
user.set_password(self.cleaned_data['password1'])
if commit:
user.save()
return user
models.py:
class StudentManager(BaseUserManager):
def create_user(self, firstname, lastname, email, is_second_year, password, is_officer=False, hours=0, points=0):
if not email:
raise ValueError("Student must have an email address.")
newStudent = self.model(
email = self.normalize_email(email),
firstname=firstname,
lastname=lastname,
is_officer=is_officer,
is_second_year=is_second_year,
hours=hours,
points=points
)
newStudent.set_password(password)
user.save(using=self.db)
return newStudent
def create_superuser(self, firstname, lastname, email, password, is_second_year, is_officer=True, hours=0, points=0):
newSuperStudent = self.create_user(
email = self.normalize_email(email),
firstname=firstname,
lastname=lastname,
is_officer=is_officer,
is_second_year=is_second_year,
hours=hours,
points=points,
password=password
)
newSuperStudent.is_admin = True
newSuperStudent.save(using=self.db)
return newSuperStudent
class Student(AbstractBaseUser):
firstname = models.CharField(verbose_name="First Name", max_length=30, default="")
lastname = models.CharField(verbose_name="Last Name", max_length=30, default="")
email = models.EmailField(
verbose_name='Email Address',
max_length=255,
unique=True,
default=''
)
is_officer = models.BooleanField(default=False)
is_second_year = models.BooleanField(verbose_name="Check this box if this is your second year in NHS")
hours = models.DecimalField(max_digits=5, decimal_places=2)
points = models.DecimalField(max_digits=3, decimal_places=1)
USERNAME_FIELD = 'email'
def __unicode__(self):
return self.username
views.py:
def sign_up(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = RegistrationForm(request.POST)
# check whether it's valid:
if form.is_valid():
print "money"
form.save()
# redirect to a new URL:
return HttpResponseRedirect('/sign_up_success/')
# if a GET (or any other method) we'll create a blank form
args = {}
args.update(csrf(request))
args['form'] = RegistrationForm()
return render_to_response('events/sign_up.html', args)
Error Location within the .is_valid() method:
field_value = self.cleaned_data.get(field, None)
My guess is that for some reason, the cleaned_data attribute of my form is a unicode object rather than a dictionary. But I have no clue why this is so!
clean must return the full cleaned_data dictionary, not a single string field.
I have looked at a lot of posts that had similar issues and the answers did nothing for my code.
I am using a custom registration form for a site I'm working on that makes email required. most of the code in it is based off of the one built in to django. I have tried to create a new form class based on django.contrib.auth.forms.UserCreationForm and still get the same error.
The form based on the one in django
class UserCreateFrom(UserCreationForm):
"""
A form that creates a user, with no privileges, from the given username and
password.
"""
error_messages = {
'duplicate_username': _("A user with that username already exists."),
'duplicate_email': _("That email is already in use"),
'password_mismatch': _("The two password fields didn't match."),
}
email = forms.EmailField(label=_("Email Address"),
required=True,
help_text="Required. Your Email Address for password resets, and other emails from us")
def clean_email(self):
email = self.cleaned_data["email"]
try:
User._default_manager.get(email=email)
except User.DoesNotExist:
return email
raise forms.ValidationError(
self.error_messages['duplicate_email'],
code='duplicate_email',
)
the form currently in use
class UserCreateFrom(forms.ModelForm):
"""
A form that creates a user, with no privileges, from the given username and
password.
"""
error_messages = {
'duplicate_username': _("A user with that username already exists."),
'duplicate_email': _("That email is already in use"),
'password_mismatch': _("The two password fields didn't match."),
}
username = forms.RegexField(label=_("Username"), max_length=30,
regex=r'^[\w.#+-]+$',
help_text=_("Required. 30 characters or fewer. Letters, digits and "
"#/./+/-/_ only."),
error_messages={
'invalid': _("This value may contain only letters, numbers and "
"#/./+/-/_ characters.")
}
)
email = forms.EmailField(label=_("Email Address"),
required=True,
help_text="Required. Your Email Address for password resets, and other emails from us")
password1 = forms.CharField(label=_("Password"),
widget=forms.PasswordInput)
password2 = forms.CharField(label=_("Password confirmation"),
widget=forms.PasswordInput,
help_text=_("Enter the same password as above, for verification."))
class Meta:
model = User
fields = ("username",)
def clean_username(self):
# Since User.username is unique, this check is redundant,
# but it sets a nicer error message than the ORM. See #13147.
username = self.cleaned_data["username"]
try:
User._default_manager.get(username=username)
except User.DoesNotExist:
return username
raise forms.ValidationError(
self.error_messages['duplicate_username'],
code='duplicate_username',
)
def clean_email(self):
email = self.cleaned_data["email"]
try:
User._default_manager.get(email=email)
except User.DoesNotExist:
return email
raise forms.ValidationError(
self.error_messages['duplicate_email'],
code='duplicate_email',
)
def clean_password2(self):
password1 = self.cleaned_data["password1"]
password2 = self.cleaned_data["password2"]
if password1 and password2 and password1 != password2:
raise forms.ValidationError(
self.error_messages['password_mismatch'],
code='password_mismatch',
)
return password2
def save(self, commit=True):
user = super(UserCreateFrom, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
the view, I have not been able to work on if the form is valid since I cant get it to work with no data UserCreateFrom is my custom registration form imported from froms.py in the same app.
#sensitive_post_parameters()
#csrf_protect
#never_cache
def register(request):
"""
Allow registration of new users
:param request:
:return:
"""
context = {}
form = UserCreateFrom(data=request.post)
context.update({'form': form})
if request.method == 'POST' and form.is_valid():
return render(request, 'test.html', context)
else:
return render(request, 'register.html', context)
if I switch form = UserCreateFrom(data=request.post) to form = UserCreateFrom(request) I get 'WSGIRequest' object has no attribute 'get' error, but this way at least errors in the template right where the form is called via `{{ form }}, and not the view.
The data attribute is called request.POST.
But you should move that into the block that checks the method.
I have a custom ChangeUserForm (ModelForm on User) that allows a user to update their account information.
However, when I save the form, user.is_active, user.is_staff and user.is_superuser all get set to False.
Any thoughts on what's going on here?
forms.py
class UserChangeForm(forms.ModelForm):
username = forms.RegexField(label="Username", max_length=30, regex=r'^[\w.#+-]+$',
help_text = "Required. 30 characters or fewer. Letters, digits and #/./+/-/_ only.",
error_messages = {'invalid': "This value may contain only letters, numbers and #/./+/-/_ characters."})
first_name = forms.CharField(label="First name", max_length=30)
last_name = forms.CharField(label="Last name", max_length=30)
email = forms.EmailField(label="E-mail Address")
new_password1 = forms.CharField(label="New password", widget=forms.PasswordInput, required=False)
new_password2 = forms.CharField(label="Confirm new password", widget=forms.PasswordInput, required=False)
class Meta(auth_forms.UserChangeForm):
model = User
exclude = ('password', 'last_login', 'date_joined')
def clean_new_password2(self):
password1 = self.cleaned_data.get('new_password1')
password2 = self.cleaned_data.get('new_password2')
if password1 != password2:
raise forms.ValidationError("The two password fields didn't match.")
else:
if len(password2) > 0 and len(password2) < 8:
raise forms.ValidationError("Your password must be a minimum of 8 characters.")
return password2
def save(self, commit=True):
user = super(UserChangeForm, self).save(commit=False)
if len(self.cleaned_data['new_password2']) > 0:
user.set_password(self.cleaned_data['new_password2'])
if commit:
user.save()
return user
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
exclude = ('user')
views.py
#login_required
def profile(request):
context = {}
if request.method == 'POST':
user_form = UserChangeForm(request.POST, instance = request.user)
user_profile_form = UserProfileForm(request.POST, instance = request.user.profile)
if user_form.is_valid() and user_profile_form.is_valid():
user_form.save()
user_profile_form.save()
return render_to_response('accounts_profile_complete.html', context_instance=RequestContext(request))
else:
user_form = UserChangeForm(instance = request.user)
user_profile_form = UserProfileForm(instance = request.user.profile)
context.update(csrf(request))
context['user_form'] = user_form
context['user_profile_form'] = user_profile_form
return render_to_response('accounts_profile.html', context, context_instance=RequestContext(request))
Just a guess: they aren't on the exclusion list in the Meta class so they're being set to false (boolean fields like those use a checkbox, which doesn't show up in POST data when unchecked). The form can't tell the difference between a boolean form field set to false and one that isn't on the page in the first place so you need to explicitly exclude them.