So I have the following code:
# the view
class UpdateDateView(LoginRequiredMixin, UpdateView):
model = Date
form_class = DateForm
template_name = 'app/form/date_edit_form.html'
def save_photos(self, date) -> None:
photos = self.request.FILES.getlist('photo')
current_photos = self.request.FILES.getlist('custom-photo-name') # this is not working
for photo in photos:
Photo.objects.create(date=date, photo=photo)
def form_valid(self, form):
date = form.save()
self.save_photos(date)
return super().form_valid(form)
# the form
class DateForm(forms.ModelForm):
photo = forms.ImageField(required=False)
class Meta:
model = Date
exclude = ('user',)
# the Edit form
<form action="{% url 'app:edit-date' date.slug %}" method="post" enctype="multipart/form-data">{% csrf_token %}
<div class="form-container">
...
<tr>
<th><label for="id_photo">Image:</label></th>
<td>
<input type="file" name="photo" accept="image/*" id="id_photo" multiple>
</td>
</tr>
<div class="current-photos">
{% for photo in date.photos.all %}
<div class="photo-wrapper-{{ forloop.counter }}">
<img src="{{ photo.photo.url }}" width="200px"><a class="delete-photo" id="{{ forloop.counter }}">Delete</a>
<input type="file" name="custom-photo-name" value="{{ photo }}" class="hide" id="photo_{{ forloop.counter }}">
</div>
{% endfor %}
</div>
</div>
<div class="buttons">
<input type="submit" value="Save" class="create-button redirection no_decoration">
Back
</div>
</form>
# js (jquery)
$('.delete-photo').on('click', function() {
const id = $(this).attr('id');
const div_class = `.photo-wrapper-${id}`;
$(div_class).remove()
});
I have a CreateView and UpdateView. The ImageField is not required, it is optional.
Let's assume I have created a new date with photos. Then I wanted to edit its pictures (delete some and add some new). When I click on tag (Delete), the div wrapper for that photo is being removed. When I try to save my edits, I want to access 2 different lists with photos (ones which were added in the past, and the new photos).
This self.request.FILES.getlist('custom-photo-name') seems to do nothing with current photos. Please help, maybe my code logic is bad in general? What I am missing here? What html form looks for when I submit the form, whether for the tag or maybe name attribute? Huge thanks in advance!
Related
Django-ckeditor in for loop shows correctly only for the first iteration. For the remaining iterations, the default template form appears as shown below. I see element conflict error in the documentation but it doesn't say anything how to solve. ckeditor.js:21 [CKEDITOR] Error code: editor-element-conflict. Thank you in advance!
Here is my template code
<div class="d-none" id="comment-{{answer.id}}" >
{% for comment in answer.comment_set.all %}
<div class="card mb-2" >
<div class="card-body">
<p>{{comment.comment|safe}}</p>
<p> {{comment.user.username}} </p>
</div>
</div>
{% endfor %}
</div>
<div class="d-none" id="commentForm-{{answer.id}}">
{% if user.is_authenticated %}
<div class="commentform">
<form method="post">
<div class="form-group">
{% csrf_token %}
{{ commentForm.media }}
{{commentForm|crispy}}
<input type="hidden" name="answerid" value="{{ answer.id }}">
<input type="submit" name="submit" value="Submit" >
</div>
</form>
</div>
{% endif %}
I've figured out!
It happens because fields have the same ID, and CKEditor gets confused because it finds a few elements with the same ID.
Solution: change IDs dynamically when the page is being generated.
I don't know the structure of your model, but I can assume that your form is defined like this:
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = “__all__”
Then you need to change it like this:
from ckeditor.widgets import CKEditorWidget
class CommentForm(forms.ModelForm):
base_textarea_id = "id_comment"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.textarea_id_counter = 0
self.fields['comment'].widget = CKEditorWidget(attrs={'id': self.get_textarea_next_id})
def get_textarea_next_id(self):
result = self.base_textarea_id + str(self.textarea_id_counter)
self.textarea_id_counter += 1
return result
class Meta:
model = Comment
fields = “__all__”
If I were you, I would make the form variable name using snake case and would change the name of the field "comment" inside the Comment model to something different (even "text" would be better), but it's up to you, of course.
It's my first time doing a Django Form challenge.
The challenge for now is just from a HTML Template get the last_name information and store into DB from views. So I have a scenario below:
models.py:
class Person(models.Model):
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
an HTML template, I will put below only the form part:
<form action="{% url 'store' %}" method="post">
{% csrf_token %}
<div class="form-group row">
<label for="last_name" class="col-sm-2 col-form-label">Last Name</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="last_name" placeholder="Last Name">
</div>
</div>
<div class="form-group row">
<div class="col-sm-10">
<button type="submit" class="btn btn-primary">Send Last Name</button>
</div>
</div>
</form>
And the views.py itself... I created a InsertLastName ModelForm to store the data from the form, but didn't work. For some reason, when I tryed to call form.cleaned_data I reveived an error about the is_valid() verification. Seens like that I'm not getting the information from label.
class InsertLastName(forms.ModelForm):
class Meta:
model = Person
fields = ['last_name']
exclude = ['first_name']
def index(request):
persons = Person.objects.all()
context = {'persons': persons}
return render(request, '/index.html', context)
def store(request):
form = InsertLastName(request.POST or None)
print(form.cleaned_data['last_name'])
return HttpResponse("Storing a new Last Name object into storage")
What is the correct way to get the information from last_name label in my form?
I'm following that documentation and coding from a challenge template.
Your just set attr name for your input html tag
Example:
<input type="text" name="first">
And for get input in function store in view.py:
request.POST.get("first")
Add this to your html template in your form
{{persons}}
I am very new in Python and Django. A am trying to make app but I have an issue.
Can anyone help me, please xD
I can't get id of authenticated user...
I tried it in this way, and many other ways...
views.py
class CreateProfile(CreateView):
template_name = 'layout/add_photo.html'
model = Profile
fields = ['image', 'user']
html
<form class="form-horizontal" action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
<input type="text" name="username"> #Here has to be field filled in with logged in user
<input type="file" name="image">
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-success">Save Changes</button>
</div>
</div>
</form>
And when I'm starting app, and want to change/add picture, I can do it for anyone from my database, not only for logged in user.
enter image description here
Thanks for patience and help!
In the Django ClassBasedViews you can get your user's id as self.request.user.id and in your template as {{ user.id }}
To check if someone is authenticated you can use self.request.user.is_authenticated() and in your template {% if user.is_authenticated %} .. {% endif %}
class CreateProfile(CreateView):
template_name = 'layout/add_photo.html'
model = Profile
fields = ['image', 'user']
# For example, if you want to return to a certain user
# profile (which requires url adjustments to take a Primary Key)
def get_success_url(self):
user_id = self.request.user.id # Get user_id from request
return reverse_lazy('git_project:user_profile', kwargs={'id': user_id})
I'm currently working on a fairly simple django project and could use some help. Its just a simple database query front end.
Currently I am stuck on refining the search using checkboxes, radio buttons etc
The issue I'm having is figuring out how to know when a checkbox (or multiple) is selected. My code so far is as such:
views.py
def search(request):
if 'q' in request.GET:
q = request.GET['q']
if not q:
error = True;
elif len(q) > 22:
error = True;
else:
sequence = Targets.objects.filter(gene__icontains=q)
request.session[key] = pickle.dumps(sequence.query)
return render(request, 'result.html', {'sequence' : sequence, 'query' : q, 'error' : False})
return render(request, 'search.html', {'error': True})
search.html
<p>This is a test site</p></center>
<hr>
<center>
{% if error == true %}
<p><font color="red">Please enter a valid search term</p>
{% endif %}
<form action="" method="get">
<input type="text" name="q">
<input type="submit" value="Search"><br>
</form>
<form action="" method="post">
<input type='radio' name='locationbox' id='l_box1'> Display Location
<input type='radio' name='displaybox' id='d_box2'> Display Direction
</form>
</center>
My current idea is that I check which checkboxes/radio buttons are selected and depending which are, the right data will be queried and displayed in a table.
So specifically:
How do I check if specific check-boxes are checked? and how do I pass this information onto views.py
Radio Buttons:
In the HTML for your radio buttons, you need all related radio inputs to share the same name, have a predefined "value" attribute, and optimally, have a surrounding label tag, like this:
<form action="" method="post">
<label for="l_box1"><input type="radio" name="display_type" value="locationbox" id="l_box1">Display Location</label>
<label for="d_box2"><input type="radio" name="display_type" value="displaybox" id="d_box2"> Display Direction</label>
</form>
Then in your view, you can look up which was selected by checking for the shared "name" attribute in the POST data. It's value will be the associated "value" attribute of the HTML input tag:
# views.py
def my_view(request):
...
if request.method == "POST":
display_type = request.POST.get("display_type", None)
if display_type in ["locationbox", "displaybox"]:
# Handle whichever was selected here
# But, this is not the best way to do it. See below...
That works, but it requires manual checks. It's better to create a Django form first. Then Django will do those checks for you:
forms.py:
from django import forms
DISPLAY_CHOICES = (
("locationbox", "Display Location"),
("displaybox", "Display Direction")
)
class MyForm(forms.Form):
display_type = forms.ChoiceField(widget=forms.RadioSelect, choices=DISPLAY_CHOICES)
your_template.html:
<form action="" method="post">
{# This will display the radio button HTML for you #}
{{ form.as_p }}
{# You'll need a submit button or similar here to actually send the form #}
</form>
views.py:
from .forms import MyForm
from django.shortcuts import render
def my_view(request):
...
form = MyForm(request.POST or None)
if request.method == "POST":
# Have Django validate the form for you
if form.is_valid():
# The "display_type" key is now guaranteed to exist and
# guaranteed to be "displaybox" or "locationbox"
display_type = request.POST["display_type"]
...
# This will display the blank form for a GET request
# or show the errors on a POSTed form that was invalid
return render(request, 'your_template.html', {'form': form})
Checkboxes:
Checkboxes work like this:
forms.py:
class MyForm(forms.Form):
# For BooleanFields, required=False means that Django's validation
# will accept a checked or unchecked value, while required=True
# will validate that the user MUST check the box.
something_truthy = forms.BooleanField(required=False)
views.py:
def my_view(request):
...
form = MyForm(request.POST or None)
if request.method == "POST":
if form.is_valid():
...
if request.POST["something_truthy"]:
# Checkbox was checked
...
Further reading:
https://docs.djangoproject.com/en/1.8/ref/forms/fields/#choicefield
https://docs.djangoproject.com/en/1.8/ref/forms/widgets/#radioselect
https://docs.djangoproject.com/en/1.8/ref/forms/fields/#booleanfield
In models :
class Tag:
published = BooleanField()
(...)
In the template:
{% for tag in tags %}
<label class="checkbox">
<input type="checkbox" name="tag[]" value="" {% if tag.published %}checked{% endif %}>
</label>
{% endfor %}
Assuming you are sending the form as a POST, the values of the selected checkboxes are in request.POST.getlist('tag').
For example :
<input type="checkbox" name="tag[]" value="1" />
<input type="checkbox" name="tag[]" value="2" />
<input type="checkbox" name="tag[]" value="3" />
<input type="checkbox" name="tag[]" value="4" />
Say if 1,4 were checked,
check_values = request.POST.getlist('tag')
check_values will contain [1,4] (those values that were checked)
{% for tag in tags %}
<label class="checkbox">
<input type="checkbox" name="tag[]" value=""
{% if tag.published %}checked{% endif %}>
</label>
{% endfor %}
<input type="checkbox" name="tag[]" value="1" />
<input type="checkbox" name="tag[]" value="2" />
<input type="checkbox" name="tag[]" value="3" />
<input type="checkbox" name="tag[]" value="4" />
Form.is_valid() always returns false. Here's my code.
#urls.py
url(r'^create/', "app.views.createpost", name="createpost"),
My models.py
class Post(models.Model):
"""docstring for Post"""
post_image = AjaxImageField(upload_to='posts', max_width=200, max_height=200, crop=True, null= False, default='site_media/media/BobMarley/bob1.jpg')
poster = models.ForeignKey(User, null= False, default=User.objects.get(username="admin")
Here's my forms.py
#forms.py
class AjaxImageUploadForm(forms.Form):
image = forms.URLField(widget=AjaxImageWidget(upload_to='posts'))
view.py
#views.py
def createpost(request):
if request.method == 'POST':
form = AjaxImageUploadForm(request.POST, request.FILES)
if form.is_valid():
newpost = Post(post_image = request.FILES['image'])
newpost.poster = request.user
newpost.save()
return HttpResponseRedirect('/create/')
else:
form = AjaxImageUploadForm() # An empty, unbound form
posts = Post.objects.all()
return render_to_response('create.html',{'posts': posts, 'form': form},context_instance=RequestContext(request))
The Template
#create.html
{% block extra_head %}
{{ form.media }}
{% endblock %}
{% block body %}
<form method="POST" enctype="multipart/form-data" action="{% url "createpost" %}">
{% csrf_token %}
{{ form.errors}}
{{ form.as_p }}
<button type="submit" name='image'>Upload</button>
</form>
{% endblock %}
The form is never valid and the error printed is "This field is required."
And this is the form widget begin created
<tr><th><label for="id_image">Image:</label></th><td><ul class="errorlist"><li>This field is required.</li></ul>
<div class="ajaximage"><a class="file-link" target="_blank" href=""> <img class="file-img" src=""></a> <a class="file-remove" href="#remove">Remove</a>
<input class="file-path" type="hidden" value="" id="id_image" name="image" /> <input type="file" class="file-input" name="image"/> <input class="file-dest" type="hidden" name="image" value="/ajaximage/upload/posts/0/0/0"> <div class="progress progress-striped active"> <div class="bar"></div></div>
</div>
</td></tr>
I am using the django package called django-ajaximage and their custom widget (AjaxImageWidget) is probably a custom text widget
class AjaxImageWidget(widgets.TextInput):
Thank you for you help
You do not need the init on your model class. Also, null=False is the default. I'm not sure the text 'admin' will default to the user with username admin. You would need to do:
default=User.objects.get(username="admin")
You can also include the poster assignment in the creation of the object like so:
newpost = Post(post_image=request.FILES['image'], poster=request.user)
To make the form validate you need to put blank=True in the field like so:
poster = models.ForeignKey(User, blank=True, default=User.objects.get(username="admin")
I would also make the form be a ModelForm:
class AjaxImageUploadForm(forms.ModelForm):
class Meta:
model=Post
exclude=['poster',]