Pass username to Django form - python

I have a custom Form where I need to pass in the request.user.username so I can use that to fill out forms.ModelChoiceField based on what user is accessing it.
Here is what I have
views.py
if request.method == 'POST':
form = DepartmentForm(request.POST, username=request.user.username)
# Do stuff
else:
form = DepartmentForm(username=request.user.username)
forms.py
class DepartmentForm(forms.Form):
def __init__(self, *args, **kwargs):
self.username = kwargs.pop('username', None)
super(DepartmentForm, self).__init__(*args, **kwargs)
Company = forms.ModelChoiceField(queryset=Company.objects.raw('''
SELECT DISTINCT c.id, c.name, c.createdBy, c.allowedTeam_ID FROM projects_company AS c
LEFT JOIN auth_user_groups AS aug ON c.allowedTeam_id=aug.group_id
LEFT JOIN auth_user AS au ON aug.user_id=au.id
WHERE au.username = %s OR c.createdBy = %s''',
[self.username, self.username]),
empty_label='Select company', widget=forms.Select(attrs={'class': 'materialSelect', 'id': 'companyDropdown'}))
But when I try to select fill out self.username, I get:
NameError: name 'self' is not defined
I tried searching for my solution, but none of the ones I found seem to work.
I would appreciate any help you guys can give.
If you need more information, please don't hesitate to ask, and I will update the question accordingly.
This is the error I'm getting:
line 25, in DepartmentForm
[self.username, self.username]),
NameError: name 'self' is not defined
Which is the end of the query where I select based on self.username

The line Company = forms.ModelChoiceField() is evaluated when the module is loaded. You don't have access to self.username at that point.
Instead, you should set the queryset in the form's __init__ method:
class DepartmentForm(forms.Form):
company = forms.ModelChoiceField(
queryset=Company.objects.none(), # use empty queryset now, we'll set the real queryset when the form is initialised
widget=forms.Select(...),
)
def __init__(self, *args, **kwargs):
self.username = kwargs.pop('username', None)
super(DepartmentForm, self).__init__(*args, **kwargs)
self.fields['company'].queryset = Company.objects.raw(...)

You can pre-fill any field with a dictionary:
if request.method == 'POST':
# do stuff
else:
form = DepartmentForm({"username":request.user.username})
or
if request.method == 'POST':
# do stuff
else:
form = DepartmentForm()
form.initial = {"username":request.user.username}

Related

Django Form field created in __init__ does not exist in request.POST

Form.py
class FormA(forms.ModelForm):
fieldA = forms.CharField(required=True)
fieldB = forms.CharField(required=True)
def __init__(self, *args, **kwargs):
super(OfflineAccountEditForm, self).__init__(*args, **kwargs)
self.fields['fieldC'] = forms.CharField(required=True)
class Meta:
model = Profile
fields = ('username','first_name','last_name')
As you can see, I try to initiate a new field named fieldC in init function. During request 'get' method, it display nicely on form.
However, when I submit form, i print out my form, the fieldC field is missing.
if request.method == 'GET':
if obj:
form = FormA(instance=obj)
else:
form = FormA()
else:
if obj:
form = FormA(request.POST, instance=obj)
else:
form = FormA(request.POST)
print form
When I run cleaned_data, it can't find the field.
fieldC = form.cleaned_data['fieldC']
Any solution? Please guide. Thanks in advance and appreciate your help.
Could it be because you did not indent your __init__() method? or Meta class.

Django forms selecting data based on request user

