not show field in form if user is authenticated - python

I do not want to show one form field if user is authenticated.
I tried if not request.user.is_authenticated():
but it's not working.
def create_event(request):
if not request.user.is_authenticated():
CreateEventForm.base_fields['owner_email'] = forms.EmailField(required=True)
event_form = CreateEventForm(request.POST or None, prefix='event')
context = {
'event_form': event_form,
}
if event_form.is_valid():
event = event_form.save(commit=False)
if request.user.is_authenticated():
event.registered_owner = request.user
else:
event.owner_email = event_form.cleaned_data.get('owner_email')
event = event_form.save()
return HttpResponseRedirect('/event-%s' %event.id)
return render(request, 'create_event.html', context)
Form in forms.py
class CreateEventForm(forms.ModelForm):
class Meta:
model = Event
fields = ['title', 'description', 'location', 'duaration', 'private']

You should never modify base_fields; that's a class attribute, so once you add something to it, it's present for all form instances until you explicitly remove it.
Instead, move this logic into the __init__ method for the form itself.
class CreateEventForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
is_authenticated = kwargs.pop('is_authenticated', False)
super(CreateEventForm, self).__init__(*args, **kwargs)
if is_authenticated:
self.fields['owner_email'] = forms.EmailField(required=True)
Now in your view you need to pass that parameter to the form:
event_form = CreateEventForm(request.POST or None, prefix='event', is_authenticated=request.user.is_authenticated())

Related

How to show excluded form fields in ModelAdmin?

I have a simple CategoryForm which has a hidden field that automatically gets added during save on the front-end. In the Admin panel I would like is_staff users to be able to add a Category while the field is hidden there as well. To superusers I would like the field to be shown. How do I get the excluded fields back in my Admin form?
Forms.py:
class CategoryForm(forms.ModelForm):
class Meta:
model = Category
fields = ('category', 'company',)
exclude = ['company']
widgets = {'company': forms.HiddenInput()}
Admin.py:
class CustomCategoryAdmin(admin.ModelAdmin):
form = CategoryForm
def get_form(self, request, obj=None, **kwargs):
form = super().get_form(request, obj, **kwargs)
if not request.user.is_superuser:
self.fields = ('category',)
else:
self.fields = ('category', 'company',) # this throws a key error because company is excluded
return form
def save_related(self, request, form, formsets, change):
super(CustomCategoryAdmin, self).save_related(request, form, formsets, change)
company = request.user.company
form.instance.company.add(company) # add object to company field while saving
What I decided to do was create another form named AdminCategoryForm and set the form = AdminCategoryForm as an attribute of CustomCategoryAdmin.
So now my Forms.py:
class CategoryForm(forms.ModelForm):
class Meta:
model = Category
fields = ('category', 'company',)
exclude = ['company']
widgets = {
'company': forms.HiddenInput()
}
class AdminCategoryForm(forms.ModelForm):
class Meta:
model = Category
fields = ('category', 'company',)
And my Admin.py:
class CustomCategoryAdmin(admin.ModelAdmin):
form = AdminCategoryForm
def get_form(self, request, obj=None, **kwargs):
form = super().get_form(request, obj, **kwargs)
if not request.user.is_superuser:
self.fields = ('category',)
else:
self.fields = ('category', 'company',)
self.filter_horizontal = ('company',)
return form
def save_related(self, request, form, formsets, change):
super(CustomCategoryAdmin, self).save_related(request, form, formsets, change)
company = request.user.company
form.instance.company.add(company)
Even though I am repeating my code I feel that this may be the more elegant solution than overriding a ModelAdmin method as it becomes much more clear to outside programmers what is going on here.
If anybody else has other solutions I would love to hear..

Django Forms - dynamic choice field filtering

