forms validationerror sends me to a ValidationerError page - django

Ive been struggling with this problem for days now. As you se the validation error works but i want the error to show in the form and not redirect the user to the ValidationError page. What am i missing? I use django Alluth
def custom_signup(self, request, user):
user.profile.pid = self.cleaned_data[_("pid")]
data = User.objects.filter(profile__pid=user.profile.pid)
if data.exists():
raise forms.ValidationError(
_('This user exists in our system. Please try another.'),
code='unique_pid'
)
else:
user.save()
return user

Ok, so first you need to create a custom signup form, I've detailed how that is done in answer to this question
What you're seeing there is a 500 page, in debug mode (so you get all the information about what's happened). The reason that you're seeing this is that you are raising an error.
What you want to do, is to add an error to a form as part of that form's validation.
Once you've created your custom signup form, you can add your validation as part of the form's clean method;
def clean(self):
"""
Clean the form
"""
cleaned_data = super().clean()
pid = self.cleaned_data["pid"]
if User.objects.filter(profile__pid=pid).exists():
self.add_error(
'pid',
_('This user exists in our system. Please try another.'),
)
return cleaned_data
Please note, you're also using translation (_("")) to access the form's cleaned_data - you don't need to do this.

Related

Conditionally Access and Direct User in Django Class-Based View

I have a Django custom form classed-based view. Under normal conditions I want it to be accessible to both authenticated and logged out or anonymous visitors. However, under certain conditions I'd like it to alert the user they need to login to submit the form (and redirect them). Example:
class CustomFormView(FormView):
...
def form_valid(self, form):
user = self.request.user
req_id = self.request.GET.get("req_id")
if req_id:
errors = False
if not user.is_authenticated():
messages.error(self.request, "You must be logged in to fill out this form. Please sign in, then visit this link again.")
errors = True
# redirect
try:
...
if errors:
ctx = self.get_context_data()
return self.render_to_response(ctx)
I'm aware of LoginRequiredMixin (docs) as well as a decorator #method_decorator(login_required) but I don't want to apply it at the view level or to the entire form_valid() function, only check login state when if req_id condition is met. Currently the view's not executing my if not user.is_authenticated(): so my attempt isn't correct. Is there a way to accomplish this within form_valid()? thanks

Django field cleaning ValidationErrors don't prevent form from processing

I'm designing a Django form with custom cleaning methods for both fields, and the form itself.
Ideally, I'd love for my form to stop processing and throw an error if my fields don't validate. However, the custom clean() method that I wrote for my form runs even when fields throw ValidationErrors.
Here's an example:
forms.py
from django import forms
from .models import User
class BasicsForm(forms.Form):
email = forms.EmailField(label='E-mail address', max_length=128)
def clean_email(self):
email = self.cleaned_data['email']
if User.objects.filter(email=email).exists():
raise forms.ValidationError("E-mail is already taken.")
return email
def clean(self):
# Call the parent clean method
cleaned_data = super().clean()
email = cleaned_data.get('email')
u = User(email=email)
u.save()
If I attempt to submit the above form with an invalid e-mail address (for example, an e-mail already registered on the site, which will raise the ValidationError within clean_email), I get an IntegrityError that says I can't add a NULL e-mail to my database. What's happening is that even though clean_email catches an error, the lines that create a user in my clean() method (i.e., u = User(email=email) and u.save()) still run.
How do I make it so that if my clean_email() method catches an error, clean() doesn't run, and my form instead shows the error thrown by clean_email()?

Django Integrity Error when adding post in a form that excludes a foreign key

the cause of the error is simple. The admin site asks me to select or browse user when I am logged in. So, I excluded the field to hide it in the admin form. It generates the integrity error.
How do I tell django to attach the currently logged in user (in the admin area) as the creator of the object?
I have seen a few posts that require me to make use of forms.py but I want to use the default admin template. Where do I make the edits at least?
Like that:
class ObjectAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
obj.user = request.user
obj.save()

Model form update page show to all register users

