I'm trying to create a way to update an item of the database that has the fields CharField and ForeignKey. I want to pass the original values so that they don't have to be manually entered for each field every time, but this gives me a "Select a valid choice. That choice is not one of the available choices." warning for the group field. How do I remove this warning message?
Setting the error message (in ModelForm) to something else manually still displays an empty (unordered) list item. Setting the form in UpdateUserView to form = UserForm() gets rid of the errors, but doesn't pass default values to the form.
models.py
class User(models.Model):
username = models.CharField(max_length=50)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
class Group(models.Model):
name = models.CharField(max_length=20)
description = models.CharField(max_length=200)
forms.py
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ['username', 'group']
views.py
class UpdateUserView(TemplateView):
template_name = 'update_user.html'
def get(self, request):
user_id = int(request.GET.get('user_id'))
user = User.objects.get(id=user_id)
default_name = getattr(user, 'username')
default_group = getattr(user, 'group')
form = UserForm({'username': default_name, 'group': default_group})
return render(request, self.template_name, {'form': form, 'user': user})
End Result
You have to use initial argument like this:
class UpdateUserView(TemplateView):
template_name = 'update_user.html'
def get(self, request):
user_id = int(request.GET.get('user_id'))
user = User.objects.get(id=user_id)
form = UserForm(initial={'username': user.username, 'group': user.group.id})
return render(request, self.template_name, {'form': form, 'user': user})
Look I'm using group: user.group.id here, since the model Field you are referencing there in your form is a ForeignKey.
I hope this help.
Related
I am a beginner in django and trying to create a web application for my task.
I am trying to assign a user to every to employee.
The idea is that user(in my class Employee) brings a list of user options that have not yet been assigned to the new employee to be registered.
My model:
class Employee():
name = models.CharField(max_length=100)
job = models.CharField(max_length=30)
user = models.OneToOneField(User,on_delete=models.CASCADE)
def __str__(self):
return'{}'.format(self.name,self.job,self.user)
My form:
class EmployeeForm(forms.ModelForm):
user= forms.ModelChoiceField(queryset=User.objects.filter(id=Employee.user))
class Meta:
model = Employee
fields = [
'name',
'job',
'user'
]
My view:
def register_employee(request):
if request.method == 'POST':
form = EmployeeForm(request.POST)
if form.is_valid():
form.save()
return redirect('/')
return redirect('list_employee')
else:
form = EmployeeForm()
return render(request, 'employee/employee_form.html',{'form': form})
I guess your code to be modified as,
class EmployeeForm(forms.ModelForm):
user= forms.ModelChoiceField(queryset=User.objects.filter(employee=None))
Please try the above.
So this is the scenario. I allow my user to first input their vehicle brand with one form and then use another form to list down the models available for that vehicle brand. The information on the vehicles and the brands is stored in my database.
Refer to this image to get a better idea:
And this is my views.py:
def driver_dashboard_trip_brand (request, brand):
if request.method == "POST":
form = AddVehicleForm(request.POST)
else:
form = AddVehicleForm()
brands = VehicleBrand.objects.all()
context = {
"form":form,
"brands":brands,
"chosen_brand":brand
}
return render (request, "app/driver_dashboard.html", context)
And my forms.py:
class AddVehicleForm(forms.ModelForm):
model = forms.ModelChoiceField(queryset=VehicleModel.objects.all())
vehicle_colour = forms.ChoiceField(choices=COLOURS)
vehicle_number = forms.CharField(max_length=8, widget=forms.TextInput(attrs={'placeholder': 'eg: CAB-1234'}))
class Meta:
model = Vehicle
fields = ['model', 'vehicle_colour', 'vehicle_number']
So in order to set a query in the forms.py, I would first need to send the data from views.py to forms.py, and then I also need to do a query.
So my question is how can I query for all the car models from the VehicleModel database and create choices attribute for the form, once the user chooses the car brand.
My models.py...
class VehicleModel (models.Model):
brand = models.ForeignKey(VehicleBrand, on_delete=models.CASCADE)
model = models.CharField(max_length=30)
def __str__ (self):
return f"{self.brand} - {self.model}"
Its honestly not so hard, i kinda figured it out...
So this is my forms.py...
class AddVehicleForm(forms.ModelForm):
def __init__(self, brand=None, *args, **kwargs):
super(AddVehicleForm, self).__init__(*args, **kwargs)
self.fields['model'].queryset = VehicleModel.objects.filter(brand=brand)
model = forms.ModelChoiceField(queryset=VehicleModel.objects.all())
vehicle_colour = forms.ChoiceField(choices=COLOURS)
vehicle_number = forms.CharField(max_length=8, widget=forms.TextInput(attrs={'placeholder': 'eg: CAB-1234'}))
class Meta:
model = Vehicle
fields = ['model', 'vehicle_colour', 'vehicle_number']
class AddVehicleFormPost(forms.ModelForm):
model = forms.ModelChoiceField(queryset=VehicleModel.objects.all())
vehicle_colour = forms.ChoiceField(choices=COLOURS)
vehicle_number = forms.CharField(max_length=8, widget=forms.TextInput(attrs={'placeholder': 'eg: CAB-1234'}))
class Meta:
model = Vehicle
fields = ['model', 'vehicle_colour', 'vehicle_number']
Where the form AddVehicleForm allowed me to send the parameter as shown by typing form = AddVehicleForm(VehicleBrand.objects.filter(brand=brand).first()) in my views.py, but then when I wanted to save my form I needed to create another form in the forms.py without taking any query which is shown in AddVehicleFormPost.
Then i casually did,
if request.method == "POST":
form = AddVehicleFormPost(request.POST)
if form.is_valid():
In my views.py...
Here you have a nice tutorial on how to create dependent fields, you need to understand what's going on on the Server, and what's going on on the Client
I'm was creating ModelForm I try to make change the parent class while saving child class fields to the database, in the views.py I made but it didn't save to the database.
here is my model.py
class Table(models.Model):
restaurant = models.ForeignKey(Restaurant, on_delete=models.CASCADE)
book = models.BooleanField(default=False)
class People(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True)
taple = models.OneToOneField(Table, on_delete=models.CASCADE, null=True, blank=True)
#receiver(post_save, sender=User)
def update_people_profile(sender, instance, created, **kwargs):
try:
instance.people.save()
except ObjectDoesNotExist:
People.objects.create(user=instance)
Class People is the child class and Table is the parent class so I'm using People class for making forms. here is my forms.py
class Booking(forms.ModelForm):
class Meta:
model = People
fields = [
'taple',
]
So I want to make True book field in Table class and save it to the database when saving Booking form. here is my views.py
def booking(request):
if request.method == 'POST':
try:
people_instance = People.objects.get(user=request.user)
except Table.DoesNotExist:
people_instance = People(user=request.user)
form = Booking(request.POST, instance=people_instance)
if form.is_valid():
user = form.save(commit=False)
user.taple.booking = True
user.refresh_from_db()
user.user = request.user
user.taple = form.cleaned_data.get('taple')
user.save()
print(user.taple.booking, user.taple.id)
return redirect('booked')
else:
form = Booking()
return render(request, 'main/booking.html', {'form': form})
Any Idea?
What I understand from the snippets is that you want to be able to record if a table is booked (book Boolean Field in your Table model and if so by whom, which is the object of your People model.
If my understanding is correct, then I don't think you really need a join table (People model). Instead, I would change your model as follow:
class Table(models.Model):
restaurant = models.ForeignKey(Restaurant, on_delete=models.CASCADE)
booked_by = models.OneToOneField(User, null=True, on_delete=models.SET_NULL, related_name='table_booked')
#property
def is_booked(self):
# This returns True if booked_by is set, False otherwise
return self.booked_by_id is not None
This way you don't need the People model. The property decorator will allow you to use is_booked as a calculated field.
Also, note the related name which will be used in the form:
class BookingForm(forms.ModelForm):
table_booked = forms.ModelChoiceField(queryset=Table.objects.filter(booked_by__isnull=True))
class Meta:
model = User
fields = ['table_booked',]
In the form, you will see that we define a custom queryset for table_booked. THe aim is to filter for free tables only.
Then you can hopefully simplify as well your view as follow:
Update:
As table_booked is a reverse foreign key, we actually need to save the table object which contains the relation. Here is the modified view:
#login_required
def booking(request):
form = BookingForm(request.POST or None, instance=request.user)
if form.is_valid():
user = form.save(commit=False)
tbl = form.cleaned_data['table_booked']
tbl.booked_by = request.user
tbl.save()
user.save()
print(request.user.table_booked.id, request.user.table_booked.is_booked)
return redirect('/')
return render(request, 'booking/booking.html', {'form': form})
Note: I haven't tested the code so there could be some typos but that should help you getting started.
I have a model called Listing which is basically a job listing posted by my users. One of the fields is a Foreign Key called Address (since a user can have multiple addresses). Here is my models.py:
class JobListing(models.Model):
title = models.CharField(max_length=250)
description = models.TextField()
customer = models.ForeignKey('CustomerAuth.CustomerProfile')
address = models.ForeignKey('CustomerAuth.Address')
Here is my forms.py:
class JobListingForm(forms.ModelForm):
class Meta:
model = JobListing
fields = ['title', 'description', 'address', 'customer']
and finally the relevant parts of my views.py:
def create_listing(request):
form = JobListingForm(request.POST or None)
if form.is_valid():
listing = form.save(commit=False)
listing.save()
current_user = CustomerProfile.objects.get(user=request.user)
listing.customer = current_user
listing.save()
return HttpResponseRedirect('/listings/id/%s' % listing.id)
context_dict = {'form': form}
return render(request, 'listing/create-listing.html', context_dict)
As it currently stands when a user selects an address from the dropdown it shows everyones address. Is there anyway I can filter it so that only the addresses entered by that user is shown.
forms.py
class JobListingForm(forms.ModelForm):
class Meta:
model = JobListing
fields = ['title', 'description', 'address', 'customer']
def __init__(self, user, *args, **kwargs):
super(JobListingForm, self).__init__(*args, **kwargs)
self.fields['address'].queryset = Address.objects.filter(user=user)
in your views file
def create_listing(request):
user = request.user
form = JobListingForm(user, request.POST or None) #pass request.user
try something like this
model1.objects.get(pk=1).model2_set.all()
After a ModelForm has been submitted, how can I add a foreign key relation so that it validates?
models.py
class Comment(models.Model):
id = models.AutoField(primary_key=True)
activity = models.ForeignKey(Activity)
submitter = models.ForeignKey(User)
creation_date = models.DateTimeField(auto_now_add=True)
content = models.TextField()
forms.py
class CommentForm(forms.ModelForm):
content = forms.CharField(widget=forms.Textarea)
class Meta:
model = Comment
views.py
def index(request, id=None):
activity_instance = Activity.objects.get(pk=1)
submitter_instance = User.objects.get(id=1)
newComment = CommentForm(request.POST)
newComment.activity = activity_instance
newComment.submitter = submitter_instance
if newComment.is_valid(): # <-- false, which is the problem
I think you are mixing up form instance with model instance. your newComment is a form, assigning other objects as a form attribute will not make the form saving the foreign key(not sure where did you find this usage), because all form data is saved in form.data, which is a dict like data structure.
I'm not sure what does your form look like because you didn't exclude the foreign keys so they should be rendered as dropdowns and you could select them. If you don't want the user to select the foreign key but choose to assign the values as you currently do, you should exclude them in the form so form.is_valid() would pass:
class CommentForm(forms.ModelForm):
content = forms.CharField(widget=forms.Textarea)
class Meta:
model = Comment
exclude = ('activity', 'submitter')
views.py
def index(request, id=None):
activity_instance = Activity.objects.get(pk=1)
submitter_instance = User.objects.get(id=1)
comment_form = CommentForm(request.POST)
if comment_form.is_valid():
new_comment = comment_form.save(commit=False)
new_comment.activity = activity_instance
new_comment.submitter = submitter_instance
new_comment.save()
Django doc about save() method.