Django : Invalid password format or unknown hashing algorithm - django

I have problem when I want to use simple CreateView for creating new user. Everything is ok, I can create user, but when I want logging with new created user, I cant do it.
I got this type of my password in admin:
Invalid password format or unknown hashing algorithm.
Raw passwords are not stored, so there is no way to see this user's password, but you can change the password using this form.
This is my code:
model.py
from django.db import models
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import AbstractUser, UserManager
class CustomUser(AbstractUser):
"""app setting of user"""
url = models.URLField(u'Site URL', max_length=100, null=True, unique=True)
admin.site.register(CustomUser, UserAdmin)
urls.py
from django.conf.urls.defaults import *
from models import CustomUser
from django.views.generic import CreateView
from django.contrib.auth.decorators import login_required
from django.core.urlresolvers import reverse
urlpatterns = patterns('',
url(r'^create_user/$',(CreateView.as_view(model=CustomUser, get_success_url =lambda: reverse('create_user'),
template_name="create_user.html")), name='create_user'),
)
create_user.html
<div title="Create Form " id="/create_user">
<p> <b>Create account:</b> </p>
{{ form.errors }}
<form action="" method="post" id="id_create_user" >
{% csrf_token %}
{{ form.as_p }}
<div>
<input type="submit" value="Create account" style="">
</div>
</form>
</div>
And after creating user, I have to log in as admin and change this password, and after that everything will be ok.
What should I do to solve the problem?
Thank you!

The problem is that CreateView is generating a form automatically based on the model, which means it's writing directly to the password field rather than using the correct API for creating a user.
Try this form instead, it'll handle it for you:
from django.contrib.auth.forms import UserCreationForm
urlpatterns = patterns('',
url(r'^create_user/$',(CreateView.as_view(model=CustomUser, get_success_url =lambda: reverse('create_user'), form_class=UserCreationForm, template_name="create_user.html")), name='create_user'),
)
These forms essentially give you the same as what you see in the admin, which is a good starting point, if you're using a custom user model you might want to do some additional work to get your customisations in.
Here's the source code for the supplied UserCreationForm: https://github.com/django/django/blob/stable/1.5.x/django/contrib/auth/forms.py#L61-L110
You can re-implement it yourself as a normal ModelForm, the key thing you must include is the save method where user.set_password is called.

Related

Django Autocomplete Light not working with Django update from Django 3.1 to 4.1

The application I inherited was at Django 2.2. I have gradually updated to 4.1 and everything works except the Django Autocomplete Light fields. For some forms.ModelForm, I have a box with a correct list that can be selected but it does not have the ability to type the first few letters and select from that filtered list. Most of the autocomplete fields are on forms.Form and either display a dropdown box where the only choice is '-----', a scroll bar only with no list, or a box that is 2 x 47 pixels.
I have gone through the DAL documentation but could not find a solution. I have searched here plus other Google searches but I have not found a solution.
I do realize that parts of the code use the older URL pattern that includes ^, $, and ?P< items. I have tried to change these for one of the apps but it did not solve the issue.
forms.py
# Forms
from django import forms
from django.forms import ModelForm
# Models
from login.models import User
from .models import Suggestion, SuggestionDecision, Implementation
# Autocomplete
from dal import autocomplete
class ReviewForm(forms.ModelForm):
class Meta:
model = Suggestion
fields = ['suggestion', 'supervisors', 'managers']
widgets = {
'supervisors': autocomplete.ModelSelect2Multiple(url='login:user_autocomplete'),
'managers': autocomplete.ModelSelect2Multiple(url='login:user_autocomplete')
}
urls.py
from django.urls import path, re_path
from process_improvement import views as pi_views
app_name='process_improvement'
re_path(r'^autocomplete/suggestion/$', pi_views.SuggestionAutocomplete.as_view(), name='suggestion_autocomplete')
views.py
from dal import autocomplete
from django.urls import reverse
from django.shortcuts import redirect
from django.contrib.auth.mixins import LoginRequiredMixin
class SuggestionAutocomplete(autocomplete.Select2QuerySetView, LoginRequiredMixin):
def get_queryset(self):
qs = Suggestion.objects.all()
if self.q:
for term in self.q.split():
qs = qs.filter(Q(suggestion__icontains=term) | Q(pk__icontains=term) | Q(created_at__icontains=term))
return qs
suggestion.html
<form method="POST" class="needs-validation" id="suggestionForm" data-parsley-validate>
{% csrf_token %}
<label for="id_supervisors">Supervisors*</label>
{{ suggestionForm.supervisors }}
{{ suggestionForm.suggestion | as_crispy_field }}
</form>
This is the code for the fields that appear with a list that can be selected but not the option to enter the first few letters of the name. What do I need to change to get this working properly?

Django ModelForm submit button not working

