I've implemented a MultipleChoiceField form with a CheckboxSelectMultiple. It works perfectly in that the form is displayed and user selected options are saved to the BaseServicesOffered model as desired. The problem is that when the user goes back to the form, the checkboxes that the user had previously selected/submitted are not selected -- they are all unchecked. I'd imagine that it's a problem with my views.py. Here is my code:
models.py
class BaseServicesOffered(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
service = models.CharField(max_length=255, default='', null=True, blank=True)
def __str__(self):
return self.user.username
forms.py
class BaseServicesOfferedForm(forms.ModelForm):
service = forms.MultipleChoiceField(required=False, widget=forms.CheckboxSelectMultiple)
def __init__(self, *args, **kwargs):
user = kwargs.pop('user') #this takes in the value of 'user', which is passed from the view function.
super(BaseServicesOfferedForm, self).__init__(*args, **kwargs)
self.fields['service'].choices = [(t.id, t.service) for t in AllServices.objects.filter(industrycode=user.userprofile.industry)]
class Meta:
exclude = ('user',)
model = BaseServicesOffered
views.py
#login_required(login_url="/accounts/login/")
def baseservicesoffered(request):
try:
base_services_offered = BaseServicesOffered.objects.create(user=request.user)
except:
pass
user = request.user
instance = get_object_or_404(BaseServicesOffered, user=user)
form = BaseServicesOfferedForm(request.POST or None, user=request.user, instance=instance)
if request.method == 'POST':
if form.is_valid():
instance = form.save(commit=False)
instance.user = request.user
service = form.cleaned_data['service']
services = [int(i) for i in service]
instance.service = services
instance.save()
return redirect('/accounts/profile/')
else:
context = {'form': form}
return render(request, 'accounts/setup8.html', context)
context = {'form': form}
return render(request, 'accounts/setup8.html', context)
setup8.html
<form id="post_form" method="post" action="" enctype="multipart/form-data">
{{ form.non_field_errors }}
{% csrf_token %}
{{ form.as_p }}
<div class="submitbutton">
<button type="submit">
SUBMIT
</button>
</div>
</form>
Update:
This is how you store a list of ints in the Charfield:
service = form.cleaned_data['service']
services = [int(i) for i in service] #converts list of strings to list of ints
instance.service = services
I've updated my code above with this.
multiple_choice = forms.MultipleChoiceField(
label=u"Select multiple",
choices=MY_CHOICES,
widget=forms.widgets.CheckboxSelectMultiple,
initial=(c[0] for c in MY_CHOICES)
)
You should set the inital parameter for the options to be checked for a particular user.
Related
I am trying to upload image from form but whenever I submit everything got saved in database other than image field.But when I try to do samething from admin panel it works.
models.py
class Post(models.Model):
title = models.CharField(("Title"), max_length=100)
title_image = models.ImageField(
("Title Image"),
upload_to='static/Images/TitleImages/',
max_length=None,
blank = True,null = True)
Forms.py
class AddPostForm(ModelForm):
class Meta:
model = Post
fields = ['title','title_image']
Views.py
class AddPostView(LoginRequiredMixin,CreateView):
model = Post
template_name = 'MainSite/add_post.html'
fields = '__all__'
def dispatch(self, request, *args, **kwargs):
if request.user.is_anonymous:
messages.error(request,"You need to login to access this page")
return redirect('/')
elif request.user.is_superuser:
if request.method == "POST":
form = AddPostForm(request.POST)
if form.is_valid():
form.save()
messages.success(request,"POST added successfully")
return redirect('/')
else:
print("error")
else:
print("method is not post")
form = AddPostForm()
return render(request,'MainSite/add_post.html',{'form':form})
else :
messages.error(request,"You need to have superuser permission to access this page")
return redirect('/')
addpost.html
<form action= "" method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form.media }}
{{ form|crispy}}
<button class="btn btn-primary profile-button" style = "width:150px;"type="submit" >Add Post</button></div>
</form>
my model have 2 things title and title_image but whenever I submit only title is saved and when I do through admin panel it works.
I dont know what I am doing wrong here any advice will be helpful.
Thanks in advance
You've to pass request.FILES in order to save files
if request.method == "POST":
form = AddPostForm(request.POST, request.FILES)
if form.is_valid():
form.save()
messages.success(request,"POST added successfully")
return redirect('/')
I just cant make my modelform to validate. I call it from view, and GET prints it right, but when POST occurs it doesn´t validate.
Allways getting
ValueError Exception Value: The view
gestionPartesMedicos.views.partes_medicos_add didn't return an
HttpResponse object. It returned None instead.
form´s name attributes correspond to model´s and form´s.
---UPDATED---
This my model:
class MedicalList(models.Model):
worker= models.ForeignKey(worker, on_delete=models.CASCADE)
description=models.CharField(max_length=255)
upload=models.FileField(upload_to=user_directory_path, null=False, blank=False)
created_at=models.DateTimeField(auto_now_add=True)
this my form class:
class MedicalListForm(forms.ModelForm):
worker = forms.ModelChoiceField(
queryset=Worker.objects.none(),
empty_label=None,
widget=forms.Select(attrs={'class': 'form-control'})
)
description=forms.CharField(
widget=forms.Textarea(attrs={'class': 'form-control'})
)
upload=forms.FileField(
widget=forms.ClearableFileInput(attrs={'class': 'form-control'})
)
class Meta:
model = MedicalList
fields = (
'worker',
'description',
'upload',
)
def __init__(self, *args, **kwargs):
user_id = kwargs.pop('user_id', None)
super().__init__(*args, **kwargs)
self.fields['worker'].queryset = Worker.objects.filter(user_id=user_id)
And this my view in trouble:
def medical_list_add(request):
if request.method == "POST":
form = MedicalListForm(request.POST,request.FILES,user_id=request.user)
if form.is_valid():
form.save()
return redirect('medical_list')
else:
form = MedicalListForm(user_id=request.user)
return render(request, 'medical_list_add.html', {'form': form})
The form in template:
<form method="POST">
{% csrf_token %}
<div class="form-group">
{{ form.as_p }}
<button type="submit" class="btn btn-primary">Guardar</button>
<a class="nav-item linking" href = "{% url 'medical_list' %}">Cancel</a>
</div>
</form>
this is the response I get:
Request information USER 12345
GET No GET data
POST Variable Value csrfmiddlewaretoken
'2zG3amQlZlPsrytMtF91ZiJQDZ679E2Zgrx3YxcOPzcNj6dNCl101Lj0UV96STLY'
worker '14' description 'pm' upload 'medical.pdf'
Might it be around Model field created_at? just trying to guess, totally lost.
thanks in advance
The main problem is that your view does not return a HTTP response in case the form was invalid. You should unindent the render(…) call with:
def medical_list_add(request):
if request.method == "POST":
form = MedicalListForm(request.POST,request.FILES,user_id=request.user)
if form.is_valid():
form.save()
return redirect('medical_list')
else:
form = MedicalListForm(user_id=request.user)
# ↓↓ both for GET and a failed POST
return render(request, 'medical_list_add.html', {'form': form})
Furthermore the form fields are specified at class level. By constructing a form field in the __init__ method, this will not use that
class MedicalListForm(forms.ModelForm):
worker = forms.ModelChoiceField(
queryset=Trabajador.objects.none(),
empty_label=None,
widget=forms.Select(attrs={'class': 'form-control'})
)
description=forms.CharField(
widget=forms.Textarea(attrs={'class': 'form-control'})
)
upload=forms.FileField(
widget=forms.ClearableFileInput(attrs={'class': 'form-control'})
)
class Meta:
model = MedicalList
fields = (
'worker',
'description',
'upload',
)
def __init__(self, *args, **kwargs):
user_id = kwargs.pop('user_id', None)
super().__init__(*args, **kwargs)
self.fields['worker'].queryset = worker.objects.filter(user_id=user_id)
If your form handles files, you should set the enctype=… parameter to multipart/form-data:
<form method="POST" enctype="multipart/form-data">
…
</form>
I've spent several hours on this and I'm not able to see any signs as to why the change on the flag is not getting through.
Please note the change form already works for all exposed fields, i.e. the user can go in and change the name or country already and it will get saved after clicking on update profile.
What I'm now trying to do is to also change the confirmed_email flag to True (but without telling or letting the user see it) whenever the client makes an update to the form.
To do this I check if the user was logged in using Linkedin (or any Social account for that matter) via something along the lines of ""if user.social_auth.exists()"". That said, it's not that i can't fulfill this function, it's that even when i use a silly condition that i know it's true the field "email_confirmed" will still NOT change to True in the back-end.
Thanks so much in advance. I appreciate your time.
PS. I'm a noob with Django but loving it.
Models.py
class CustomUser(AbstractUser):
id = models.BigAutoField(primary_key=True)
email = models.EmailField(unique=True)
email_confirmed = models.BooleanField(default=False)
country = models.CharField(max_length=30,choices=COUNTRY, null=True, blank=False)
first_name = models.CharField(max_length=50, null=False, blank=False, default="")
last_name = models.CharField(max_length=50, null=False, blank=False, default="")
Views.py
class SignUpView(CreateView):
form_class = CustomUserCreationForm
success_url = reverse_lazy('home')
template_name = 'signup.html'
...
class UpdateProfileView(UpdateView):
form_class = CustomUserChangeForm
success_url = reverse_lazy('home')
template_name = 'update_profile.html'
def get_object(self, queryset=None):
return self.request.user
Forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from .models import CustomUser
class CustomUserCreationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = CustomUser
fields = ('first_name', 'last_name','country',)
class CustomUserChangeForm(UserChangeForm):
password = None
class Meta:
model = CustomUser
fields = ('first_name', 'last_name','country',)
update_profile.html
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block title %}Home{% endblock title %}
{% block content %}
{% if user.is_authenticated %}
<h2>Update Profile</h2>
<form method="post">
{% csrf_token %}
{{ form|crispy }}
<button class="btn btn-success" type="submit">Update</button>
</form>
{% else %}
<p>You are not logged in</p>
Log In |
Sign Up
{% endif %}
{% endblock content %}
My main attempt was to adding another leg in the view (see def ChangeActiveStatus below).
class UpdateProfileView(UpdateView):
form_class = CustomUserChangeForm
success_url = reverse_lazy('home')
template_name = 'update_profile.html'
def get_object(self, queryset=None):
return self.request.user
def ChangeActiveStatus(request):
if request.method == "POST":
form = self.form_class(request.POST)
user = form.save(commit=False)
if form.is_valid() and user.social_auth.exists() == True:
user.email_confirmed = True
form.save()
else:
form = form()
return render(request, 'login', {'form':form})
The issue here is that you're setting the email_confirmed = True on user and not form.instance. You could also save the user instance rather than calling form.save().
form = self.form_class()
if request.method == "POST":
form = self.form_class(request.POST)
if form.is_valid() and user.social_auth.exists():
user = form.save(commit=False)
user.email_confirmed = True
user.save()
return render(request, 'login', {'form':form})
Or
form = self.form_class()
if request.method == "POST":
form = self.form_class(request.POST)
if form.is_valid() and user.social_auth.exists():
form.instance.email_confirmed = True
form.save()
return render(request, 'login', {'form':form})
I ended up implementing a solution via models.py instead, basically bypassing the need to save any changes on one of the fields through the views, i.e. this is the logic, which will be triggered every time the client changes something in their profile.
def save(self, *args, **kwargs):
try:
CustomUser.objects.latest('id').id
except:
...
...
if self.is_active == True and self.email_verified == False:
self.email_verified = True
super(CustomUser, self).save(*args, **kwargs)
def __str__(self):
return self.email
I want to add tags to posts in my Django app.
I can add tags through the admin interface, but when I try to do it through the form I created, I get an IntegrityError.
I couldn't find the solution in the existing topics with the same error. I ran makemigrations and migrate.
From models.py:
class Post(models.Model):
title = models.CharField(null=False, blank=False)
text = models.TextField()
class Tag(models.Model):
post = models.ForeignKey('my_app.Post', on_delete=models.CASCADE, related_name='tags')
tag_text = models.CharField()
The view:
def post_add_tags(request, pk):
post= get_object_or_404(Post, pk=pk)
if request.method == "POST":
form = TagForm(request.POST)
if form.is_valid():
tag = form.save()
tag.post= post
tag.save()
return redirect("single_post_view", pk=post.pk)
else:
form = TagForm()
return render(request, "add_tags.html", {"form": form})
The form from forms.py:
class TagForm(forms.ModelForm):
class Meta:
model = Tag
fields = ["tag_text"]
The template:
<form method="POST"> {% csrf_token %}
{{ form.as_p }}
<button type="submit" class="save btn btn-default">Add tags</button>
</form>
The error:
IntegrityError at /post/4/add_tags/
NOT NULL constraint failed: my_app_tag.post_id
I'm using Django version 2.2, Python 3.6.8.
do not save form until you set all required fields, specially foreign keys :
def post_add_tags(request, pk):
post= get_object_or_404(Post, pk=pk)
if request.method == "POST":
form = TagForm(request.POST)
if form.is_valid():
tag = form.save(commit=False)
tag.post= post
tag.save()
return redirect("single_post_view", pk=post.pk)
else:
form = TagForm()
return render(request, "add_tags.html", {"form": form})
I am new to Django and I am trying to add comments for a post in a blog in Django 2.1. When adding comments to a post, I need to save the user_id of logged in user and post_id of that comment. I defined my comment model with relations to post and user models as below:
class Comments(models.Model):
comment = models.CharField(max_length=120, null=True, )
name = models.CharField(max_length=120, null=True)
created_by = models.ForeignKey(User, related_name='created_by', null=True, on_delete=models.PROTECT)
post_name = models.ForeignKey(Post, related_name='post_name', null=True, on_delete=models.PROTECT)
def __str__(self):
return self.comment
There is the template code where I use CommentForm and get the data comments from the user:
{% if user.is_authenticated %}
<form method="POST" action=" ">
<div class="form-group"></div>
{% csrf_token %}
{{ form.as_p }}
<input type='submit' class="btn btn-success" />
</form>
{% else %}
Add Comment
{% endif %}
I used __init__() method in CommentForm to get the post_id and user_id. This method works fine for first parameter 'post' and gets post_id and saves it, but not is working for getting user_id 'create'. I want to get the session user_id and pass it from views.py to forms.py and save it with comment creation same as getting post_id. Is it possible to pass more than one parameter from views.py and pass it to form and get them in that form to save to that model?
Here is the code which I wrote for doing above functionality:
veiws.py
My method for creating comments:
def details(request, id):
instance = get_object_or_404(Post, id=id)
if request.method == 'GET':
form = CommentForm(request.POST or None, request.FILES or None)
if request.method == 'POST':
form = CommentForm(request.POST or None, request.FILES or None, post=instance.id) # get and pass post_id of related post
if request.method == 'POST':
if request.user:
user = request.user.id
form = CommentForm(request.POST or None, request.FILES or None, create=user) # Wants to get the session user id and pass it to forms.py
forms.py
In my CommentForm I have following method:
def __init__(self, args, *kwargs):
post = kwargs.pop('post', '')
super(CommentForm, self).__init__(*args, **kwargs)
if post:
self.fields['post_name'] = forms.ModelChoiceField(queryset=Post.objects.filter(pk=post))
create = kwargs.pop('create', '')
print(kwargs)
super(CommentForm, self).__init__(*args, **kwargs)
if create:
self.fields['created_by'] = forms.ModelChoiceField(queryset=Comments.objects.filter(created_by=create))
Above code works for first parameter 'post' but not for second parameter 'create' and give the "name 'create' is not defined" error.