I am developing a django application which has a form for creating ingredients. The form contains a dropdown for selecting Recipes. When a user creates an ingredient, in the dropdown, I want that only those recipes should appear that are created by the same user.
Here is my code:
#forms.py
class IngredientForm(forms.ModelForm):
primal = forms.BooleanField()
class Meta:
model = Ingredient
fields = ('recipe_id', 'title', 'instructions', 'rules')
#models.py
class Recipe(models.Model):
user = models.ForeignKey('auth.User')
title = models.CharField(max_length=500)
description = models.TextField(max_length=500)
rules = models.TextField(max_length=500,blank=True)
def __str__(self):
return self.title
class Ingredient(models.Model):
user = models.ForeignKey('auth.User')
recipe_id = models.ForeignKey(Recipe, on_delete=models.CASCADE)
title = models.CharField(max_length=500)
instructions = models.CharField(max_length=500)
rules = models.TextField(max_length=500,blank=True)
primal = models.CharField(default='0',max_length=500,blank=True)
def __str__(self):
return self.title
#views.py
def create_ingredient(request):
if request.method == 'POST':
form = IngredientForm(request.POST)
if form.is_valid():
current_user = request.user
data = form.cleaned_data
ingredient_data=Ingredient.objects.create(user=current_user, recipe_id=data['recipe_id'],title=data['title'], primal=data['primal'], instructions=data['instructions'], rules=data['rules'])
ingredient_data.save()
ingredient = Ingredient.objects.get(pk = ingredient_data.pk)
return redirect('ingredient_detail', pk=ingredient.pk)
else:
messages.error(request, "Error")
return render(request, 'create_ingredient.html', {'form': IngredientForm })
The problem is that right now, when the user tries to select a recipe, the recipes created by all users of the site appear in the 'recipe_id' dropdown. He should only be able to see recipes in the dropdown that are created by himself. Any ideas how to do it?
UPDATE FROM ANSWER:
If I use this:
...
if request.method == 'POST':
form = IngredientForm(current_user=request.user, request.POST)
if form.is_valid():
...
it gives me this syntax error: non-keyword arg after keyword arg in this line form = IngredientForm(current_user=request.user, request.POST)
UPDATE#2:
If I use:
...
if request.method == 'POST':
form = IngredientForm( request.POST,current_user=request.user)
if form.is_valid():
...
It gives me error: __init__() got multiple values of argument 'current.user'
If I use:
...
if request.method == 'POST':
form = IngredientForm( request.POST)
if form.is_valid():
...
It gives me error: 'QueryDict' object has no attribute 'id'
UPDATE # 3:
After implementing the latest update from answer. It gives me error name 'current_user' is not defined
in the following piece of code:
def create_ingredient(request):
form = IngredientForm(current_user=request.user)
In the model form you can do this:
class IngredientForm(ModelForm):
primal = forms.BooleanField()
class Meta:
model = Ingredient
fields = ('recipe_id', 'title', 'instructions', 'rules')
def __init__(self, current_user, *args, **kwargs):
super(IngredientForm, self).__init__(*args, **kwargs)
self.fields['recipe_id'].queryset = self.fields['recipe_id'].queryset.filter(user=current_user.id)
then instantiate the form like so
form = IngredientForm(current_user=request.user)
EDIT #1:
Passing in the user to the POST request form:
if request.method == "POST":
form = IngredientForm(request.POST, current_user=request.user)
if form.is_valid():
....
EDIT #2:
Try changing the init decleration to what is below and pop the user from the kwargs:
def __init__(self, *args, **kwargs):
current_user = kwargs.pop('current_user', None)
super(IngredientForm, self).__init__(*args, **kwargs)
if current_user:
self.fields['recipe_id'].queryset = self.fields['recipe_id'].queryset.filter(user=current_user.id)
I think this might solve your problems, leave the rest of the code the same as my answer above (where you create the forms)

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)

request.user in Django Form