I am trying to make a Django ModelForm that retrieves data from my database using the GET method. When I click the submit button nothing happens. What am I doing wrong?
HTML doc
<form role="form" action="" method="GET" id="form-map" class="form-map form-search">
<h2>Search Properties</h2>
{% csrf_token %}
{{ form.as_p }}
<input type="submit" action= "" class="btn btn-default" value="Submit">
<input type="reset" class="btn btn-default" value="Reset">
</form><!-- /#form-map -->
forms.py
from django import forms
from .models import StLouisCitySale208
from django.forms import ModelForm, ModelMultipleChoiceField
class StLouisCitySale208Form(ModelForm):
required_css_class = 'form-group'
landuse = forms.ModelMultipleChoiceField(label='Land use', widget=forms.SelectMultiple, queryset=StLouisCitySale208.objects.values_list('landuse', flat=True).distinct())
neighborho =forms.ModelMultipleChoiceField(label='Neighborhood',widget=forms.SelectMultiple, queryset=StLouisCitySale208.objects.values_list('neighborho', flat=True).distinct())
policedist = forms.ModelMultipleChoiceField(label='Police district',widget=forms.SelectMultiple,queryset=StLouisCitySale208.objects.values_list('policedist', flat=True).distinct())
class Meta:
model = StLouisCitySale208
fields = ['landuse', 'neighborho', 'policedist', 'precinct20','vacantland', 'ward20', 'zip', 'zoning','asmtimprov', 'asmtland', 'asmttotal', 'frontage', 'landarea','numbldgs', 'numunits']
views.py
from django.views.generic import FormView, TemplateView
from .forms import StLouisCitySale208Form
class StLouisCitySale208View(FormView):
form_class = StLouisCitySale208Form
template_name = 'maps/StlouiscitySale208.html'
maps/urls.py
from django.urls import path
from .views import StLouisCitySale208View, ComingSoonView
app_name = 'maps'
urlpatterns = [
path("maps/stlouiscitysale208",StLouisCitySale208View.as_view(),name="stlouiscitysale208"),
path('maps/coming_soon', ComingSoonView.as_view(), name="coming_soon")
]
You need a get method in your class to tell the button what to do.
class MyView(View):
def get(self, request):
# <view logic>
return HttpResponse('result')
https://docs.djangoproject.com/en/4.0/topics/class-based-views/intro/
Your form currently has method="GET" which is something you'd use for search, or some other operation which doesn't change the state of the application.
If that's what you want to do, and you're using existing data, through a form, to allow users to query the database, then you'll need to implement a get method on the view in order to implement the logic for this. The following should help with the get() method for FormView;
http://ccbv.co.uk/projects/Django/4.0/django.views.generic.edit/FormView/#get
It sounds like you're hoping to create objects using your model form, so change that to method="POST" and you'll at least allow the application to create your object. There may be more to debug at that point, but you need to start by sending data to the server.

Form fields not being displayed Django

I am still learning Django. I have been looking at various tutorials but I am struggling with forms on django framework.
The problem is that I am unable to display the form field for email on the base.html page. It is basically a subscription form. I am still new to django. This is what I have made till now.
models.py
from django.db import models
class SubscribeModel(models.Model):
email = models.CharField(max_length=100)
forms.py
from django import forms
from models import SubscribeModel
class SubscribeForm(forms.ModelForm):
class Meta:
model=SubscribeModel
views.py
def loadform(request):
form = SubscribeForm()
return render_to_response('base.html', {'form': form},context_instance=RequestContext(request))
base.html
<html>
...
<form action="" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Subscribe"></ul>
</form>
...
</html>
urls.py
urlpatterns = patterns('',
url(r'^$', 'chsite.blog.views.index'),
url(r'^$', 'chsite.blog.views.loadform'),
url(r'^admin/', include(admin.site.urls)),
)
Once you are edited the question, I can see two url(---) reffenceced to the same url. Hence Django will loadd the first one. It means you never load the loadform view. So try removing the line:
url(r'^$', 'chsite.blog.views.index'),
or edit the actual tuple for the loadform for instance:
url(r'^suscribe/$', 'chsite.blog.views.loadform'),
and go to your browser at 127.0.0.1:8000/suscribe/ url.
You have to define different url patterns as your first two are identical. URL processing stops at first hit, in your case uses index view.

How do I install an app that doesn't have models or views?

