Convert case sensitives - django

i want to convert any new enter user name to lowercase and check if the user is exist or now and use iexact to login in capital or small
where should determine the login uses small or capital
forms.py
class AddCompanyForm(forms.ModelForm):
"""
Add company model form
"""
name = forms.CharField(required=True)
password = forms.CharField(widget=forms.PasswordInput())
logo = forms.ImageField(required=False)
phone_number = forms.CharField(widget=forms.NumberInput())
label = forms.CharField(max_length=20)
country = forms.ModelChoiceField(queryset=Country.objects.all())
city = forms.ModelChoiceField(queryset=City.objects.all())
area = forms.ModelChoiceField(queryset=Area.objects.all())
latitude = forms.CharField(max_length=50, required=False)
longitude = forms.CharField(max_length=50, required=False)
water_source = forms.ModelChoiceField(queryset=WaterSource.objects.all())
class Meta:
model = User
fields = ['name', 'username', 'email', 'password']
def __init__(self, *args, **kwargs):
super(AddCompanyForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_tag = False
self.layout = Layout(Row(Column('name', css_class='form-group col-md-6 mb-0'),
Column('username', css_class='form-group col-md-6 mb-0'), css_class='form-row'),
Row(Column('email', css_class='form-group col-md-6 mb-0'),
Column('password', css_class='form-group col-md-6 mb-0'), css_class='form-row'),
Row(Column('phone_number', css_class='form-group col-md-6 mb-0'),
Column('logo', css_class='form-group col-md-6 mb-0'), css_class='form-row'),
Row(Column('label', css_class='form-group col'), css_class='form-row'),
Row(Column('country', css_class='form-group col'),
Column('city', css_class='form-group col'), Column('area', css_class='form-group col'),
css_class='form-row'), Row(Column('latitude', css_class='form-group col'),
Column('longitude', css_class='form-group col'),
css_class='form-row'),
Row(Column('water_source', css_class='form-group col'), css_class='form-row'))
self.helper.layout = self.layout
views.py
class Companies(LoginRequiredMixin, UserPassesTestMixin, FormView, ListView):
"""
Company add edit delete view search paginator
"""
model = Company
template_name = 'company/index.html'
form_class = AddCompanyForm
success_url = reverse_lazy('companies:index')
object_list = Company.objects.all()
def form_valid(self, form):
user, created = User.objects.get_or_create(username=form.cleaned_data['username'],
email=form.cleaned_data['email'])
user.set_password(form.cleaned_data['password'])
user.save()
if created:
address = Address(label=form.cleaned_data['label'], city=form.cleaned_data['city'],
area=form.cleaned_data['area'], long=form.cleaned_data['longitude'],
lat=form.cleaned_data['latitude'], country=form.cleaned_data['country'])
address.save()
company = Company(owner=user, name=form.cleaned_data['name'],
phone_number=form.cleaned_data['phone_number'], logo=form.cleaned_data['logo'],
address=address, water_source=form.cleaned_data['water_source'])
company.save()
return super().form_valid(form)
am try to put this function in form to convert lowercase
def clean_username(self):
return self.cleaned_data['username'].lower()
how i can use iexact when login and where

you can match username in lowercase like this
from django.db.models.functions import Lower
input_name = form.cleaned_data['username'].lower()
User.objects.annotate(username_lower=Lower("username")).filter(username_lower=input_name)

Related

Django User does not update when saved?

I cannot get the default User model or my created Agent model to update. Below is my admin.py, forms.py, models.py, urls.py, views.py, and my edit_profile.html. I know it must be silly, but I've got three good days working on this.
The HTML page tries to edit both the EditProfileForm and the MoreInfoForm. The EditProfileForm uses the built-in User model, while the MoreInfoForm is my model that extends the built-in User model. As a note, the MoreInfoForm also contains an Image that I want to be able to update.
When I submit the form, I get a POST request, but when I view the profile, it doesn't contain any changes.
admin.py:
class AgentInline(admin.StackedInline):
model = Agent
can_delete = False
verbose_name_plural = 'agent'
class UserAdmin(BaseUserAdmin):
inlines = (AgentInline,)
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
forms.py:
class RegisterUserForm(UserCreationForm):
email = forms.EmailField(widget=forms.EmailInput(attrs={'class': 'form-control'}))
first_name = forms.CharField(max_length=50,
widget=forms.TextInput(attrs={'class': 'form-control'}))
last_name = forms.CharField(max_length=50,
widget=forms.TextInput(attrs={'class': 'form-control'}))
class Meta:
model = User
fields = ('username',
'first_name',
'last_name',
'email',
'password1',
'password2',)
def __init__(self, *args, **kwargs):
super(RegisterUserForm, self).__init__(*args, **kwargs)
self.fields['username'].widget.attrs['class'] = 'form-control'
self.fields['password1'].widget.attrs['class'] = 'form-control'
self.fields['password2'].widget.attrs['class'] = 'form-control'
class MoreInfoForm(forms.ModelForm):
agent_phone_num = forms.CharField(max_length=10,
required=True,
help_text='Enter a 10 digit # without spaces or dashes',
widget=forms.TextInput(
attrs={'class': 'form-control'}))
agent_mls = forms.CharField(max_length=6,
required=True,
help_text='Enter your 6 digit MLS #',
widget=forms.TextInput(
attrs={'class': 'form-control'}))
headshot = forms.ImageField(required=False,
error_messages={'invalid': 'Image files only'},
widget=forms.FileInput(attrs={'class': 'form-control'}))
class Meta:
model = Agent
fields = ('agent_phone_num',
'agent_mls',
'headshot',)
class EditProfileForm(UserChangeForm):
email = forms.EmailField(widget=forms.EmailInput(attrs={'class': 'form-control'}))
first_name = forms.CharField(max_length=50,
widget=forms.TextInput(attrs={'class': 'form-control'}))
last_name = forms.CharField(max_length=50,
widget=forms.TextInput(attrs={'class': 'form-control'}))
class Meta:
model = User
fields = ('first_name',
'last_name',
'email',
'password',)
def __init__(self, *args, **kwargs):
super(EditProfileForm, self).__init__(*args, **kwargs)
del self.fields['password']
models.py:
class Agent(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
agent_phone_num = models.CharField(blank=False, max_length=10, default=None)
agent_mls = models.CharField(blank=False, max_length=6, default=None)
headshot = models.ImageField(upload_to='agents', blank=True)
def formatted_phone(self):
phone_string = f'{self.agent_phone_num}'
return ('1-' +
phone_string[:3] + '-' +
phone_string[3:6] + '-' +
phone_string[6:])
def __str__(self):
return self.user.username + self.formatted_phone()
urls.py:
urlpatterns = [
path('login', views.login_user, name='login', ),
path('logout', views.logout_user, name='logout', ),
path('register', views.register_user, name='register', ),
path('profile', views.view_profile, name='profile', ),
path('profile/edit/', views.edit_profile, name='edit_profile', ),
# TODO user password reset page
path('reset_password/',
auth_views.PasswordResetView.as_view(),
name='reset_password'),
path('reset_password_sent',
auth_views.PasswordResetDoneView.as_view(),
name='password_reset_done'),
path('reset/<uidb64>/<token>/',
auth_views.PasswordResetConfirmView.as_view(),
name='password_reset_confirm'),
path('reset_password_complete/',
auth_views.PasswordResetCompleteView.as_view(),
name='password_reset_complete'),
]
views.py:
def login_user(request):
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
return redirect('index')
else:
messages.success(request, 'There Was An Error Logging In, Try Again...')
return redirect('login')
else:
return render(request, 'authenticate/login.html', {
})
def logout_user(request):
logout(request)
messages.success(request, 'You Were Logged Out!')
return redirect('index')
def register_user(request):
if request.method == 'POST':
form = RegisterUserForm(request.POST)
more_form = MoreInfoForm(request.POST, request.FILES)
if form.is_valid() and more_form.is_valid():
user = form.save()
more = more_form.save(commit=False)
more.user = user
more.save()
username = form.cleaned_data['username']
password = form.cleaned_data['password1']
user = authenticate(username=username, password=password)
login(request, user)
messages.success(request, 'Registration Successful!')
return redirect('index')
else:
form = RegisterUserForm()
more_form = MoreInfoForm(request.POST)
return render(request, 'authenticate/register_user.html', {
'form': form,
'more_form': more_form,
})
def view_profile(request):
return render(request, 'authenticate/profile.html', {
'user': request.user,
})
def edit_profile(request):
user_profile = get_object_or_404(Agent, user=request.user)
if request.method == 'POST':
form = EditProfileForm(request.POST, instance=request.user)
more_form = MoreInfoForm(request.POST, request.FILES, instance=user_profile)
if form.is_valid() and more_form.is_valid():
form.save()
more_form.save()
messages.success(request, 'Your profile has been updated.')
return redirect('edit_profile')
else:
form = EditProfileForm(instance=request.user)
more_form = MoreInfoForm(instance=user_profile)
return render(request, 'authenticate/edit_profile.html', {
'form': form,
'more_form': more_form,
'user_profile': user_profile,
})
edit_profile.html:
<div class="container"
style="min-height: 100vh">
{% if user.is_authenticated %}
<h1 class="h1 text-center mt-3 text-capitalize">{{ user.first_name }}'s Profile</h1>
<div class="">
<img src="{{ user.agent.headshot.url }}"
alt="Profile Picture"
class=""
height="300"
width="">
</div>
<form action="{% url 'edit_profile' %}"
method="POST"
enctype="multipart/form-data">
{% csrf_token %}
{{ form.first_name }}
{{ form.last_name }}
{{ form.email }}
{{ more_form.agent_phone_num }}
<div class="form-group col-md-6">
<label for="">Profile Picture</label>
{{ more_form.headshot }}
</div>
<input type="submit"
class="btn btn-secondary"
value="Save">
{#<button class="btn btn-secondary"#}
{# type="submit">Save#}
{#</button>#}
</form>
{% else %}
<h1 class="h1 text-center mt-3">You must be logged in to view this page</h1>
<div class="text-center m-3">
<a href="{% url 'login' %}"
class="text-decoration-none">
<button type="button"
class="btn btn-light pl-5 pr-5">Login
</button>
</a>
</div>
{% endif %}
</div>

Datalist with free text error "Select a valid choice. That choice is not one of the available choices."

I am building a Create a Recipe form using crispy forms and I am trying to use a datalist input field for users to enter their own ingredients, like 'Big Tomato' or select from GlobalIngredients already in the database like 'tomato' or 'chicken'. However, regardless of whether I enter a new ingredient or select a pre-existing one, I am getting the following error: "Select a valid choice. That choice is not one of the available choices.". How do I fix this error?
Visual:
models.py
class Recipe(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
websiteURL = models.CharField(max_length=200, blank=True, null=True)
image = models.ImageField(upload_to='image/', blank=True, null=True)
name = models.CharField(max_length=220) # grilled chicken pasta
description = models.TextField(blank=True, null=True)
notes = models.TextField(blank=True, null=True)
serves = models.CharField(max_length=30, blank=True, null=True)
prepTime = models.CharField(max_length=50, blank=True, null=True)
cookTime = models.CharField(max_length=50, blank=True, null=True)
class Ingredient(models.Model):
name = models.CharField(max_length=220)
def __str__(self):
return self.name
class GlobalIngredient(Ingredient):
pass # pre-populated ingredients e.g. salt, sugar, flour, tomato
class UserCreatedIngredient(Ingredient): # ingredients user adds, e.g. Big Tomatoes
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
class RecipeIngredient(models.Model):
recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE)
ingredient = models.ForeignKey(Ingredient, null=True, on_delete=models.SET_NULL)
description = models.TextField(blank=True, null=True)
quantity = models.CharField(max_length=50, blank=True, null=True) # 400
unit = models.CharField(max_length=50, blank=True, null=True) # pounds, lbs, oz ,grams, etc
forms.py
class RecipeIngredientForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(RecipeIngredientForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
#self.helper.form_id = 'id-entryform'
#self.helper.form_class = 'form-inline'
self.helper.layout = Layout(
Div(
Div(Field("ingredient", placeholder="Chickpeas - only write the ingredient here"), css_class='col-6 col-lg-4'),
Div(Field("quantity", placeholder="2 x 400"), css_class='col-6 col-md-4'),
Div(Field("unit", placeholder="grams"), css_class='col-5 col-md-4'),
Div(Field("description", placeholder="No added salt tins - All other information, chopped, diced, whisked!", rows='3'), css_class='col-12'),
css_class="row",
),
)
class Meta:
model = RecipeIngredient
fields = ['ingredient', 'quantity', 'unit', 'description']
labels = {
'ingredient': "Ingredient",
"quantity:": "Ingredient Quantity",
"unit": "Unit",
"description:": "Ingredient Description"}
widgets={'ingredient': forms.TextInput(attrs={
'class': 'dropdown',
'list' : 'master_ingredients',
'placeholder': "Chickpeas - only write the ingredient here"
})}
views.py
#login_required
def recipe_create_view(request):
ingredient_list = Ingredient.objects.all()
form = RecipeForm(request.POST or None)
# Formset = modelformset_factory(Model, form=ModelForm, extra=0)
RecipeIngredientFormset = formset_factory(RecipeIngredientForm)
formset = RecipeIngredientFormset(request.POST or None)
RecipeInstructionsFormset = formset_factory(RecipeInstructionForm, extra=0)
instructionFormset = RecipeInstructionsFormset(request.POST or None, initial=[{'stepName': "Step 1"}], prefix="instruction")
context = {
"form": form,
"formset": formset,
"instructionFormset": instructionFormset,
"ingredient_list": ingredient_list
}
if request.method == "POST":
print(request.POST)
if form.is_valid() and formset.is_valid() and instructionFormset.is_valid():
parent = form.save(commit=False)
parent.user = request.user
parent.save()
# formset.save()
#recipe ingredients
for form in formset:
child = form.save(commit=False)
print(child.ingredient)
globalIngredient = Ingredient.objects.filter(name=child.ingredient.lower()) # not truly global as this will return user ingredients too
if (globalIngredient):
pass
else:
newIngredient = UserCreatedIngredient(user=request.user, name=child.ingredient.lower())
newIngredient.save()
if form.instance.ingredient.strip() == '':
pass
else:
child.recipe = parent
child.save()
# recipe instructions
for instructionForm in instructionFormset:
instructionChild = instructionForm.save(commit=False)
if instructionForm.instance.instructions.strip() == '':
pass
else:
instructionChild.recipe = parent
instructionChild.save()
context['message'] = 'Data saved.'
return redirect(parent.get_absolute_url())
else:
form = RecipeForm(request.POST or None)
formset = RecipeIngredientFormset()
instructionFormset = RecipeInstructionsFormset()
return render(request, "recipes/create.html", context)
create.html
<!--RECIPE INGREDIENTS-->
{% if formset %}
<h3 class="mt-4 mb-3">Ingredients</h3>
{{ formset.management_form|crispy }}
<div id='ingredient-form-list'>
{% for ingredient in formset %}
<div class='ingredient-form'>
{% crispy ingredient %}
</div>
{% endfor %}
<datalist id="master_ingredients">
{% for k in ingredient_list %}
<option value="{{k.name|title}}"></option>
{% endfor %}
</datalist>
</div>
<div id='empty-form' class='hidden'>
<div class="row mt-4">
<div class="col-6">{{ formset.empty_form.ingredient|as_crispy_field }}</div>
<div class="col-6">{{ formset.empty_form.quantity|as_crispy_field }}</div>
<div class="col-6">{{ formset.empty_form.unit|as_crispy_field }}</div>
<div id="ingredientIdForChanging" style="display: none;"><div class="col-12">{{ formset.empty_form.description|as_crispy_field }}</div><button type="button"
class="btn btn-outline-danger my-2" onclick="myFunction('showDescription')"><i class="bi bi-dash-circle"></i> Hide
Description</button></div><button type="button"
class="btn btn-outline-primary col-5 col-md-3 col-lg-3 col-xl-3 m-2" id="ingredientIdForChanging1"
onclick="myFunction('showDescription')"><i class="bi bi-plus-circle"></i> Add a
Description Field</button>
</div>
</div>
<button class="btn btn-success my-2" id='add-more' type='button'>Add more ingredients</button>
{% endif %}
You can create your own TextInput and TypedModelListField field to handle this. I think what you're looking for is something which allows the user to both search and provide a recommended selection of choices but validate the input against a model (Ingredient).
I've created one here:
class TypedModelListField(forms.ModelChoiceField):
def to_python(self, value):
if self.required:
if value == '' or value == None:
raise forms.ValidationError('Cannot be empty')
validate_dict = {self.validate_field: value}
try:
value = type(self.queryset[0]).objects.get(**validate_dict))
except:
raise forms.ValidationError('Select a valid choice. That choice is not one of the available choices.')
value = super().to_python(value)
return value
def __init__(self, *args, **kwargs):
self.validate_field= kwargs.pop('validate_field', None)
super().__init__(*args, **kwargs)
class ListTextWidget(forms.TextInput):
def __init__(self, dataset, name, *args, **kwargs):
super().__init__(*args)
self._name = name
self._list = dataset
self.attrs.update({'list':'list__%s' % self._name,'style': 'width:100px;'})
if 'width' in kwargs:
width = kwargs['width']
self.attrs.update({'style': 'width:{}px;'.format(width)})
if 'identifier' in kwargs:
self.attrs.update({'id':kwargs['identifier']})
def render(self, name, value, attrs=None, renderer=None):
text_html = super().render(name, value, attrs=attrs)
data_list = '<datalist id="list__%s">' % self._name
for item in self._list:
data_list += '<option value="%s">' % item
data_list += '</datalist>'
return (text_html + data_list)
Within the RecipeIngredientForm add the following definition:
ingredient = TypedModelListField(
queryset=Ingredient.objects.all(),
validate_field='name')
And then in RecipeIngredientForm within the __init__ function. Include the following after the super() is called.
self.fields['ingredient'].widget = ListTextWidget(
dataset=Ingredient.objects.all(),
name='ingredient_list')
With ecogels comment I was able to understand what was causing the issue and with a combination of Lewis answer and this answer I managed to get this working with the following code.
fields.py
from django import forms
class ListTextWidget(forms.TextInput):
def __init__(self, data_list, name, *args, **kwargs):
super(ListTextWidget, self).__init__(*args, **kwargs)
self._name = name
self._list = data_list
self.attrs.update({'list':'list__%s' % self._name})
def render(self, name, value, attrs=None, renderer=None):
text_html = super(ListTextWidget, self).render(name, value, attrs=attrs)
data_list = '<datalist id="list__%s">' % self._name
for item in self._list:
data_list += '<option value="%s">' % str(item).title()
data_list += '</datalist>'
return (text_html + data_list)
forms.py
from .fields import ListTextWidget
class RecipeIngredientForm(forms.ModelForm):
ingredientName = forms.CharField(required=True)
def __init__(self, *args, **kwargs):
super(RecipeIngredientForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.layout = Layout(
Div(
Div(Field("ingredientName", placeholder="Chickpeas - only write the ingredient here"), css_class='col-6 col-lg-4'),
Div(Field("quantity", placeholder="2 x 400"), css_class='col-6 col-md-4'),
Div(Field("unit", placeholder="grams"), css_class='col-5 col-md-4'),
Div(Field("description", placeholder="No added salt tins - All other information, chopped, diced, whisked!", rows='3'), css_class='col-12'),
css_class="row",
),
)
self.fields['ingredientName'].widget = ListTextWidget(data_list=Ingredient.objects.all(), name='ingredient-list')
class Meta:
model = RecipeIngredient
fields = ['ingredientName', 'quantity', 'unit', 'description']
labels = {
'ingredientName': "Ingredient",
"quantity:": "Ingredient Quantity",
"unit": "Unit",
"description:": "Ingredient Description"}
create.html:
<!--RECIPE INGREDIENTS-->
{% if formset %}
<h3 class="mt-4 mb-3">Ingredients</h3>
{{ formset.management_form|crispy }}
<div id='ingredient-form-list'>
{% for ingredient in formset %}
<div class='ingredient-form'>
{% crispy ingredient %}
</div>
{% endfor %}
</div>
<div id='empty-form' class='hidden'>
<div class="row mt-4">
<div class="col-6">{{ formset.empty_form.ingredientName|as_crispy_field }}</div>
<div class="col-6">{{ formset.empty_form.quantity|as_crispy_field }}</div>
<div class="col-6">{{ formset.empty_form.unit|as_crispy_field }}</div>
<div id="ingredientIdForChanging" style="display: none;"><div class="col-12">{{ formset.empty_form.description|as_crispy_field }}</div><button type="button"
class="btn btn-outline-danger my-2" onclick="myFunction('showDescription')"><i class="bi bi-dash-circle"></i> Hide
Description</button></div><button type="button"
class="btn btn-outline-primary col-5 col-md-3 col-lg-3 col-xl-3 m-2" id="ingredientIdForChanging1"
onclick="myFunction('showDescription')"><i class="bi bi-plus-circle"></i> Add a
Description Field</button>
</div>
</div>
<button class="btn btn-success my-2" id='add-more' type='button'>Add more ingredients</button>
{% endif %}
views.py changes:
form = RecipeForm(request.POST or None)
# Formset = modelformset_factory(Model, form=ModelForm, extra=0)
RecipeIngredientFormset = formset_factory(RecipeIngredientForm)
formset = RecipeIngredientFormset(request.POST or None)
RecipeInstructionsFormset = formset_factory(RecipeInstructionForm, extra=0)
instructionFormset = RecipeInstructionsFormset(request.POST or None, initial=[{'stepName': "Step 1"}], prefix="instruction")
URLForm = RecipeIngredientURLForm(request.POST or None)
context = {
"form": form,
"formset": formset,
"URLForm": URLForm,
"instructionFormset": instructionFormset
}

Include a Searchbox in a Django Crispy Forms

I am using the Django Crispy forms and a Foreignkey field. I am using a foreignkey to get a list of all contacts. When creating a new form, I`ve got a very long list of contact to choose from. What I would like to do is to search the contact in a searchbox. At the moment, I can not use this feature as there are too many contacts to search. Is there a way to add a search box in the forms html? What would be the django crispy forms field to modify?
forms.py
class InvoiceForm(forms.ModelForm):
class Meta:
model = Invoice
fields = ['name','contact','company','terms','due_date','invoice_date','notes','draft']
def __init__(self, *args, **kwargs):
super(InvoiceForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_tag = True
self.helper.layout = Layout(
Row(
Column('name', css_class='form-group col-md-2 mb-0'),
Column('contact', css_class='form-group col-md-2 mb-0'),
Column('company', css_class='form-group col-md-2 mb-0'),
css_class='form-row'
),
Row(
Column('terms', css_class='form-group col-md-2 mb-0'),
Column('due_date', css_class='form-group col-md-2 mb-0'),
Column('invoice_date', css_class='form-group col-md-2 mb-0'),
css_class='form-row'
),
Fieldset('Add lines',Formset('lines')),
Row(
css_class='form-row'
),
Row(
Column('notes', css_class='form-group col-md-2 mb-0'),
Column('draft', css_class='form-group col-md-2 mb-0'),
css_class='form-row'
),
Div(
HTML("<br>"),
ButtonHolder(Submit('submit', 'Save')),
css_class='float-right',
),
Div(
HTML("<br>"),
)
)
Many thanks
In the past I've used two solutions for this problem:
https://django-autocomplete-light.readthedocs.io/en/master/
I used (for some internal project) the admin widget (Horizontal Filter?). It doesn't look very nice but it might do the job... but it feels a bit hacky
I cannot think of a way to do it just using django-crispy-forms.

Unable to update individual items in Django

I am trying to update some information in my Django application but I am getting this error "Cannot assign "9": "Reservation.table" must be a "Tables" instance".
I have tried so manual method also but it still same error.
Error: Cannot assign "9": "Reservation.table" must be a "Tables" instance
views.py
#login_required
def UpdateReservation(request, pk):
table_exists = get_object_or_404(Reservation, id=pk)
form = ReservationForm(instance=table_exists)
if request.method == "POST":
form = ReservationForm(request.POST, instance=table_exists)
if form.is_valid():
form = ReservationForm(request.POST, instance=table_exists)
if form.is_valid():
form.save()
return redirect('view_reservations')
messages.success(request, "successfully updated table")
context = {"form": form}
return render(request, "dashboard/super/landlord/update_reserve.html", context)
models.py
class Reservation(models.Model):
status_choices = (
("pending", "pending"),
("confirmed", "confirmed")
)
first_name = models.CharField(max_length=200)
last_name = models.CharField(max_length=200)
email = models.EmailField()
phone = PhoneNumberField(blank=True)
people = models.IntegerField(default=1)
time = models.TimeField()
date_reserved = models.DateField()
date_booked = models.DateTimeField(auto_now_add=True)
status = models.CharField(max_length=10, choices=status_choices, default="confirmed")
comment = models.TextField(blank=True)
table = models.ForeignKey(Tables, on_delete=models.CASCADE)
def __str__(self):
return self.first_name
forms.py
class ReservationForm(forms.ModelForm):
time = forms.CharField(
widget=forms.TextInput(attrs={'id': 'timepicker',
'class': 'input-group',
'placeholder': '12:00:AM'}))
date_reserved = forms.DateField(widget=forms.TextInput(
attrs={'placeholder': 'yyyy-mm-dd',
'id': 'datepicker'}), required=True,)
comment = forms.CharField(widget=forms.TextInput(
attrs={'placeholder': 'Leave a message'}), required=True,)
first_name = forms.CharField(widget=forms.TextInput(
attrs={'placeholder': 'Leave a message'}), required=False,)
email = forms.CharField(widget=forms.TextInput(
attrs={'placeholder': 'Your Email Address'}), required=True,)
phone = forms.CharField(widget=forms.TextInput(
attrs={'placeholder': 'Your Telephone number'}), required=True,)
table = forms.IntegerField(widget=forms.TextInput(
attrs={'placeholder': 'Table Number'}), required=True,)
class Meta:
model = Reservation
fields = ['first_name', 'email', 'time', 'comment',
'phone', 'date_reserved', 'people', 'table']
template.html
<div class="panel-body">
<form class="form-horizontal" role="form" method="post" enctype="multipart/form-data">
{% csrf_token %}
{% for field in form %}
<div class="form-group">
<label class="col-md-2 control-label">{{ field.label }}</label>
<div class="col-md-10">
{{ field|attr:'class:form-control'}}
</div>
</div>
{% endfor %}
<div class="form-group">
<div class="col-md-10">
<center><button class="btn btn-primary" type="submit">Update Reservation</button></center>
</div>
</div>
</div>
You can not make use of an IntegerField, since it expects a Table, not an integer for table. You should use a ModelChoiceField and then use a TextInput as widget:
table = forms.ModelChoiceField(
queryset=Table.objects.all()
widget=forms.TextInput(attrs={'placeholder': 'Table Number'}),
required=True
)
In your form remove your table field from the field list above but keep the one in the Meta, its messing with it because the value is in Integer and you have to assign an object.

Is it possible to create an edit form using crispy form?

I've a form named "CarForm". I 've created a "Create Form" to create car record using crispy form. I would like to ask is it possible to display the detail and update the car record using the same form?
Here is the code for CarForm:
from .models import *
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Submit, HTML, Row, Column
from crispy_forms.bootstrap import PrependedAppendedText, PrependedText, FormActions
from django.urls import reverse
class CarForm(forms.ModelForm):
note = forms.CharField(widget=forms.Textarea())
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['note'].required = False
self.fields['policy_num'].required = False
self.helper = FormHelper()
self.helper.form_method = 'POST'
self.helper.form_action = reverse('create')
self.helper.layout = Layout(
Row(
Column('reg_num', css_class='form-group col-md-6 mb-0'),
Column('make', css_class='form-group col-md-6 mb-0'),
Column('year', css_class='form-group col-md-4 mb-0'),
Column('color', css_class='form-group col-md-4 mb-0'),
Column('cc', css_class='form-group col-md-4 mb-0'),
Column('engine_num', css_class='form-group col-md-6 mb-0'),
Column('chasis_num', css_class='form-group col-md-6 mb-0'),
css_class='form-row'
),
'note',
Row(
Column(PrependedAppendedText('price_buy', 'RM','.00'), css_class='form-group col-md-6 mb-0'),
Column(PrependedAppendedText('price_sell','RM','.00'), css_class='form-group col-md-6 mb-0'),
Column('policy_num', css_class='form-group col-md-12 mb-0'),
Column('owner_name', css_class='form-group col-md-4 mb-0'),
Column('owner_ic',css_class='form-group col-md-4 mb-0'),
Column('owner_phone', css_class='form-group col-md-4 mb-0'),
css_class='form-row'
),
FormActions(
Submit('submit', 'Create'),
)
)
class Meta:
model = Car
exclude = ['date']
Code in views.py.
I've added instance in the edit function, but there is an error for all the field this field is required
def edit(request,id):
car = Car.objects.get(id=id)
form = CarForm(request.POST,instance=car)
context = { 'car':car ,'form':form }
return render(request,'cars/edit.html',context)
def update(request,id):
car = Car.objects.get(id=id)
car.reg_num = request.POST['reg_num']
car.make = request.POST['make']
car.color = request.POST['color']
car.year = request.POST['year']
car.engine_num = request.POST['engine_num']
car.chasis_num = request.POST['chasis_num']
car.note = request.POST['note']
car.price_buy = request.POST['price_buy']
car.price_sell = request.POST['price_sell']
car.policy_num = request.POST['policy_num']
car.owner_name = request.POST['owner_name']
car.owner_ic = request.POST['owner_ic']
car.owner_phone = request.POST['owner_phone']
car.save()
messages.success(request,'Car "%s" updated successfully' % car.reg_num)
return redirect('/cars/list/')
Here is the code for edit.html:
{% block title %}Edit Car Record{% endblock %}
{% load crispy_forms_tags %}
{% block content %}
<h1 align="center">Edit Car Record</h1>
{% crispy form %}
{% endblock %}