I'm having a problem accessing a Django Form POST data.
I need to pass request.user to the form, so:
class TradeForForm(forms.Form):
def __init__(self, *args, **kwargs):
user = kwargs.pop('user')
else:
request = kwargs.pop('request')
super(TradeForForm, self).__init__(*args, **kwargs)
#Obtain items for user
if user:
print user
items = Item.objects.filter(user=user)
choices = []
for i in range(len(items)):
choices.append([i,items[i].name])
self.fields['item_to_be_traded_for'].choices = choices
trade_type = forms.ChoiceField(
widget=RadioSelect(),
choices = [
['0','Item'],
['1','Money offer'],
]
)
item_to_be_traded_for = forms.ChoiceField()
and then call it using:
def trade_for(request, item_id):
item = Item.objects.get(id=item_id)
if request.method == 'POST':
form = TradeForForm(request.POST)
if form.is_valid():
pass
else:
form = TradeForForm(user=request.user)
variables = RequestContext(request, {
'form': form,
'item': item,
})
return render_to_response('trade_for.html', variables)
Now the problem is, when doing GET to access the empty form, it works just fine. But when I post it, I received an error:
KeyError at /trade_for/1/
'user'
Request Method: POST
Request URL: http://localhost:8000/trade_for/1/
Django Version: 1.3.1
Exception Type: KeyError
Exception Value:
'user'
Now how can this be fixed? I assume it's because the user variable is not passed to the form when creating it using the request.POST data, but I want to be able to create the form with the user parameter and without it, both working.
you should probably pass the user to the form creator even with POST data so the choices can be validated properly, so
TradeForForm(request.POST, user=request.user)
if you don't want this, you need to change user = kwargs.pop('user') to something like
user = kwargs.pop('user', None)
# if kwargs has no key 'user', user is assigned None
# make sure your code handles this case gracefully
pop will raise a KeyError unless it has a default value. So you just need to pass it a default value - probably None:
user = kwargs.pop('user', None)
If you want the form to work without the user, change the constructor to:
user = kwargs.pop('user', None)
But then you have to be able to deal with user being None.
The suggestion of user = kwargs.pop('user', None) is part of your missing code. A better approach would be to drop in your own arguments to avoid all the popping!
class TradeForForm(forms.Form):
def __init__(self, user=None, request=None, *args, **kwargs):
super(TradeForForm, self).__init__(*args, **kwargs)
if user:
...code here...

Validate form A's data by usuing form B's data

So I have these two forms. I would like to be able to access the data in form env_form when I am checking add_uRG for my other form. Is it possible to do this? My env form is a very common form through out my app so I would like to keep it separate instead of including it on every form.
class env_form(forms.Form):
env = forms.ChoiceField(choices=ENV, required=True)
class add_uRG(forms.Form):
user = forms.CharField(max_length=50)
group = forms.CharField(required=True)
role = forms.CharField(required=True)
def clean_user(self):
post_user = self.cleaned_data['user']
post_env = self.cleaned_data['env']
c = User.objects.filter(user__contains=post_user, env__contains=post_env ).count()
if (c == 0):
raise forms.ValidationError(u"User Not Found.")
else:
user_info = User.objects.filter(user__contains=post_user).values('password').distinct().count()
user_env = User.objects.filter(user__contains=post_user).values('env').distinct().count()
if not (user_env == user_info):
raise forms.ValidationError(u'User is using same password')
return(post_user)
If I'm reading your question correctly, I think that form inheritance could be used here.
class env_form(forms.Form):
env = forms.ChoiceField(choices=ENV, required=True)
class add_uRG(env_form):
user = forms.CharField(max_length=50)
group = forms.CharField(required=True)
role = forms.CharField(required=True)
def clean_user(self):
post_user = self.cleaned_data['user']
post_env = self.cleaned_data['env']
c = User.objects.filter(user__contains=post_user, env__contains=post_env ).count()
if (c == 0):
raise forms.ValidationError(u"User Not Found.")
else:
user_info = User.objects.filter(user__contains=post_user).values('password').distinct().count()
user_env = User.objects.filter(user__contains=post_user).values('env').distinct().count()
if not (user_env == user_info):
raise forms.ValidationError(u'User is using same password')
return(post_user)
def __init__(self, *args, **kwargs):
super(env_form, self).__init__(*args, **kwargs)
class SomeOtherForm(env_form):
some_field = forms.CharField()
def __init__(self,*args,**kwargs):
super(env_form, self).__init__(*args,**kwargs)
You could assign a property on your add_uRG form after you validate the env_form, or you could pass the value to the add_uRG form as a parameter.
#forms.py
class AdduRGForm(forms.Form):
def __init__(self, *args, **kwargs):
super(AdduRGForm, self).__init__(*args, **kwargs)
self.env = None
#my_view.py
def my_view(request):
env_form = env_form(request.POST or None)
if request.POST:
if env_form.is_valid():
add_uRG_form = AdduRGForm(request.POST or None)
add_uRG_form.env = env_form.cleaned_data.get('env')
if add_uRG_form.is_valid():
#do something else
return render_to_response('template.html',
{'env_form' : env_form, 'add_uRG_form' : add_uRG_form})
I'm not exactly sure of your workflow, so if these forms don't exist in the same view, like if you're processing the env_form first, and then going to another view and needing the value someone previously selected, you could pass in the request to env_form, and set the selection in session, which you could pick up again in the second form using the method I outlined.

Categories

Resources