I am attempting to install and test django-honeypot from sunlightlabs using the provided templates.
the application does not come accompanied with models nor views and I am confused as to how I am supposed to get the app to work. I have attempted to play with the urls to call the templates.
my mysite/mysite/urls.py follows:
from django.conf.urls.defaults import *
urlpatterns = patterns('',
#url(r'^$', include('honeypot.urls')),
)
and my mysite/honeypot/urls.py follows:
from django.conf.urls.defaults import *
#from tagging.views import tagged_object_list
from django.conf.urls import patterns, include, url
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
from django.shortcuts import render
from django.contrib import admin
urlpatterns = patterns('',
url(r'^$', render, dict(template_name='/home/mohrashak/attribute2/honeypot/templates/honeypot/webpage.html'), name='price'),
)
ROOT_URLCONF="honeypot.urls"
where webpage is
{% load honeypot %}
<form>
{% render_honeypot_field "field_name" %}
</form>
and my understanding is that something will be entered into the box be processed using the application. But there is no model. What am I missing?
You don't need to worry about models or views for django-honeypot. It is installed into the site-packages folder of your Python library so you don't have to write models/views/urls.py for you - these are all there in your pythonpath.
Make sure you read the online documentation for installing the app.
Here is the checklist:
Add honeypot to INSTALLED_APPS in settings.py;
Define HONEYPOT_FIELD_NAME which is the name to use for the honeypot field in your form. Try not to use 'honeypot' though as some bots will avoid it.
Make sure you add {% load honeypot %} in the top of your template using django-honeypot;
Then use the following tag in any form {% render_honeypot_field "field_name" %}
When your form is submitted - you can use the check_honeypot decorator from honeypot.decorators to check the value is present (or not by default) and correct.
Here is the example from the documentation to add to your view:
from honeypot.decorators import check_honeypot
#check_honeypot(field_name='hp_field_name')
def post_comment(request):
...
#check_honeypot
def other_post_view(request):
...
Edit1:
In response to your comment:
Yes;
Yes.
No - the nature of django-honeypot is that it prevents "form spam". So you have to have at least a form in your template. You should pass a form from a view to a template. More information in the documentation. I've written a near full example below.
Example of a contact form using django-honeypot
Note: This is untested.
This is an example that creates and shows a contact form (by going to a /contact/ URL) and then handles the form being submitted. Imagine we have used django_admin.py startapp contact_app
urls.py
Your urls file takes the /contact/ URL passes the request to our contact view.
from django.conf.urls import patterns, url
urlpatterns = patterns('',
url(r'^contact/$', 'contact_app.views.contact'),
)
contact_app/views.py
Your views file takes the request, and handles GET and POST requests. If the request is a GET it passes an empty form to the template. If a POST then it checks the form is valid and processes the form. We wrap it in the check_honeypot decorator to make sure it passes our django-honeypot test.
from contact_app.forms import ContactForm
from honeypot.decorators import check_honeypot
#check_honeypot
def contact(request):
if request.method == 'POST': # If the form has been submitted...
form = ContactForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
# Process the data in form.cleaned_data
# ...
return HttpResponseRedirect('/thanks/') # Redirect after POST
else:
form = ContactForm() # An unbound form
return render(request, 'contact.html', {
'my_form': form,
})
contact_app/forms.py
Here we specify the form fields that are going to be required and display in the template.
from django import forms
class ContactForm(forms.Form):
subject = forms.CharField(max_length=100)
message = forms.CharField()
sender = forms.EmailField()
cc_myself = forms.BooleanField(required=False)
templates/contact.html
From our view, we pass our form (called my_form) to our template and use django's templating language to render each field as a <p></p>. We also load the honeypot and insert the necessary field.
{% load honeypot %}
<form action="/contact/" method="post">{% csrf_token %}
{{ my_form.as_p }}
{% render_honeypot_field "field_name" %}
<input type="submit" value="Submit" />
</form>

How do I auto populate fields in Django Threadedcomments based on user.is_authenticated

It seems simple to me. If a user is authenticated, auto populate the relavent form fields and don't show them. If a user isn't authenticated, show the form fields. I've been looking everywhere and I can't seem to find the answer. Does anyone know of some way to address this?
in your template you could do something like this:
{% if user.is_authenticated %}
<form>
<input type="hidden" name="username" value="{{ user.username }}" />
</form>
{% else %}
<!-- use your "regular" form here -->
Hope this helps...
This example come from real system, I've worked on. Hope that helps you out.
import datetime
from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.utils.encoding import force_unicode
import django.contrib.comments.forms
from current_user.middleware import get_current_user
class AuthCommentForm(django.contrib.comments.forms.CommentForm):
def get_comment_create_data(self):
"""
Returns the dict of data to be used to create a comment. Subclasses in
custom comment apps that override get_comment_model can override this
method to add extra fields onto a custom comment model.
"""
return dict(
content_type=ContentType.objects.get_for_model(self.target_object),
object_pk=force_unicode(self.target_object._get_pk_val()),
user_name=get_current_user().username,
user_email=get_current_user().email,
user_url='',
comment=self.cleaned_data["comment"],
submit_date=datetime.datetime.now(),
site_id=settings.SITE_ID,
is_public=True,
is_removed=False,
)
AuthCommentForm.base_fields.pop('url')
AuthCommentForm.base_fields.pop('name')
AuthCommentForm.base_fields.pop('email')
AuthCommentForm.base_fields.pop('honeypot')
AuthCommentForm.base_fields['comment'].label = False