I am trying to dynamically filter which choices are displayed in a form. the form fields are generated from model. Currently all choices are being displayed without any filters applying.
in the view I get the currents site_type then pass this to the form, to filter the subnets that also have the same site_type, or this is whats supposed to happen anyway.
can anyone see why the filter would not be applying?
forms.py
class AutoSubnetForm(forms.Form):
subnet_type_data = SubnetTypes.objects.all()
def __init__(self, *args, **kwargs):
self.site_type = kwargs.pop("site_type")
# get site type if set and filter against it
if self.site_type:
self.subnet_type_data = SubnetTypes.objects.filter(related_sites=self.site_type)
super(AutoSubnetForm, self).__init__(*args, **kwargs)
# create list for types
subnet_types = []
for stype in subnet_type_data:
# add tuple for each type
subnet_types.append((stype.id,stype.subnet_type))
subnets = forms.MultipleChoiceField(
choices=subnet_types,
widget = forms.CheckboxSelectMultiple(
attrs = {'class': 'form-control'}
)
)
views.py
#login_required
#user_passes_test(lambda u: u.has_perm('config.add_subnet'))
def auto_gen_subnets(request, site_id):
#generate_subnets(site_id)
from config.models import SubnetTypes
site_data = get_object_or_404(SiteData.objects.select_related('site_type'),pk=site_id)
subnets = None
if request.method == 'GET':
form = AutoSubnetForm(site_type=site_data.site_type)
else:
# A POST request: Handle Form Upload
form = AutoSubnetForm(request.POST)
# If data is valid, proceeds to create a new post and redirect the user
if form.is_valid():
subnets = form.cleaned_data['subnets']
return render(request, 'sites/generate_subnets.html', {
'data': subnets,
'form': form,
'SiteName' : site_data.location,
'SiteID' : site_id,
}
)
If you are generating form from the model you need ModelMultipleChoiceField.
Try something like this:
class AutoSubnetForm(forms.Form):
def __init__(self, *args, **kwargs):
site_type = kwargs.pop("site_type")
queryset = SubnetTypes.objects.all()
if site_type:
queryset = queryset.filter(related_sites=site_type)
super(AutoSubnetForm, self).__init__(*args, **kwargs)
self.fields['the_name_of_your_form_field'] = forms.ModelMultipleChoiceField(
queryset=queryset,
widget = forms.CheckboxSelectMultiple(
attrs = {'class': 'form-control'}
)
)

Passing Request to Django form Still shows self not defined

I am currently using Python and Django to make a Web Application. As my title states I am trying to pass the request down to one of my form classes so I can use user data. I know there are a lot of questions on this, but I have tried each one of them and it does not allow me to access the user parameter.
My Code:
Form Class:
class CreateEventForm(forms.ModelForm):
def __init__(self, request, *args, **kwargs):
self.request = request
super(CreateEventForm, self).__init__(*args, **kwargs)
name = forms.CharField(widget=forms.TextInput(attrs={'class': 'form-control'}))
image = forms.CharField(widget=forms.TextInput(attrs={'class': 'form-control'}))
description = forms.CharField(widget=forms.Textarea(attrs={'class': 'form-control'}))
location = forms.CharField(widget=forms.TextInput(attrs={'class': 'form-control'}))
ticket_name = forms.CharField(widget=forms.TextInput(attrs={'class': 'form-control'}))
event_owner = forms.ModelChoiceField(queryset=EventOwner.objects.all().filter())
ticket_price = forms.CharField(widget=forms.TextInput(attrs={'class': 'form-control'}))
class Meta:
model = Event
fields = ['name', 'image', 'description', 'category', 'event_owner', 'ticket_name', 'ticket_price', 'location']
My View:
class CreateEventView(View):
form_class = CreateEventForm
template_name = 'create-event.html'
def get(self, request):
form = self.form_class(request, request.POST)
if request.user.is_authenticated:
# Now check to make sure the user has created an "Event Organiser" name
eo = EventOwner.objects.filter(owner_id=request.user.id)
# If there has been an event owner made
if eo.count() > 0:
return render(request, self.template_name, {'form': form})
# Else send the user to the create event owner
else:
messages.warning(request, 'You must have an organiser profile setup before creating an event.')
return redirect('/create-organiser')
else:
messages.success(request, 'You have to login before you can create an event.')
return redirect('/login')
However when ever I try to use self.request it does not work. It says unresolved reference "self"
The above still works no problem, but I was confusing some stuff from the init section. Leave init the way it is.
By creating a query set of all objects first and then overwriting them as follows, I was able to limit the query set by filtering it with the request.user parameter:
class CreateEventForm(forms.ModelForm):
event_owner = forms.ModelChoiceField(queryset=User.objects.all())
def __init__(self, request, *args, **kwargs):
self.request = request
super(CreateEventForm, self).__init__(*args, **kwargs)
self.fields['event_owner'].queryset = EventOwner.objects.filter(owner=self.request.user)

How To Exclude A Value In A ModelMultipleChoiceField?

