I'm pretty new in the Web development world, have been using Django so far.
I've been trying to figure out how to render data back to page after clicking on a submit button, so I see I'll need to use AJAX for that purpose.
I've created a very simple app just to understand the basics of AJAX.
However, googling, I couldn't really find a basic straight-forward implementation so I kinda got lost...
What I'm trying to achieve:
I have a model called Country:
class Country(models.Model):
name = models.CharField(primary_key=True, max_length=35)
continent = models.CharField(max_length=10)
capital = models.CharField(max_length=35)
currency = models.CharField(max_length=10)
And a super simple main page that asks the user to insert some country name.
The idea is to bring to the page all the info from the DB.
So it would look like this:
Main page HTML body:
<body>
<h2><em>Please type a country name:</em></h2><br><br>
<div class="container">
<form id="get_info" method="post">
{{ form }}
{% csrf_token %}
<input id="submit_button" type="submit" name="submit" value="Get info">
</form>
</div>
</body>
views.py:
from django.shortcuts import render
from country_trivia import forms
def main_page(request):
get_info_form = forms.GetInfo()
return render(request, 'country_trivia/index.html', {'form': get_info_form})
forms.py:
from django import forms
class GetInfo(forms.Form):
country_name = forms.CharField(label="")
I've seen some examples using forms, but I'm not even sure if it's needed, as I've seen some other examples that count on 'onclick' even listeners, then "grab" the text in the search field and pass it via AJAX...
How should I build my AJAX object for that simple purpose, and how should I integrate it?
Do I need to use forms at all?
I don't post anything to DB, just query it and print out data...
Thanks!!
Related
I am relatively new with Django, this must be a common problem.
I have created a view to show a form to input date (using widget that returns separate fields):
when date is inserted, I call a function userPage(request, my_date)
that filters, processes and renders a page (user.html) showing a list of items.
def datePage(request):
user=request.user
context = {}
context['form'] = UserDateForm()
if request.GET:
date_yr = request.GET['food_date_year']
date_mo = request.GET['food_date_month']
date_day = request.GET['food_date_day']
my_date_string = date_yr+'-'+date_mo+'-'+date_day
my_date = datetime.strptime(my_date_string, "%Y-%m-%d").date()
return userPage(request,my_date)
return render(request, "date.html", context)
def userPage(request, my_date):
user=request.user
# process context using user, my_date
context={...:..., 'my_date': my_date}
return render(request,'user.html',context)
In user.html I include a URL to add an item:
</div>
<form action="{% url 'My_ItemCreate' %}" method="POST">
{%csrf_token%}
<button type="submit" class="btn btn-success">
<span class="glyphicon glyphicon-plus"></span>
</button>
</form>
</div>
'My_ItemCreate' points to a django.views.generic CreateView that creates an item.:
path('MyItemCreate/',views.My_ItemCreate.as_view(),name='My_ItemCreate'),
class My_ItemCreate(CreateView):
model = MyItem
fields = ...
After creating the item in the CreateView, how do I go back to the user page
after I inserted the date? I have lost the date in the new URL.
If I use URL resolver to go to userPage, how do I pass a date in the format?
It would be nice that I am able to pass initial values in the CreateView, and
make some fields read-only, how do I modify/override CreateView ?
Many Thanks for your help!
I have found an answer to my problem: using request.session
to store a value and retrieving in other views, it works fine.
I am still curious to know if there are experts who
would provide a more elegant solution, and if someone
could be so kind to answer point 2) regarding CreateView read_only fields
Thanks
D
I am pulling my hair out trying to add a "like" button in my site´s post app, but as i want to add it in a ListView that contains the rest of the posts entries and everyone has the option to be commented I have added a Formixin to do so, so, now i cannot add another form for the like button as it would mean two posts requests....so I am not finding a clear solution... I have read here and there about using AJAX or Json techs but as im new programing im kind of stuck in it... has anyone any tip to offer?
While using AJAX (javascript XHR requests) would be the proper way so the page doesn't need to be refreshed when just clicking a like button, you can do it without AJAX.
HTML
On the HTML side of things, you can have multiple forms (<form>), one for each post, which have a hidden input field that's the post's id. You have set that explicitly in the HTML template, e.g.
{% for post in post_list %}
<h3>{{ post.title }}</h3>
<p>{{ post.summary }}</p>
<form method="post">
{% csrf_token %}
<input type="hidden" value="{{ post.id }}" name="{{ form.id.html_name }}">
<input type="submit">Like</input>
</form>
{% endfor %}
So basically you're reusing the form multiple times, changing the "value" attribute to match the post.
Django Form
Adding the FormMixin to your view is the right step, just use the form_class to a custom LikeForm with just one field that's an IntegerField called id.
View
By adding the FormMixin you get the form_valid() method, which you'll want to override to save the like:
def form_valid(self, form):
id = form.cleaned_data['id']
try:
post = Post.objects.get(id=id)
except Post.DoesNotExist:
raise Http404
post.likes.add(self.request.user) # assuming likes is a m2m relation to user
return redirect('post_list') # this list view
Hopefully I am not so late, I had similar challenges trying to implement the same functionalities on my website.
I came to realize that each button id should be unique (Preferably the post id if blog), but the classes can be the same.
I was able to solve it. Here is an article I wrote on medium recently on the steps I followed to so get this working you can check it out here
I've created an app, and on the CreateView page, the Submit button works fine to create a new S Reference. I also created an error message if the input value matches an existing Reference. I created button in the error message part and tried to link it to update the page to update these reference fields, like primary contact. I tried many options but have not got right code for the argument with pk or id to get individual record update page.
this is the url in error message.
I tried quite few pk, id options, none of them works.
'pk'=self.pk;
{'pk'=self.pk};
object.id
some code as below
models.py
class LNOrder(models.Model):
reference_number = models.CharField(max_length=15,blank=True, null=True, unique=True, error_messages={'unique':"This reference already exists."})
primary_contact = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True)
urls.py
urlpatterns = [
path('lfcnotifier', LNCreateView.as_view(), name='lnorder_create'),
path('lfcnotifier/<int:pk>', LNDetailView.as_view(), name='lnorder_detail'),
path('lfcnotifier/<int:pk>/update/', LNUpdateView.as_view(), name='lnorder_update'),
]
template
<div class="input-group mb-3">
<div class="input-group-prepend w-225px">
<label class="input-group-text w-100">S Reference</label>
</div>
<input name="reference_number" type="text" class="form-control" placeholder="Enter your S Reference"/>
<button class="btn btn-primary cardshadow " data-toggle="tooltip" title="Click to submit" style="width:200px;" type="submit">submit</button>
{%for field in form %}
{% for error in field.errors %}
{{ error }} Update Request
{% endfor %}
{% endfor %}
Views.py
class LNCreateView(SuccessMessageMixin,LoginRequiredMixin,CreateView):
model = LNOrder
template_name = 'lfcnotifier/lnorder_create.html'
form_class = LNOrderForm
def form_valid(self, form):
form.instance.created_by = self.request.user
return super().form_valid(form)
I expect when users click on Update Request button, it'll open the update page to edit the individual reference.
but I got message "Could not parse the remainder: '=self.pk' from ''pk'=self.pk'".
I get slightly different messages when I try the above different options.
I would like to have the right code for the URL to update the page when the Update Request button is clicked.
Thanks,
Additional background, I only put some of template code here to save space. They are in form section. If I use the following code
Update Request
instead of
Update Request
it can open the full list page without issue. I can go to update page from full list page without issue. But I want to open update page from here directly other than have one more step.
This is all kinds of confused.
For a start, you can't use a string on the left-hand side of an expression, either in pure Python or in Django templates.
But secondly, you don't have anything called self there. What you do have would be passed from the view; however it's not clear from the code you have posted which actual view this is. It doesn't seem to be that CreateView, because you are linking to the update. But assuming it's actually the LNDetailView, and assuming that that actually is a DetailView, you have access to the current object in the template exactly as object.
So you would do:
{% url 'lnorder_update' pk=object.pk %}
However again, this makes no sense to actually do. You can't submit a form via an a. You need a <form> element with a button.
I am trying to create a Django web app that accepts text in a form/textbox, processes it and redirects to a webpage showing the processed text . I have written a half-functioning app and find de-bugging quite challenging because I don't understand most of what I've done. I'm hoping you will help me understand a few concepts, Linking to resources, also appreciated.
Consider this simple model:
class ThanksModel(models.Model):
thanks_text = models.CharField(max_length=200)
Is the only way to set the text of thanks_text through the manage.py shell? This feels like a pain if I just have one piece of text that I want to display. If I want to display a webpage that just says 'hi', do I still need to create a model?
Consider the view and template below:
views.py
class TestView(generic.FormView):
template_name = 'vader/test.html'
form_class = TestForm
success_url = '/thanks/'
test.html
<form action = "{% url 'vader:thanks'%}" method="post">
{% csrf_token %}
{{ form }}
<input type = "submit" value = "Submit">
</form>
I need to create another model, view and html template and update urls.py for '/thanks/' in order for the success_url to redirect correctly? (That's what I've done.) Do I need to use reverse() or reverse_lazy() the success_url in this situation?
Models are used when you are dealing with Objects and Data and DataBases that can contain a lot of information.
For Example A Person would be a model. their attributes would be age, name, nationality etc.
models.py
class Person(models.Model):
Name = models.CharField(max_length=50)
age = models.IntegerField()
nationality = models.CharField(max_length=50)
Thi deals with multiple bits of information for one object. (the object being the person)
A Thank you message would not need this? so scrap the model for the thank you message. just have views where you create the view using a templates and setting the view to a url.
views.py
class TestView(generic.FormView):
template_name = 'vader/test.html' # self explantory
form_class = TestForm # grabs the test form object
success_url = reverse_lazy('vader:thanks') # this makes sure you can use the name of the url instead of the path
def ThanksView(request): # its simple so you don't even need a class base view. a function view will do just fine.
return render(request,"thanks.html")
test.html
<form action = "{% url 'vader:thanks'%}" method="post">
{% csrf_token %}
{{ form }}
<input type = "submit" value = "Submit">
</form>
thanks.html
<h1>Thank you for Submitting</h1>
<h2> Come Again </h2>
url.py
from django.urls import path
from djangoapp5 import views
urlpatterns = [
path('', TestView.as_view(), name='test_form'),
path('thanks/', views.ThanksView, name='vader:thanks'),
]
I haven't tested this but hopefully it helps and guide you in the right direction
Hellow. I have a document database and flask app that gives me web-based opportunity to see the db's docs, add them and delete. Every doc has only it's number and name.
Usually I add the documents one by one, cause i have the WTForm -
class addDocForm(FlaskForm):
doc_name = StringField('Название документа', validators=[DataRequired()])
doc_number = StringField('Исходящий номер', validators=[DataRequired()])
the .html code -
<form action="" method="post" >
{{ form.hidden_tag() }}
<div class="row">
<label>{{ form.doc_name.label }}</label>
{{ form.doc_name(size=32) }}
</div>
<div class="row">
<label>{{ form.doc_number.label }}</label>
{{ form.doc_number(size=32) }}
</div>
<div class="row">
<button type="submit">Добавить</button>
</div>
</form>
and some /route logic -
#app.route('/add_doc', methods=['GET', 'POST'])
#login_required
def add_doc():
form = addDocForm()
if form.validate_on_submit():
doc = Doc(doc_name=form.doc_name)
if Doc.query.filter_by(doc_name=form.doc_name.data).first() == None:
db.session.add(doc)
db.session.commit()
So I add each document one by one filling this form and submitting it again and again. Now i've been tired. I want to save my energy by reducing number of clicking on submit button. Of course it's a joke, but the question is really about thing like this:
how can i add several copies of this 'addDocForm' on one page, fill the fields of these copies and click submit only once?
Is there any clever way to do that? I want to add for example 5-7 docs at once without the necessity to add them one by one. Let's suppose i've load the page with my form (one form) fill the fields, and than clicked '+' button and there appear another form.. fill the fields-> '+' button .. again. After all click the 'submit' button and all the data from filled fields by turns go to the data base. Is it real? any ideas? p.s. i have an idea on how to make it using clear sql + html + js, without flask-wtforms, sqalchemy and so on.. but i guess this is wrong way cause half of my app is already written using them. ) so many text, don't sure if anyone reach this point.. but still - help me, pls (((((
You could construct a MegaForm using field enclosures.
For example (untested):
from wtforms import StringField, FormField, FieldList
class AddDocForm(FlaskForm):
doc_name = StringField('Название документа', validators=[DataRequired()])
doc_number = StringField('Исходящий номер', validators=[DataRequired()])
class MegaForm(FlaskForm):
documents = FieldList(FormField(AddDocForm), min_entries=7, max_entries=7)
#app.route('/add_doc', methods=['GET', 'POST'])
#login_required
def add_doc():
form = AddDocForm()
if form.validate_on_submit():
for idx, data in enumerate(form.documents.data):
doc = Doc(doc_name=data["doc_name"])
if Doc.query.filter_by(doc_name=data["doc_name"]).first() == None:
db.session.add(doc)
db.session.commit()