Django-registration form without email field - django

I've read through several similar questions here, but I still can't seem to find a solution:
I am using the django-registration package and I want to make a registration form that does not have an email field, or at least not required. I have tried many different ways, but here is one:
# in forms.py
from registration.forms import RegistrationForm
class ExpRegistrationForm(RegistrationForm):
# email = forms.EmailField(label="E-mail",required=False)
def __init__(self, *args, **kwargs):
super(RegistrationForm, self).__init__(*args, **kwargs)
self.fields['email'].required = False
Then I link this to a custom view:
# in views.py
from registration.backends.simple.views import RegistrationView as BaseRegistrationView
class ExpRegistrationView(BaseRegistrationView):
form_class = ExpRegistrationForm
Then in urls, after importing views, I add to urlpatterns:
url(r'^../accounts/register/$',views.ExpRegistrationView.as_view(), name='registration_register')
I've shown two attempts above, but I also tried using del or pop to try to get rid of email from my form... And I always get a field error, saying that email is required...
Any suggestions? Or more information needed?

Related

Overriding Django Default Authentication Form

I am trying to override the canned error message for the Django AuthorizationForm. Instead of it saying this field is required I am trying to get it to say Username is required.
I have tried to subclass the AuthorizationForm with the standard LoginView and it doesn't pick up my custom clean method. I looked at this SO similar issue, Change default django error messages for AuthenticationForm and tried to follow the tips in there but still can't get it to work. Thanks in advance for any tips on what I might be doing wrong.
class AuthenticationForm(AuthenticationForm):
def __init__(self, *args, **kwargs):
super(AuthenticationForm, self).__init__(*args, **kwargs)
def clean(self):
cleaned_data = super(AuthenticationForm, self).clean()
username = cleaned_data.get('username')
password = cleaned_data.get('password')
if username and password:
pass
else:
self.add_error('username','Username and Password required.')
pass
I am trying to get it to show Username and Password Required instead of the canned default This field is required messages. No matter what I do I can't seem to get it to pick up my code above. I have it stored in my project forms.py file. I believe I'm subclassing it incorrectly. I've tried a lot of different combinations but can't seem to get it see this form. I'm running Django 1.11
#Jagjeet Singh Thank you!
Jagleet's suggestion helped me understand that I needed to define this form in the format below in my forms.py file for User to get my desired end result.
class AuthenticationForm(AuthenticationForm):
class Meta:
model = User
fields = '__all__'
def __init__(self, *args, **kwargs):
super(AuthenticationForm, self).__init__(*args, **kwargs)
for field in self.fields.values():
field.error_messages = {'required':'{fieldname} is required'.format(
fieldname=field.label)}

How to add custom page to django admin with custom form, not related to any Model?

I want to bulk_create models by importing csv data through django admin, with TextArea or FileField. I learned how to override template blocks, how to add new urls to django admin. But I have no idea how to solve my problem. I want to create custom admin page with my form. Pass data, parse it and bulk_create my model objects. Can you guys suggest the way how can I do this?
I found a snippet for this situation
from django.contrib import admin, messages
from django.http import HttpResponseRedirect
from django.shortcuts import render
from my_app.forms import CustomForm
class FakeModel(object):
class _meta:
app_label = 'my_app' # This is the app that the form will exist under
model_name = 'custom-form' # This is what will be used in the link url
verbose_name_plural = 'Custom AdminForm' # This is the name used in the link text
object_name = 'ObjectName'
swapped = False
abstract = False
class MyCustomAdminForm(admin.ModelAdmin):
"""
This is a funky way to register a regular view with the Django Admin.
"""
def has_add_permission(*args, **kwargs):
return False
def has_change_permission(*args, **kwargs):
return True
def has_delete_permission(*args, **kwargs):
return False
def changelist_view(self, request):
context = {'title': 'My Custom AdminForm'}
if request.method == 'POST':
form = CustomForm(request.POST)
if form.is_valid():
# Do your magic with the completed form data.
# Let the user know that form was submitted.
messages.success(request, 'Congrats, form submitted!')
return HttpResponseRedirect('')
else:
messages.error(
request, 'Please correct the error below'
)
else:
form = CustomForm()
context['form'] = form
return render(request, 'admin/change_form.html', context)
admin.site.register([FakeModel], MyCustomAdminForm)
from django import forms
class CustomForm(forms.Form):
# Your run-of-the-mill form here
Using a proxy model would save some typing:
class ImportCSVData(SomeModel):
class Meta:
proxy = True
#admin.register(ImportCSVData)
class MyCustomAdminForm(admin.ModelAdmin):
... as in accepted answer ...
I'm glad to say that since version 1.3.0 django-etc ships with etc.admin.CustomModelPage. So you may want to do something like:
from etc.admin import CustomModelPage
class BulkPage(CustomModelPage):
title = 'Test page 1' # set page title
# Define some fields.
my_field = models.CharField('some title', max_length=10)
def save(self):
# Here implement bulk creation using values
# from self fields attributes, e.g. self.my_field.
super().save()
# Register this page within Django admin.
BulkPage.register()
When I came across this answer, I was hoping to find a way to add a second form to the admin page for an existing model. The answer here gets you sort of close, but there is a much easier way to approach this.
For this example, I will assume the model we're working with is called Candle.
# Make a proxy class for your model, since
# there can only be one admin view per model.
class EasyCandle(models.Candle):
class Meta:
proxy = True
# Make a ModelAdmin for your proxy class.
#admin.register(EasyCandle)
class EasyCandleAdminForm(admin.ModelAdmin):
# In my case, I only want to use it for adding a new model.
# For changing an existing instance of my model or deleting
# an instance of my model, I want to just use the
# views already available for the existing model.
# So has_add_permission returns True while the rest return False.
def has_add_permission(*args, **kwargs):
return True
def has_change_permission(*args, **kwargs):
return False
def has_delete_permission(*args, **kwargs):
return False
# This replaces all the complicated stuff other
# answers do with changelist_view.
def get_form(self, request, obj=None, **kwargs):
return EasyCandleForm
# Finally, make whatever form you want.
# In this case, I exclude some fields and add new fields.
class EasyCandleForm(forms.ModelForm):
class Meta:
model = models.Candle
# Note, do NOT exclude fields when you want to replace their form fields.
# If you do that, they don't get persisted to the DB.
fields = "__all__"
vessel = forms.CharField(
required=True,
help_text="If the vessel doesn't already exist in the DB, it will be added for you",
)