I do not want the logged in user to show up on this ModelMultipleChoiceField in order to restrict themselves from creating a following relationship with themselves? So how do I exclude the logged in user from the queryset, probably an easy fix but I'm new to Django and it has eluded me for a few hours now.
forms.py
class Add_Profile(forms.ModelForm):
def __init__(self,*args, **kwargs): # initializing your form in other words loading it
super(Add_Profile, self).__init__(*args, **kwargs)
user_id = kwargs.pop('user_id') # taking user_id out of the querylist
self.fields['follows'] = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple(), queryset=UserProfile.objects.filter(~Q(id=user_id)))
class Meta:
model = UserProfile
fields = (
'bio',
'follows',
'theme',
'profile_picture',
)
Views.py
#login_required
def edit_profile(request, user_id):
userprofile = UserProfile.objects.get(pk=user_id)
if request.method == 'POST':
edit_profile = Add_Profile(request.POST, request.FILES, instance=userprofile, user_id=request.user.id)
if edit_profile.is_valid():
edit_profile.save()
return redirect('/home/user/{0}/'.format(request.user.username))
else:
print edit_profile.errors
else:
edit_profile = Add_Profile(instance=userprofile, user_id=request.user.id)
return render (request, 'edit.html', {'form': edit_profile,})
Error: init() got an unexpected keyword argument 'user_id'
You can definitely do it using forms.Form instead of forms.ModelForm with something along the lines of this example in the docs:
from django import forms
from django.contrib.auth import get_user_model
class Add_Profile(forms.Form):
follows = forms.ModelMultipleChoiceField(queryset=None)
def __init__(self, user=None, *args, **kwargs):
super(Add_Profile, self).__init__(*args, **kwargs)
if user is not None:
self.fields['follows'].queryset = get_user_model().objects.exclude(pk=user.pk)
else:
self.fields['follows'].queryset = get_user_model.objects.all()
Just pass in the user you wish to exclude when you instantiate the form:
form = Add_Profile() # all users will be present in the dropdown
some_guy = User.objects.get(pk=4)
form = Add_Profile(user=some_guy) # all users except some_guy will be present
Define an __init__ method for the form class. Pass the logged in userid to the form while initializing it, this will work with a model form.
def __init__(self, *args, **kwargs):
user_id = kwargs.pop('user_id')
super(Add_Profile, self).__init__(*args, **kwargs)
self.fields['follows'] = forms.ModelMultipleChoiceField(queryset=UserProfile.objects.filter(~Q(user_id=user_id)))
While initializing your form, you can pass user_id
address_form = Add_Profile(request.POST, user_id=request.user.id)

django update view and passing context

I have a update view:
class GeneralUserUpdateView(UpdateView):
model = GeneralUser
form_class = GeneralUserChangeForm
template_name = "general_user_change.html"
def dispatch(self, *args, **kwargs):
return super(GeneralUserUpdateView, self).dispatch(*args, **kwargs)
def post(self, request, pk, username):
self.pk = pk
self.username = username
self.gnu = GeneralUser.objects.get(pk=self.pk)
#form = self.form_class(request.POST, request.FILES)
return super(GeneralUserUpdateView, self).post(request, pk)
def form_valid(self, form, *args, **kwargs):
self.gnu.username = form.cleaned_data['username']
self.gnu.email = form.cleaned_data['email']
self.gnu.first_name = form.cleaned_data['first_name']
self.gnu.last_name = form.cleaned_data['last_name']
self.gnu.address = form.cleaned_data['address']
self.gnu.save()
return redirect("user_profile", self.pk, self.username)
Here in this view I want to pass a context like:
context['picture'] = GeneralUser.objects.get(pk=self.pk)
I did trying get_context_data but I cant access pk in there..
Am I doing the update right?? How can I pass that context in there??
You shouldn't be overriding post at all. All of that logic should happen in get_context_data.
In fact, none of your overrides are needed. Everything that you do in form_valid will be done already by the standard form save. And overriding dispatch just to call the superclass is pointless.
Your view should look like this only, with no overridden methods at all:
class GeneralUserUpdateView(UpdateView):
model = GeneralUser
form_class = GeneralUserChangeForm
template_name = "general_user_change.html"
context_object_name = 'picture'
(although it seems a little odd that you want to refer to an instance of GeneralUser as "picture").
Edit to redirect to a specific URL, you can define get_success_url:
def get_success_url(self):
return reverse("user_profile", self.kwargs['pk'], self.kwargs['username'])

Categories

Resources