Overriding Django Default Authentication Form - django

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)}

Related

How to skip or remove password field in simplejwt token authentication in django rest framework?

My requirement is, I don't wanted to enter password in simplejwt token authentication. I have added one extra field in the authentication by inheriting the init() method of TokenObtainPairSerializer
as per my requrements.
Currently, I am passing None as in password field but still its showing to user (djnago admin portal). What I want is, I don't wanted to show the password field to user while authentication using simplejwt.
below is my code,
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
class CustomSerializer(TokenObtainPairSerializer):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields[self.username_field] = serializers.CharField()
self.fields['password'] = PasswordField(default=None)
self.fields['extra'] = serializers.CharField()
def validate(self, attrs):
pass
Is there any ways to set PasswordField as unusable so it wont show to user?
I have followed the below mentioned process to solve the problem,
Override the TokenObtainPairSerializer class __init__ method like below,
Use del self.fields['password'], so It wont ask you the password and add whatever fields you want.
class CustomSerializer(TokenObtainPairSerializer):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields[self.username_field] = serializers.CharField()
del self.fields['password']
This works really well. There is a almost same question I have answered, You can check it here for more knowledge.
Let me know if anyone have better solution of this problem.

Django-registration form without email field

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?

Get current user in Django admin

I have a posting object that can be either accessed in the website or the admin panel. In both, the user is automatically assigned to the post when the user posts it. In the website area, it works fine. However, it does not work in the admin area. First, I tried just having the form input there. When I try to save the object and leave the input blank, it tells me the form has no value. Then, trying to see if I just put in a random value and see if it was overwritten, I did that. However, that random value was not overwritten with the current user. If I excluded the field, when I try to save the model I get an Integrity error saying the field author 'may not be NULL', so I'm assuming my save_model() function is not firing right at all. Now the code I'm using for this I've seen all over the internet and people claim for it to work, I don't know if it's just broken now or what. Here's my code:
from django.contrib import admin
from posting.models import Posting, Categories
class PostingAdmin(admin.ModelAdmin):
list_display = ("title","author", "article","date")
exclude = ('author',)
fieldsets = (
(None, {
'fields': ('title',)
}),
('Body', {
'fields': ('article',)
}),
)
def save_model(self,request,form,obj,change):
print 'ENTERING SAVE_MODEL FUNCTION'
if not change:
obj.author = request.user
print 'OBJ.AUTHOR:' + str(obj.author)
obj.save()
print "EXITING SAVE_MODEL FUNCTION"
admin.site.register(Posting, PostingAdmin)
I added this for information only as I came across this post which made me look deeper for an issue I was having that was similar...
To pre-populate an admin field in Django 1.11 from "request" data, see below example of a models "user" field being pre-populated with the logged in user:
admin.py
class PostingAdmin(admin.ModelAdmin):
def get_changeform_initial_data(self, request):
return {'user': request.user}
This populates the field when initially adding a new "Posting Admin" (model instance) before it has been saved for the first time.
You could override the ModelAdmin.get_form, by adding the request as an attribute of the newly created form class .
class EntryAdmin(admin.ModelAdmin):
form = EntryAdminForm
def get_form(self, request, *args, **kwargs):
form = super(EntryAdmin, self).get_form(request, *args, **kwargs)
form.request = request
return form
This works for me:
from django.contrib import admin
from page.models import Page
class PageAdmin(admin.ModelAdmin):
def get_form(self, request, *args, **kwargs):
form = super(PageAdmin, self).get_form(request, *args, **kwargs)
form.base_fields['author'].initial = request.user
return form
admin.site.register(Page, PageAdmin)
I know i am a bit late for posting this solution, but like me if anyone else come across you may try:
def save_model(self, request, obj, form, change):
if getattr(obj, 'author', None) is None:
obj.author = request.user
obj.save()

How to clean form data depending on logged-in user in django admin panel?

I've looked at several questions here that looked similar, but none of them discussed the problem from the perspective of admin panel.
I need to check if user has permission to leave a field empty. I wanted to use request.user but I don't knot how to pass request from EntryAdmin to ModelForm. I wanted to do something like this:
class EntryAdminForm(ModelForm):
class Meta:
model = Entry
def clean_category(self):
if not self.request.user.has_perm('blog.can_leave_empty_category') and not bool(self.category):
raise ValidationError(u'You need to choose a Category!')
else:
return self.cleaned_data['category']
You could override the ModelAdmin.get_form, by adding the request as an attribute of the newly created form class (should be thread-safe).
Something along these lines:
class EntryAdmin(admin.ModelAdmin):
form = EntryAdminForm
def get_form(self, request, *args, **kwargs):
form = super(EntryAdmin, self).get_form(request, *args, **kwargs)
form.request = request
return form
Then the code in your question should work.

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)