Autocomplete in django and allow creating user if not found

I'm trying to add a search box for users on the webpage to see his profile, and if the user doesn't exist, then I have the option to create it.
In flask, I used a solution that used jquery for the autocomplete, and when no one was found, it would simply put "Create_user" as the text submitted in the form, and then redirect to the url for user creation. I was not able to port this to django(javascript is not my forté and I'm starting django.)
So I tried django-autocomplete-light, but while the autocomplete worked, I found no way to replicate the behavior that would redirect me to the user creation page in the case no one was found. (the create exemple in the docs only allow to create a simple entry, while I need to create a user based on a model)
Any leads on how to accomplish this with django?
That's what i was looking few days ago, i found this
Example Admin code for autocomplete
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
from django import forms
from selectable.forms import AutoCompleteSelectField, AutoCompleteSelectMultipleWidget
from .models import Fruit, Farm
from .lookups import FruitLookup, OwnerLookup
class FarmAdminForm(forms.ModelForm):
owner = AutoCompleteSelectField(lookup_class=OwnerLookup, allow_new=True)
class Meta(object):
model = Farm
widgets = {
'fruit': AutoCompleteSelectMultipleWidget(lookup_class=FruitLookup),
}
exclude = ('owner', )
def __init__(self, *args, **kwargs):
super(FarmAdminForm, self).__init__(*args, **kwargs)
if self.instance and self.instance.pk and self.instance.owner:
self.initial['owner'] = self.instance.owner.pk
def save(self, *args, **kwargs):
owner = self.cleaned_data['owner']
if owner and not owner.pk:
owner = User.objects.create_user(username=owner.username, email='')
self.instance.owner = owner
return super(FarmAdminForm, self).save(*args, **kwargs)
class FarmAdmin(admin.ModelAdmin):
form = FarmAdminForm
admin.site.register(Farm, FarmAdmin)
Source code
https://github.com/mlavin/django-selectable
and
Documentation
http://django-selectable.readthedocs.org/en/latest/
Hope this will help you too

Django - how to add email to required things

I create registration form:
#urls.py
from django.conf.urls import patterns, url
from django.views.generic import TemplateView
from account.views import Register
urlpatterns = patterns('',
url(r'^register/$', Register.as_view(template_name='account/register.html')),
)
#views.py
from django.views.generic import CreateView
from django.contrib.auth.models import User
class Register(CreateView):
model = User
success_url = '/account/'
And i have question: how I can add that email be require (now I must only enter username, password and 2 times time).
#edit
And how "repair" password? When i create user (in this form) and then go to admin panel, in user i see "Invalid password format or unknown hashing algorithm.". How i can repair this?
The reason that email is not required is because you're using a ModelForm, which takes a lot of cues from the underlying User model. Specifically, the required=True attribute is not present on the email field of the model.
One solution is to create your own form with the necessary attributes, perhaps by using a ModelForm and adding a required email field.
Another solution, and probably the better one, is to use something like django-registration as mentioned by Aamir Adnan in the comments to your question. It'll simplify things a lot for you.
As far as your repair password goes, you can't set the password to a raw string value as you're doing with your CreateView. To set a password, you have to call user.set_password(raw_string) which will take care of hashing and salting for you. Look how the built in UserCreationForm works, and try to mimic it if you decide to build the form yourself, rather than using a library (you shouldn't).
To solve these two problems you can use form like:
class UserCreationForm(forms.ModelForm):
class Meta:
model = User
def __init__(self, *args, **kwargs):
super(UserCreationForm).__init__(*args, **kwargs)
self.fields['email'].required = True
def save(self, commit=True):
user = super(UserCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password"])
if commit:
user.save()
return user
class Register(CreateView):
model = User
form_class = UserCreationForm
success_url = '/account/'
But there'll be other problems like duplication of username.

Showing custom model validation exceptions in the Django admin site

I have a booking model that needs to check if the item being booked out is available. I would like to have the logic behind figuring out if the item is available centralised so that no matter where I save the instance this code validates that it can be saved.
At the moment I have this code in a custom save function of my model class:
def save(self):
if self.is_available(): # my custom check availability function
super(MyObj, self).save()
else:
# this is the bit I'm stuck with..
raise forms.ValidationError('Item already booked for those dates')
This works fine - the error is raised if the item is unavailable, and my item is not saved. I can capture the exception from my front end form code, but what about the Django admin site? How can I get my exception to be displayed like any other validation error in the admin site?
In django 1.2, model validation has been added.
You can now add a "clean" method to your models which raise ValidationError exceptions, and it will be called automatically when using the django admin.
The clean() method is called when using the django admin, but NOT called on save().
If you need to use the clean() method outside of the admin, you will need to explicitly call clean() yourself.
http://docs.djangoproject.com/en/dev/ref/models/instances/?from=olddocs#validating-objects
So your clean method could be something like this:
from django.core.exceptions import ValidationError
class MyModel(models.Model):
def is_available(self):
#do check here
return result
def clean(self):
if not self.is_available():
raise ValidationError('Item already booked for those dates')
I haven't made use of it extensively, but seems like much less code than having to create a ModelForm, and then link that form in the admin.py file for use in django admin.
Pretty old post, but I think "use custom cleaning" is still the accepted answer. But it is not satisfactory. You can do as much pre checking as you want you still may get an exception in Model.save(), and you may want to show a message to the user in a fashion consistent with a form validation error.
The solution I found was to override ModelAdmin.changeform_view(). In this case I'm catching an integrity error generated somewhere down in the SQL driver:
from django.contrib import messages
from django.http import HttpResponseRedirect
def changeform_view(self, request, object_id=None, form_url='', extra_context=None):
try:
return super(MyModelAdmin, self).changeform_view(request, object_id, form_url, extra_context)
except IntegrityError as e:
self.message_user(request, e, level=messages.ERROR)
return HttpResponseRedirect(form_url)
The best way is put the validation one field is use the ModelForm... [ forms.py]
class FormProduct(forms.ModelForm):
class Meta:
model = Product
def clean_photo(self):
if self.cleaned_data["photo"] is None:
raise forms.ValidationError(u"You need set some imagem.")
And set the FORM that you create in respective model admin [ admin.py ]
class ProductAdmin(admin.ModelAdmin):
form = FormProduct
I've also tried to solve this and there is my solution- in my case i needed to deny any changes in related_objects if the main_object is locked for editing.
1) custom Exception
class Error(Exception):
"""Base class for errors in this module."""
pass
class EditNotAllowedError(Error):
def __init__(self, msg):
Exception.__init__(self, msg)
2) metaclass with custom save method- all my related_data models will be based on this:
class RelatedModel(models.Model):
main_object = models.ForeignKey("Main")
class Meta:
abstract = True
def save(self, *args, **kwargs):
if self.main_object.is_editable():
super(RelatedModel, self).save(*args, **kwargs)
else:
raise EditNotAllowedError, "Closed for editing"
3) metaform - all my related_data admin forms will be based on this (it will ensure that admin interface will inform user without admin interface error):
from django.forms import ModelForm, ValidationError
...
class RelatedModelForm(ModelForm):
def clean(self):
cleaned_data = self.cleaned_data
if not cleaned_data.get("main_object")
raise ValidationError("Closed for editing")
super(RelatedModelForm, self).clean() # important- let admin do its work on data!
return cleaned_data
To my mind it is not so much overhead and still pretty straightforward and maintainable.
from django.db import models
from django.core.exceptions import ValidationError
class Post(models.Model):
is_cleaned = False
title = models.CharField(max_length=255)
def clean(self):
self.is_cleaned = True
if something():
raise ValidationError("my error message")
super(Post, self).clean()
def save(self, *args, **kwargs):
if not self.is_cleaned:
self.full_clean()
super(Post, self).save(*args, **kwargs)