I have this page :8000/edit/6/ that show a form to update an exciting model and i logged in as X, if i looged in as Y and try to open that page i can see it and update. So this is with no doubt a big bug and dangerous.
Here is my view code
class VideoUpdate(UpdateView):
form_class = VideoForm
model = Video
template_name = 'videos/video_update.html'
#method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(VideoUpdate, self).dispatch(*args, **kwargs)
def form_valid(self, form):
messages.info(self.request, _('Event is updated successfully'))
return super(VideoUpdate, self).form_valid(form)
Is there a way to check the model object id with the user id. A simple question from a newbie
Solution:
Actually there are two solutions that works for me in views.py, one is using the get_queryset method
def get_queryset(self):
base_qs = super(VideoUpdate, self).get_queryset()
return base_qs.filter(user=self.request.user.get_profile)
or using get_object method
def get_object(self):
video = get_object_or_404(Video, pk=self.kwargs['pk'])
if video.user != self.request.user.get_profile():
raise Http404
return video
Your question is not entirely clear to me but I think you want to restrict a view from registered but unauthorized users. Usually, this can be better achieved in your views instead of your models:
# views.py
def edit_form(request, parameter_indicating_user):
user = request.user
if #some logic:
# if user is equal to the user indicated by some parameter
# (id, username, etc) then allow that view to be rendered
else:
raise Http404 # or redirect the unauthorized user
I am interpreting your question as meaning the following.
When using class-based views - is there a way to control whether the specific instance of a form is editable by a given user ie. we have record #1 of a model. When you are logged in as user X you can edit record #1, but user Y is not allowed to edit record #1.
If this is what you are talking about you are going to require row/object level permissions, which I have found is best when using django-guardian.
Specifically, when using class-based views you can use the PermissionRequiredMixin, which can be found here: http://packages.python.org/django-guardian/api/guardian.mixins.html#permissionrequiredmixin
If you are looking for just controlling whether User X vs. User Y can edit any instance of that form. ie. User X can edit Form A values. Then you will just need to manage the permissions appropriately and then check if the user has that permission in the view.
JD

Django: customizing the message after a successful form save

whenever I save a model in my Admin interface, it displays the usual "successfully saved message."
However, I want to know if it's possible to customize this message because I have a situation where I want to warn the user about what he just saved and the implications of these actions.
class PlanInlineFormset(forms.models.BaseInlineFormset):
def clean(self):
### How can I detect the changes?
### (self.changed_data doesn't work because it's an inline)
### and display what he/she just changed at the top AFTER the successful save?
class PlanInline(admin.TabularInline):
model = Plan
formset = PlanInlineFormset
Django (> version 1.2) uses the messages framework for admin messages. You can add additional messages using that interface. Here's an example:
from django.contrib import messages
class SomeModelAdmin(admin.ModelAdmin):
# your normal ModelAdmin stuff goes here
def save_model(self, request, obj, form, change):
# add an additional message
messages.info(request, "Extra message here.")
super(SomeModelAdmin, self).save_model(request, obj, form, change)
To detect changes to the object being saved, you should be to override the save_model method of ModelAdmin, and compare the object the method is passed to the version currently in the database. To do this in the case of inlines, you can override the save_formset method. A possible approach might look like (untested code):
class SomeModelAdmin(admin.ModelAdmin):
# your normal ModelAdmin stuff goes here
def save_formset(self, request, form, formset, change):
if not change:
formset.save()
else:
instances = formset.save(commit=False)
for instance in instances:
try:
# if you've got multiple types of inlines
# make sure your fetching from the
# appropriate model type here
old_object = SomeOtherModel.get(id=instance.id)
except SomeOtherModel.DoesNotExist:
continue
if instance.field_x != old_object.field_x:
messages.info(request, "Something Changed")
instance.save()
formset.save_m2m()
If you're using Django 1.2 or newer, the messages framework may hold the answer.
http://docs.djangoproject.com/en/dev/ref/contrib/messages/