I have recently installed autocomplete-light in my app.
Autocomplete filters through the field called 'name' in a table called institution. However, what is post through the view is the 'id' of the same object, not the name.
Does anyone know why that is?
My view is:
class UserAccountsUpdate(UpdateView):
context_object_name = 'variable_used_in `add_user_accounts.html`'
form_class = AddUserAccountsForm
template_name = 'add_user_accounts.html'
success_url = 'add_user_accounts.html'
def add_user_institution_details(request):
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = AddUserAccountsForm(request.POST)
# check whether it's valid:
if form.is_valid():
institution_selected = Institution.objects.get(id=name)
form.save()
return render(request)
#get object
def get_object(self, queryset=None):
return self.request.user
The form is:
class AddUserAccountsForm(forms.ModelForm):
name = forms.ModelChoiceField(required=True, queryset=Institution.objects.all(), widget=autocomplete_light.ChoiceWidget('InstitutionAutocomplete'), label="")
class Meta:
model = Institution
fields = ('name',)
autocomplete-light's ChoiceWidget uses the Model's PrimaryKey for post requests by default, which in your case is id.
Since you did not post your models.py I can only assume that name is a CharField in the Institution model and you are just using autocomplete here to simplify the adding of a name.
To realize this use TextWidget and forms.CharField:
class AddUserAccountsForm(forms.ModelForm):
name = forms.CharField(
required=True,
widget=autocomplete_light.TextWidget('InstitutionAutocomplete'),
label="",
)
class Meta:
model = Institution
fields = ('name',)
Related
I am trying to create a form where one field is a ModelChoicefield. Im trying to populate that field with objects from a different model. I have ran into a problem as i need to get the current logged user within the form to filter the queryset. Here are the 2 models
class UserExercises(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=50)
Muscle = models.ForeignKey(Muscle, on_delete=models.CASCADE)
class Exercise(models.Model):
exercise = models.ForeignKey(UserExercises, on_delete=models.CASCADE)
weight = models.DecimalField(max_digits=6, decimal_places=3)
reps = models.PositiveIntegerField(validators=[MaxValueValidator(100)])
difficulty = models.CharField(max_length=30)
date = models.DateTimeField(default=timezone.now)
user = models.ForeignKey(User, on_delete=models.CASCADE)
And here is my form
class AddExerciseForm(forms.Form):
exercise = forms.ModelChoiceField(queryset=UserExercises.objects.filter(user=1))
class Meta:
model = Exercise
fields = ['exercise', 'weight', 'reps', 'difficulty']
As you can see i am currently hard coding a filter in the ModelChoiceField, but want to replace that with the current users Id. Is there anyway of Going about this. Im new to django so any help would be Appreciated.
My View
#login_required
def add_exercise_view(request):
if request.method == 'POST':
user_id = request.user.id
form = AddExerciseForm(user_id=user_id)
if form.is_valid():
form.save()
return redirect('myfit-home')
else:
form = AddExerciseForm()
return render(request, 'users/register.html', {'form': form})
Firstly, AddExerciseForm should extend forms.ModelForm.
To initialize form data based on some paramater, you can override __init_ method of ModelForm to update form fields (that field is exercise in this case) based on some argument/parameter (which is user_id in this case).
class AddExerciseForm(forms.ModelForm):
class Meta:
model = Exercise
fields = ['exercise', 'weight', 'reps', 'difficulty']
def __init__(self, *args, **kwargs):
user_id = kwargs.pop('user_id', None)
super(AddExerciseForm, self).__init__(*args, **kwargs)
if user_id is not None:
# update queryset for exercise field
self.fields['exercise'].queryset = UserExercises.objects.filter(user=user_id)
else:
# UserExercises.objects.none() will return an empty queryset
self.fields['exercise'].queryset = UserExercises.objects.none()
And pass the user_id while initializing the form in view:
if request.user.is_authenticated():
# get user id
user_id = request.user
form = AddExerciseForm(user_id=user_id)
override __init__ method of the Form, and pass the user as argument
def __init__(self,user,*args, **kwargs):
self.user = user
super().__init__(*args, **kwargs)
self.fields['exercise'].queryset=
UserExercises.objects.filter(user=self.user))
self.fields['exercise'].widget = forms.CheckboxSelectMultiple
class Meta:
model = Exercise
fields = ['exercise', 'weight', 'reps', 'difficulty']
I'm trying to display a form (ModelForm) with a select field filtered by currently logged in user. The select field in this case contains a list of categories. I want to display only the categories which "belong" to the currently logged in user. The category field is a foreign key to the IngredienceCategory model.
Here is what I've come up with so far but it's giving me an error (unexpected keyword queryset). Any ideas what I'm doing wrong?
# models.py
class IngredienceCategory(models.Model):
name = models.CharField(max_length=30)
user = models.ForeignKey(User, null=True, blank=True)
class Meta:
verbose_name_plural = "Ingredience Categories"
def __unicode__(self):
return self.name
class Ingredience(models.Model):
name = models.CharField(max_length=30)
user = models.ForeignKey(User, null=True, blank=True)
category = models.ForeignKey(IngredienceCategory, null=True, blank=True)
class Meta:
verbose_name_plural = "Ingredients"
def __unicode__(self):
return self.name
class IngredienceForm(ModelForm):
class Meta:
model = Ingredience
fields = ('name', 'category')
# views.py
def home(request):
if request.user.is_authenticated():
username = request.user.username
email = request.user.email
foods = Food.objects.filter(user=request.user).order_by('name')
ingredients = Ingredience.objects.filter(user=request.user).order_by('name')
ingrcat = IngredienceCategory.objects.filter(user=request.user)
if request.method == 'POST':
form = IngredienceForm(request.POST)
if form.is_valid():
# Create an instance of Ingredience without saving to the database
ingredience = form.save(commit=False)
ingredience.user = request.user
ingredience.save()
else:
# How to display form with 'category' select list filtered by current user?
form = IngredienceForm(queryset=IngredienceCategory.objects.filter(user=request.user))
context = {}
for i in ingredients:
context[i.category.name.lower()] = context.get(i.category.name.lower(), []) + [i]
context2 = {'username': username, 'email': email, 'foods': foods, 'ingrcat': ingrcat, 'form': form,}
context = dict(context.items() + context2.items())
else:
context = {}
return render_to_response('home.html', context, context_instance=RequestContext(request))
That's happening because ModelForm does not take a queryset keyword.
You can probably achieve this by setting the queryset on the view:
form = IngredienceForm()
form.fields["category"].queryset =
IngredienceCategory.objects.filter(user=request.user)
See related question here.
Here i have another suggestion to solve the problem. You can pass request object in your form object inside view.
In view.py just pass the request object.
form = IngredienceForm(request)
In your forms.py __init__ function also add request object
from models import IngredienceCategory as IC
class IngredienceForm(ModelForm):
class Meta:
model = Ingredience
fields = ('name', 'category')
def __init__(self, request, *args, **kwargs):
super(IngredienceForm, self).__init__(*args, **kwargs)
self.fields['name'].queryset = IC.objects.filter(user=request.user)
This filter always will be applied whenever you initialize your form .
my model:
class Event(models.Model):
title = models.CharField(max_length=255)
start = models.DateTimeField()
end = models.DateTimeField()
theme = models.ForeignKey(Theme)
class Theme(models.Model):
name = models.CharField(max_length=100)
color = models.CharField(max_length=50)
text_color = models.CharField(max_length=50)
my form:
class EventForm(ModelForm):
class Meta:
model = Event
fields = ['title', 'start', 'end']
theme = forms.ModelChoiceField(
queryset=Theme.objects.filter(public=True),
empty_label='None'
)
my view:
#login_required
def index(request):
if request.method == 'POST':
form = EventForm(request.POST)
if form.is_valid():
form.save()
Now If I fill in the values in the form star, end, title and select a theme from a list that django creates for me I get an error when I try to run the form.save() method.
IntegrityError: null value in column "theme_id" violates not-null constraint
But when I look into form.cleaned_data I can see that in theme is an instance of my Theme model available.
you cannot save Event without Theme object, so you need something like
form = EventForm(request.POST)
if form.is_valid():
# get your Theme object 'your_theme_object'
event = form.save(commit=False)
event.theme = your_theme_object
event.save()
I should have commented but I don't have enough point.
I think better way to achieve this thing is:
class EventForm(ModelForm):
class Meta:
model = Event
fields = ['title', 'start', 'end', 'theme']
As 'theme' is foreign key to Event Model, it'll appear as drop down on your template.
As here you want to filter theme objects, you can achieve it by overriding init :
class EventForm(ModelForm):
def __init__(self, *args, **kwargs):
super(EventForm, self).__init__(*args, **kwargs)
self.fields['theme'].queryset = self.fields['theme'].queryset.filter(public=True)
class Meta:
model = Event
fields = ['title', 'start', 'end', 'theme']
I'm having trouble saving data for an intermediate field. I have forms (unlisted here) to create Stocks and Portfolios. Now I am trying to build a Membership form to link the two. I followed the django documentation and the code works perfectly in the the API. Then in the views, I can the membership to save fine (I pulled it up in the API afterwards to check), but it doesn't make the make the connection between the Stock and Portfolio. After the membership form, there is a membership object saved in my database but it is not connecting the portfolio to the stock.
Thanks in advance.
Here are my models:
class Stock(models.Model):
name = models.CharField(max_length=160)
ticker = models.SlugField(max_length=20)
created = models.DateTimeField(auto_now_add=True, blank=True)
class Portfolio(models.Model):
name = models.CharField(max_length=160)
stocks = models.ManyToManyField(Stock, through='Membership')
class Membership(models.Model):
stock = models.ForeignKey(Stock)
portfolio = models.ForeignKey(Portfolio)
shares = models.IntegerField(default=0)
class StockForm(forms.ModelForm):
class Meta:
model = Stock
exclude = []
class PortfolioForm(forms.ModelForm):
class Meta:
model = Portfolio
exclude = []
class MembershipForm(forms.ModelForm):
class Meta:
model = Membership
exclude = []
And here are my views.py:
def membership_form(request):
if request.method == 'POST':
form = MembershipForm(request.POST, request.FILES)
if form.is_valid():
new_obj = form.save(commit=False)
new_obj.save()
membership = Membership.objects.create( portfolio=new_obj.portfolio ,stock=new_obj.stock)
membership.save()
return HttpResponseRedirect(reverse('portfolios', args=[]))
else:
form = MembershipForm(None)
return render(request, 'portfolio/form.html', {'form': form})
I based the views off Django m2m form save " through " table .
Write a custom form and save the relationship inside it.
I have taken the example as classes of of email address associated with an email that i wanted to send
class SendForm (forms.ModelForm) :
To = forms.ModelMultipleChoiceField(
queryset=EmailId.objects.filter(),required=False,widget=FilteredSelectMultiple(('To'), False))
def __init__(self, *args, **kwargs):
initial = kwargs.setdefault('initial', {})
if 'instance' in kwargs:
initial['To']=kwargs['instance'].To.all()
super(SendForm, self).__init__(*args, **kwargs)
def save(self, commit=True):
instance = forms.ModelForm.save(self, commit)
instance.save(send=0)
es = [e for es in self.cleaned_data['To']]
for relation in instance.To.all():
instance.To.remove(relation)
for e in es:
instance.To.add(e)
instance.save(send=1)
return instance
class Meta:
model =SentEmail
I'm trying to display a form (ModelForm) with a select field filtered by currently logged in user. The select field in this case contains a list of categories. I want to display only the categories which "belong" to the currently logged in user. The category field is a foreign key to the IngredienceCategory model.
Here is what I've come up with so far but it's giving me an error (unexpected keyword queryset). Any ideas what I'm doing wrong?
# models.py
class IngredienceCategory(models.Model):
name = models.CharField(max_length=30)
user = models.ForeignKey(User, null=True, blank=True)
class Meta:
verbose_name_plural = "Ingredience Categories"
def __unicode__(self):
return self.name
class Ingredience(models.Model):
name = models.CharField(max_length=30)
user = models.ForeignKey(User, null=True, blank=True)
category = models.ForeignKey(IngredienceCategory, null=True, blank=True)
class Meta:
verbose_name_plural = "Ingredients"
def __unicode__(self):
return self.name
class IngredienceForm(ModelForm):
class Meta:
model = Ingredience
fields = ('name', 'category')
# views.py
def home(request):
if request.user.is_authenticated():
username = request.user.username
email = request.user.email
foods = Food.objects.filter(user=request.user).order_by('name')
ingredients = Ingredience.objects.filter(user=request.user).order_by('name')
ingrcat = IngredienceCategory.objects.filter(user=request.user)
if request.method == 'POST':
form = IngredienceForm(request.POST)
if form.is_valid():
# Create an instance of Ingredience without saving to the database
ingredience = form.save(commit=False)
ingredience.user = request.user
ingredience.save()
else:
# How to display form with 'category' select list filtered by current user?
form = IngredienceForm(queryset=IngredienceCategory.objects.filter(user=request.user))
context = {}
for i in ingredients:
context[i.category.name.lower()] = context.get(i.category.name.lower(), []) + [i]
context2 = {'username': username, 'email': email, 'foods': foods, 'ingrcat': ingrcat, 'form': form,}
context = dict(context.items() + context2.items())
else:
context = {}
return render_to_response('home.html', context, context_instance=RequestContext(request))
That's happening because ModelForm does not take a queryset keyword.
You can probably achieve this by setting the queryset on the view:
form = IngredienceForm()
form.fields["category"].queryset =
IngredienceCategory.objects.filter(user=request.user)
See related question here.
Here i have another suggestion to solve the problem. You can pass request object in your form object inside view.
In view.py just pass the request object.
form = IngredienceForm(request)
In your forms.py __init__ function also add request object
from models import IngredienceCategory as IC
class IngredienceForm(ModelForm):
class Meta:
model = Ingredience
fields = ('name', 'category')
def __init__(self, request, *args, **kwargs):
super(IngredienceForm, self).__init__(*args, **kwargs)
self.fields['name'].queryset = IC.objects.filter(user=request.user)
This filter always will be applied whenever you initialize your form .