I have a website which allows Users to pick a few hobbies they enjoy. Currently the website loads these hobbies from a Model and lists them with a Checkbox. What I want to do is when a User saves the form, it should also save these Checkbox values to the database - i.e if they tick Football, the database should save the fact that this User enjoys football. I am new to Django and Python so not too sure how to accomplish this. Here is the code I am using. This is the Models.py file for the Hobbies:
TYPES = (
("Football", "Football"),
("Cricket", "Cricket"),
("Swimming", "Swimming"),
("Cycling", "Cycling")
)
class Hobby(models.Model):
myfield = models.CharField(max_length=50, choices = TYPES, default=TYPES[0], null=True)
football = models.BooleanField(default = False)
cricket = models.BooleanField(default = False)
swimming = models.BooleanField(default = False)
cycling = models.BooleanField(default = False)
This is the relevant views.py file:
def profile(request, user):
# use this for debugging:
# import pdb; pdb.set_trace()
if 'email' in request.POST:
email = request.POST['email']
gender = request.POST['gender']
dob = request.POST['dob']
## hobby = request.POST['hobby']
if user.profile:
user.profile.email = email
user.profile.gender = gender
user.profile.dob = dob
## user.profile.hobby = hobby
user.profile.save()
else:
profile = Profile(email=email, gender=gender, dob=dob)
profile.save()
user.profile = profile
user.save()
context = {
'appname': appname,
'username': user.username,
'profile' : user.profile,
'all_hobbies': [hobby[0] for hobby in TYPES],
'loggedin': True
}
return render(request, 'mainapp/profile.html', context)
And lastly the HTML/JS code to display the information:
<span class="fieldname">Hobbies</span>
{% for hobby in all_hobbies %}
<input type="checkbox" name={{hobby}} value={{hobby}}> {{hobby}}<br>
{% endfor %}
<input type='submit' value='Save'>
What I want is a way to check whether the checkboxes have been ticked, and if so to change the value of the BooleanField in the database/model to either True or False. However, I am not sure where to do this, in the views or the JS code. Can someone help me out here? Many thanks.
For this case to list all hobbies and update them again. You need to use a Form Class. Example. I just want to mention a single thing, the code below its just a guideline of what you should do. Because Its kind of confusing the logic you want to approach. Since you are not handleing a user as a session but just a plain key.
model.py
my_choices = (
(0, "None"),
(1, "Football"),
(2, "Cricket"),
(3, "Swimming"),
(4, "Cycling"),
)
class Hobby(models.Model):
user = models.ForeignKey(Profile, on_delete=models.DO_NOTHING)
field = models.integerField(choices=my_choices, default=0)
forms.py
class HobbyForm(ModelForm):
class Meta:
model = Hobby
fields = ["field"]
views.py
def profile(request,user):
try:
profile_object = Profile.get(id=user)
if request.method.POST:
form = HobbyForm(request.POST)
if form.is_valid():
profile_object.field = form.cleaned_data["field"]
profile_object.save()
context = {
"form": form,
"profile": profile_object,
}
return render(request, 'mainapp/profile.html', context)
else:
context = {
"form": form,
"profile": profile_object,
}
return render(request, 'mainapp/profile.html', context)
else:
context = {
"form": form,
"profile": profile_object,
}
return render(request, 'mainapp/profile.html', context)
except Profile.DoesNotExists:
context = {
"form": form,
"profile": profile_object,
}
return render(request, 'mainapp/profile.html', context)
profile.html
<form action="myurl/{{profile.id}}/" method="post">
{% csrf_token %}
{% form.as_p %}
<input type="submit" value="OK">
</form>
Related
I am creating a form with all sorts of headers and question before each field.
I initially create a form in Forms.py, but it seems quite difficult to customise it the way I want it.
I resorted to build the form in the html template.
I am struggling to create a drop down menu.
In this example, when selecting the colour, users would have 4 choices listed in the choices in models.py. I am clearly not linking the form in the template to the actual form.
What am I doing wrong?
(I should say, I saw a couple of things on here about fieldsets, but I dont understand the actual solutions explained)
Here is the code
Models.py
LOOKCOLOUR=(
(1,'Straw'),
(2,'Yellow'),
(3,'Gold'),
(4,'Amber'),
)
class ChampageRating(models.Model):
user = models.ForeignKey(User,blank=True, on_delete=models.CASCADE)
product=models.ForeignKey(Product,related_name="champcomments", on_delete=models.CASCADE)
look_colour=models.IntegerField(choices=LOOKCOLOUR, default=0)
..
def __str__(self):
return '%s - %s - %s'%(self.user, self.product, self.date_added)
forms.py
class ElderFlowerChampForm(ModelForm):
class Meta:
model = ChampageRating
fields = ('look_colour', )
labels ={
'look_colour': 'Colour',
}
widgets = {
'look_colour':forms.Select(attrs={'class':'form-control'}),
}
views.py
def elderflowerchamp(request, product_id):
global ChampageRating
product = Product.objects.get(pk=product_id)
url = request.META.get('HTTP_REFERER')
submitted = False
try:
if request.method == "POST":
reviews = ChampageRating.objects.get(pk=product_id)
if request.user.is_superuser:
form = ElderFlowerChampFormAdmin(request.POST, instance=reviews)
if form.is_valid():
form.save()
return redirect('home')
else:
form = ElderFlowerChampForm(request.POST, instance=reviews)
if form.is_valid():
ChampageRating = form.save(commit=False)
ChampageRating.user = request.user
ChampageRating.save()
return redirect('home')
else:
#This part goes to the page, but doesnt submit
reviews = ChampageRating.objects.get(pk=product_id)
if request.user.is_superuser:
form = ElderFlowerChampFormAdmin
else:
form = ElderFlowerChampForm
if 'submitted' in request.GET:
submitted = True
except:
reviews = None
if request.user.is_superuser:
form = ElderFlowerChampFormAdmin(request.POST)
if form.is_valid():
data = ChampageRating()
data.rating = form.cleaned_data['rating']
data.look_colour = form.cleaned_data['look_colour']
data.ip = request.META.get('REMOTE_ADDR')
data.product_id = product_id
data.user_id = request.user.id
data.save()
messages.success(request, 'Thank you! Your review has been submitted.')
return redirect('home')
else:
form = ElderFlowerChampForm(request.POST)
if form.is_valid():
data = ChampageRating()
data.rating = form.cleaned_data['rating']
data.look_colour = form.cleaned_data['look_colour']
data.ip = request.META.get('REMOTE_ADDR')
data.product_id = product_id
data.user_id = request.user.id
data.save()
messages.success(request, 'Thank you! Your review has been submitted.')
return redirect('home')
template
<form action="{% url 'ElderFlowerReview' product.id%}" method="POST">
{%csrf_token%}
<h4>Look</h4>
<h5>Colour</h5>
<select name="look_colour" rows="4" class="form-control"></select>
</form>
Just in case someone comes across the same problem, I kinda found the solution. (it creates new problems, but it's a start).
Source here: https://github.com/hadpro24/django-forms-fieldset
Here is what I did.
I installed fieldsets (thats the part I was missing on other posts)
pip install django-forms-fieldset
I added fieldsets in the installed apps (in setting.py)
INSTALLED_APPS = [
,
'forms_fieldset']
in forms.py Fieldsets need to be added before Meta
class ElderFlowerChampFormAdmin(ModelForm):
fieldsets=[
("Look",{'fields':[
('look_colour','look_clarity','look_effervescence')]}),
]
class Meta:
model = ChampageRating
fields = ('user','look_colour', ..)
labels ={
'user': '',
'product': '',
'look_colour': '',
}
widgets = {
'user': forms.Select(attrs={'class':'form-control'}),
'look_colour':forms.Select(attrs={'class':'form-control'}),
}
then in the template
{% load forms_fieldset static %}
<link rel="stylesheet" type="text/css" href="{% static 'forms_fieldset/css/main.css' %}">
<form action="{% url '#' product.id%}"method = POST>
{%csrf_token%}
{{ form|fieldset}}
<button class="btn btn-secondary">Add Review</button>
</form>
I have four fields in a model, one of which is a foreign key field and the other three are m2m fields. The form is opened in the modal, but the data is not being saved, Error given below. I don't understand what I did wrong. I would be very grateful for a little help.
Model:
class ProductAttributes(models.Model):
product = models.ForeignKey('Product', blank=True, null=True, on_delete=models.SET_NULL)
size = models.ManyToManyField('ProductSize', blank=True)
colour = models.ManyToManyField('ProductColour', blank=True)
cupsize = models.ManyToManyField('ProductCupSize', blank=True)
def __str__(self):
return self.product
Form:
class ProductAttributesForm(forms.ModelForm):
product = forms.IntegerField(label=('ID'),required=True, disabled=True)
size = forms.ModelMultipleChoiceField(queryset=ProductSize.objects.all(),widget=Select2MultipleWidget, required=False)
colour = forms.ModelMultipleChoiceField(queryset=ProductColour.objects.all(),widget=Select2MultipleWidget, required=False)
cupsize = forms.ModelMultipleChoiceField(queryset=ProductCupSize.objects.all(),widget=Select2MultipleWidget, required=False)
class Meta:
model = ProductAttributes
fields = ['product','size','colour','cupsize']
Template:
{% load crispy_forms_tags %}
<form id="Form" method="post" action="{% url 'accpack:products_attributes_create' product %}" class="js-product-create-form col s12" >
{% csrf_token %}
{% crispy form form.helper %}
</form>
View:
def save_attribute_form(request, form, template_name, pk):
data = dict()
if request.method == 'POST':
if form.is_valid():
form.save()
data['form_is_valid'] = True
else:
data['form_is_valid'] = False
context = {'form': form, 'product':pk}
data['html_form'] = render_to_string(template_name, context, request=request)
return JsonResponse(data)
def attribute_create(request, pk):
if request.method == 'POST':
form = ProductAttributesForm(request.POST, initial={'product': pk})
else:
form = ProductAttributesForm(initial={'product': pk})
return save_attribute_form(request, form, 'main/products/partial_product_attribute_form.html', pk)
ajax:
var saveForm = function () {
var form = $(this);
$.ajax({
url: form.attr("action"),
data: form.serialize(),
type: form.attr("method"),
dataType: 'json',
success: function (data) {
if (data.form_is_valid) {
$("#modal-product_attribute").modal("hide");
console.log(data.form_data);
}
else {
$("#modal-product_attribute .modal-content").html(data.html_form);
}
}
});
return false;
$("#modal-product_attribute").on("submit", ".js-product-create-form", saveForm);
error:
File "C:\ProgramData\Anaconda3\envs\djangoproject\lib\site-packages\django\db\models\fields\related_descriptors.py", line 220, in __set__
self.field.remote_field.model._meta.object_name,
ValueError: Cannot assign "111": "ProductAttributes.product" must be a "Product" instance.
You have an error in your forms.py.
class Meta:
model = ProductSize
fields = ['product','size','colour','cupsize']
Here, the model should be
model = ProductAttributes
Since the model you specified here ProductSize does exist, submitting form will just create another instance to ProductSize model without those specific fields and error messages. You can check your admin page.
EDIT ******
2. Based on what you added in the question and the error message, it looks like in attribute_create you are passing product's pk. Now in the attribute_create, you are passing initial dict {'product': pk}. This is wrong, because, in your ProductAttributesForm, the product field should be an instance rather than a pk.
You need to refer product as
product = Product.objects.filter(pk=pk)
initial = {'product':product}
The current error message will be gone, but you will have other errors.
I'm using Django. I need a form that shows the 3 fields of a class that I have created, the idea is that every time you want to add a new day and time to start and end, show a new new section, so that each teacher can be found in more of a day and time of beginning and end (the three fields go together)
I still do not logo to make it work, if someone has any idea they would be grateful.
Models.py
class Profesor(Person):
legajo = models.IntegerField(blank=True, null=True)
type = models.CharField(max_length=30)
matter = models.CharField(max_length=100, blank=True, null=True)
calendar = models.ForeignKey('calendar', on_delete=models.DO_NOTHING)
user = models.CharField(max_length=20, blank=True, null=True)
class calendar(models.Model):
day = models.DateTimeField(default=date.today().isoweekday())
hs_init = models.DateTimeField(default=datetime.now().hour)
hs_end = models.DateTimeField(default=datetime.now().hour)
Forms.py
class addProfesorForm(ModelForm):
calendar = forms.ModelChoiceField(queryset=calendar.objects.all(), widget=forms.HiddenInput())
class Meta:
model = Profesor
TYPES = (
('Motiv', 'Motiv'),
('Academic', 'Académic'),
('Otro', 'Otro')
)
help_texts = {
'matter': 'message'
}
fields = ['id', 'type', 'matter']
widgets = {
'type': Select2Widget(choices=typeS)
}
class calendarForm(ModelForm):
class Meta:
model = calendar
fields = ['day','hs_init','hs_end']
Views.py
def agregarTutor(request):
if request.method == 'POST':
form = addProfesorForm(request.POST['calendar'])
calendar=calendar.objects.all()[0]
if form.is_valid():
id = form.cleaned_data['id']
try:
person_Sysatem = SysatemPerson.objects.get(pk=id)
alumn_Sysatem = SysatemAlumn.objects.get(pk=id)
except SysatemPerson.DoesNotExist:
return render(request, 'menu/new-Profesor.html',
{'new_manual': True, 'not_found': True, 'nbar': 'profesors', 'id': id})
new_Profesor = Profesor(
nombre=person_Sysatem.nombre.rstrip(),
id=person_Sysatem.numerodocu,
legajo=alumn_Sysatem.legajo,
telefono=person_Sysatem.telefono.rstrip(),
mail=person_Sysatem.mail.rstrip(),
type=form.cleaned_data['type'],
calendar=form.cleaned_data['calendar'],
matter=form.cleaned_data['matter'],
user=id,
)
Profesor.save(new_Profesor)
contrasena = 'id'+str(id)[0:5]
user = User.objects.create_user(id, person_Sysatem.mail.rstrip(), contrasena)
user.first_name = person_Sysatem.nombre.rstrip()
user.save()
form = addProfesorForm(initial={'calendar':calendar})
return render(request, 'menu/new-Profesor.html', {'form': form, 'Profesor': new_Profesor, 'success': True, 'nbar': 'profesors'})
else:
return render(request, 'menu/new-Profesor.html', {'form': form, 'error_form': True, 'nbar': 'profesors'})
else:
form = addProfesorForm()
return render(request, 'menu/new-Profesor.html', {'form': form, 'nbar': 'profesors'})
Template.html
<h2>new Profesor</h2>
<div class="row">
<div class="col">
<form method="post">{% csrf_token %}
{% include 'common/form_template.html' with form=form %}
<button type="submit" style="margin-top: 10px; float: right;" class="btn btn-primary">Add</button>
</form>
</div>
</div>
Problem description: UserProfile form doesn't save any data.
I am creating a new User and automatically create a UserProfile object for him (so I'm extending UserProfile), so I can go to admin page and fill all the fields . But when I'm trying to do it from client side, my form just doesn't catch the data.
Also the strangest moment is that I can change username and email using UserChangeForm, so I'm trying to do the same for UserProfileObject.
models.py:
class UserProfile(models.Model):
user = models.OneToOneField(User)
image = models.ImageField(upload_to='profile_image', blank=True)
title = models.CharField(max_length=100, default = '')
first_name = models.CharField(max_length=200, default = '')
last_name = models.CharField(max_length=200, default = '')
subject = models.ManyToManyField('Subject', related_name='tutor_type', default = '', help_text="Select a subject")
AREA_STATUS = (
('Jerusalem', 'Jerusalem'),
('Tel Aviv', 'Tel Aviv'),
('Haifa', 'Haifa'),
('Eilat', 'Eilat')
)
area = models.CharField(max_length=200, choices=AREA_STATUS, blank=True, default='', help_text='Tutor area')
# Foreign Key used because tutor can only have one area, but area can have multiple tutors
# Author as a string rather than object because it hasn't been declared yet in file.
description = models.TextField(max_length=4000, help_text="Enter a brief description about yourself")
charge = models.IntegerField(default = '0')
# ManyToManyField used because Subject can contain many tutors. Tutors can cover many subjects.
# Subject declared as an object because it has already been defined.
LANGUAGE_CHOICES = (
('English','English'),
('Hebrew','Hebrew'),
('Russian','Russian'),
('French','French'),
('Arabic','Arabic'),
)
language = models.CharField('Language', choices = LANGUAGE_CHOICES, max_length=50, null=True)
def __str__(self):
return self.user.username
def display_subject(self):
"""
Creates a string for the subject. This is required to display subject in Admin.
"""
return ', '.join([ subject.name for subject in self.subject.all()[:3] ])
display_subject.short_description = 'Subject'
def create_profile(sender, **kwargs):
if kwargs['created']:
user_profile = UserProfile.objects.create(user=kwargs['instance'])
post_save.connect(create_profile, sender = User)
forms.py::
class EditProfileForm(UserChangeForm):
class Meta:
model = User
fields = (
'username',
'email',
'password'
)
class EditExtendedProfileForm(UserChangeForm):
class Meta:
model = UserProfile
fields = '__all__'
exclude = ('user',)
views.py:
def edit_profile(request):
if request.method == 'POST':
form = EditProfileForm(request.POST, instance=request.user)
if form.is_valid():
form.save()
return redirect(reverse('accounts:view_profile'))
else:
form = EditProfileForm(instance=request.user)
args = {'form': form}
return render(request, 'accounts/edit_profile.html', args)
def edit_extended_profile(request):
if request.method == "POST":
form = EditExtendedProfileForm(request.POST, instance=request.user)
if form.is_valid():
form.save()
return redirect(reverse('accounts:view_profile'))
else:
return redirect(reverse('accounts:edit_extended_profile'))
else:
form = EditExtendedProfileForm(instance = request.user)
args = {'form':form}
return render(request, 'accounts/edit_extended_profile.html', args)
edit_extended_profile.html:
{% extends "base.html" %}
{% block head %}
<title>Profile</title>
{% endblock %}
{% block body %}
<div class = "container">
<form method="POST">
{% csrf_token %}
{{form.as_p}}
<button type = "submit" class = "btn btn-success">Submit</button>
</form>
</div>
{% endblock %}
and it is the same template as for edit_profile view.
No traceback, no errors. Any help will be appreciated. Thanks in advance.
I have different models:
Cars
Pictures (models.ForeignKey(Cars))
CarsOptions(models.OneToOneField(Cars))
Then I want, that user can add new cars. Forms.py:
class NewCarsForm(ModelForm):
class Meta:
model = Cars
exclude = ('checked','user')
In views.py:
#login_required
def add_car(request):
form = NewCarsForm(request.POST or None)
if form.is_valid():
cmodel = form.save()
cmodel.save()
return redirect(profile)
return render(request, 'add_car.html', { 'form': form,})
I have a few questions (yes, I read this).
As you can see, user can add only "car", not pictures and options. How to do this on one page in one form?
exclude = ('checked','user'), it means, that I want to make all new positions with checked=0, so I can filter them. And the user-field - users cant choose user in a list. How to take user id (who adds car) in form.save()?
Thanks.
Update:
class Pictures(models.Model):
cars = models.ForeignKey(Cars, related_name='pictures')
width = models.PositiveIntegerField(editable=False, default=640)
height = models.PositiveIntegerField(editable=False, default=480)
image = models.ImageField(upload_to=lambda inst, fname: 'users_img/' + 'cars' + fname, height_field='height', width_field='width', max_length=100)
def __unicode__(self):
return str(self.id)
forms.py
class NewCarsForm(ModelForm):
class Meta:
model = Cars
exclude = ('checked','user')
PicturesFormset = inlineformset_factory(Cars, Pictures,
fields=('field_name', 'field_name'), can_delete=True)
CarsOptionsFormset = inlineformset_factory(Cars, CarsOptions,
fields=('field_name', 'field_name'), can_delete=True)
views.py
#login_required
def add_car(request):
cars = Cars(user=request.user)
if request.method == 'POST':
form = NewCarsForm(request.POST, instance=cars)
if form.is_valid():
cmodel = form.save()
picture_formset = PicturesFormset(request.POST, request.FILES,
instance=cmodel)
if picture_formset.is_valid():
picture_formset.save()
option_formset = CarsOptionsFormset(request.POST, instance=cmodel)
if option_formset.is_valid():
option_formset.save()
return redirect(profile)
form = NewCarsForm()
picture_formset = PicturesFormset(instance=Cars())
option_formset = CarsOptionsFormset(instance=Cars())
return render(request, 'add_car.html', {
'form': form,
'picture_formset': picture_formset,
'option_formset': option_formset,
})
template
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<h4>Car:</h4>
{{ form.as_p }}
<h4>Picture:</h4>
{{ picture_formset.as_p }}
<h4>Options:</h4>
{{ option_formset.as_p }}
<input type="submit" value="Submit">
</form>