I'm trying to show forms defined by new_measurement on index.html, but I only manage to get IndexView() to work. I tried various combinations between IndexView() and new_measurement(), but those didn't work out at all. I know that IndexView() doesn't pass anything related to new_measurement(), and new_measurement() isn't called, which is the core of my problem. I'd really appreciate if someone more experienced with Django could tell me what I could, or should do. Thank you.
Here's my views.py:
from django.shortcuts import render
from django.utils import timezone
from .models import Measurement
from .forms import MeasurementForm
from django.views import generic
class IndexView(generic.ListView):
model = Measurement
context_object_name = 'measurement_list'
template_name = 'index.html'
queryset = Measurement.objects.all()
def new_measurement(request):
if request.method == "POST":
form = MeasurementForm(request.POST)
if form.is_valid():
measurement = form.save(commit=False)
measurement.measurement_date = timezone.now()
measurement.save()
else:
form = MeasurementForm()
return render(request, 'index.html', {'form': form})
urls.py:
from django.urls import path
from . import views
urlpatterns = [
path('', views.IndexView.as_view(), name='index'),
]
forms.py:
class MeasurementForm(forms.ModelForm):
class Meta:
model = Measurement
fields = ('measurement_value', 'measurement_unit')
index.html:
{% extends "base.html" %}
{% block content %}
<h1>Climate Measurement Tool</h1>
<h2>Add a new measurement</h2>
<form method="POST" class="post-form">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="save">Add</button>
</form>
<h2>Measurements</h2>
{% if measurement_list %}
<ul>
{% for measurement in measurement_list %}
<li>
<p>{{ measurement }}</p>
</li>
{% endfor %}
</ul>
{% else %}
<p>No measurements yet</p>
{% endif %}
{% endblock %}
You can't map multiple views in one url but you can do mutiple works in one view.
update your views.py as you can see that I am sending (querylist and form) both in that view
views.py
def new_measurement(request):
if request.method == "POST":
form = MeasurementForm(request.POST)
if form.is_valid():
measurement = form.save(commit=False)
measurement.measurement_date = timezone.now()
measurement.save()
else:
form = MeasurementForm()
qs = Measurement.objects.all()
context = {'form': form, 'measurement_list': qs}
return render(request, 'index.html', context)
update urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.new_measurement, name='index'),
]
You can't call 2 views for one url. basically each url has to be linked to one view and that's something you can't really change.
But if you want your code to be cleaner and have multiple functions, you can call them in your view, basically what you can do is to make a view and call it when a url or even more than one url has been used and in that view decide which function to use
Example:
def god_view(request):
if request.method == "POST"
return post_func(request)
return get_func(request)
This is a very simple example but you can do so many other things.
It is not possible to have more views in one url, but you can simulate it. I did it like a view and in the template of this view was javascript which loaded the second view with the response of AJAX and filled the belonging element with the second view's content. The second view was not whole template but it started with some div tags which were placed into the first template. I'll try to give you an example
views
def first_view(request):
return render(
request,
'first_template.html',
{
'first_content': 'Some heavy content'
})
def second_view(request):
return render(
request,
'second_template.html',
{
'second_content': 'Some heavier content!'
})
first_template.html
...
<body>
<div id="1">
{{ first_content }}
</div>
<div>
... loading ...
</div>
<script>
window.onload = function() {
$.ajax({
url: {% url 'to_second_view' %},
method: 'GET',
success: function(response) {
$('#2').html(response);
}
})
}
</script>
</body>
...
second_template.html
<div>
{{ second_content }}
</div>
If you're using cbv you can override the get_template_names method for any view that inherits TemplateResponseMixin and return a list of string which are searched in order until one matches or ImporperlyConfigured is raised. For example:
class SomeView(TemplateResponseMixin):
...
def get_template_names(self):
if self.request.method == "POST":
return ['post_template.html']
else:
return ['template.html']
Instead of generic.ListView you can try with rest_framework.views.APIView
from rest_framework.views import APIView
class IndexView(APIView):
def post(self, request: Request):
form = MeasurementForm(request.POST)
if form.is_valid():
measurement = form.save(commit=False)
measurement.measurement_date = timezone.now()
measurement.save()
return render(request, 'index.html', {'form': form})
def get(self, request: Request):
form = MeasurementForm()
return render(request, 'index.html', {'form': form})
This gives you more control on the APIs you call. Also you can raise/return error when you call your API using incorrect methods (PUT, PATCH)
Related
I am not sure if I am going about this correctly, but I am not getting any errors it just reloads the page without displaying anything.
The issue could be with me trying to format the api string and input the users input there?
I also tried returning the variable as an HttpResponse, still made no difference.
Sorry just getting back into python, and just starting with Django.
Correct code should go something like this:
1.User inputs their name into the form
2. Page then displays the usersid.
Code:
views.py:
from urllib import response
from django.shortcuts import render
from django.http import HttpResponse
import requests
from .forms import SearchUser
import json
# Create your views here.
def home(response):
# data = requests.get(
# 'https://americas.api.riotgames.com/riot/account/v1/accounts/by-riot-id/ReallyBlue/NA1?api_key=RGAPI-6c5d9a2c-3341-4b0c-a0a5-7eafe46e54cf')
# userid = data.json()['puuid']
return render(response, "main/home.html", {
'form': SearchUser(), # include reference to your form
'userid': search,
# 'mmr':NA,
})
def search(response):
if response.method == "POST":
form = SearchUser(response.POST)
if form.is_valid():
n = form.cleaned_data["name"]
user = n(name=n)
user.save()
data = requests.get(
f"https://americas.api.riotgames.com/riot/account/v1/accounts/by-riot-id/'{user}'/NA1?api_key=RGAPI-6c5d9a2c-3341-4b0c-a0a5-7eafe46e54cf")
userid = data.json()['puuid']
return HttpResponse(userid)
else:
form = SearchUser()
return render(response, "main/home.html", {"userid": userid})
forms.py:
from django import forms
class SearchUser(forms.Form):
name = forms.CharField(label="Name", max_length=200)
urls.py:
from django.urls import path
from . import views
urlpatterns = [
path("", views.home, name=""),
path("", views.search, name=""),
]
home.html:
{% extends 'main/base.html'%}
{% block content %}
<h2>Valorant Ranked Checker</h2>
<form method="post" action="">
{% csrf_token %}
{{form}}
<button type="submit" name="search">
Get rank
</button>
</form>
<p><strong>{{userid}} - {{mmr}}</strong></p>
{% endblock %}
base.html:
<!DOCTYPE html>
<head>
<title>Blue's Valorant Ranked Checker</title>
</head>
<body>
<div id="content" name="content">
{% block content %}
{% endblock %}
</div>
</body>
</html>
So what you have to do is, use a single view for the url and then do the API querying inside that view. So something like:
urlpatterns = [
path("", views.search, name=""),
]
and then inside your view, you need to send the form with the context dictionary to show it in the HTML.
def search(response):
if response.method == "POST":
form = SearchUser(response.POST)
if form.is_valid():
name = form.cleaned_data["name"]
data = requests.get(
f"https://americas.api.riotgames.com/riot/account/v1/accounts/by-riot-id/{user}/NA1?api_key=*******")
userid = data.json()['puuid']
return HttpResponse(userid) # Or preferably pass onto a different view
else:
return HttpResponse("Form is not properly filled")
else:
form = SearchUser()
return render(response, "main/home.html", {"form": form})
I want to display to simple search Forms in a view.
forms.py:
from django import forms
from django.utils.translation import gettext_lazy as _
class Vehicle_Search_by_VIN(forms.Form):
vin = models.CharField(max_length=17)
first_registration_date = models.DateField()
class Vehicle_Search_by_Plate(forms.Form):
plate = models.CharField(max_length=7)
last_four_diggits_of_vin = models.DateField(max_length=4)
views.py:
from django.shortcuts import render
from django.views import View
from .forms import *
class VehicleSearch(View):
template = 'vehicle_search_template.html'
cxt = {
'Search_by_VIN': Vehicle_Search_by_VIN(),
'Search_by_Plate': Vehicle_Search_by_Plate()
}
def get(self, request):
return render(request, self.template, self.cxt)
my template-file:
<form class="by_vin" method="POST" action="">
{% csrf_token %}
{{ Search_by_VIN.as_p }}
<button name='action' value='login' type="submit">Suchen</button>
</form>
<form class="by_plate" method="POST" action="">
{% csrf_token %}
{{ Search_by_Plate.as_p }}
<button name='action' value='signup' type="submit">Suchen</button>
</form>
But as a result only the submit buttons are displayed in the view. Does anybody know why my forms aren't being rendered?
in views.py, i think, you are missing *args and **kwargs parameters in get() function
class VehicleSearch(View):
template = 'vehicle_search_template.html'
cxt = {
'Search_by_VIN': Vehicle_Search_by_VIN(),
'Search_by_Plate': Vehicle_Search_by_Plate()
}
def get(self, request, *args, **kwargs): # HERE
return render(request, self.template, self.cxt)
Update
By default, class-based views does only support a single form per view but you can counter this limitation with few options depending on your logic. refer to this thread Django: Can class-based views accept two forms at a time?
try to give full path in your template variable for e.g. if your app name is my_app then template = 'my app/vehicle_search_template.html'
I am creating a site which allows users to post comments and like posts. I have created a view function which allows a user to like posts but am not sure how to implement ajax or a similar technique to perform the request without reloading the page. So that the user doesn't lose where they were on the page and have to scroll down to find it after liking a post.
In my views.py:
#this is the function i wish to run without reloading
def like(request, operation, id):
like = Post.objects.get(id=id)
if operation == 'add':
Like.make_like(request.user, like)
elif operation == 'remove':
Like.lose_like(request.user, like)
return HttpResponseRedirect('/Feed/')
#this is the view in which it is called
class FeedView(TemplateView):
template_name = 'feed.html'
def get(self, request):
form = HomeForm()
posts = Post.objects.all().order_by('-created')
users = User.objects.exclude(id=request.user.id)
try:
like = Like.objects.get(user=request.user)
likes = like.posts.all()
except Like.DoesNotExist:
like = None
likes = None
args = {
'form': form, 'posts': posts, 'users': users, 'likes': likes
}
return render(request, self.template_name, args)
def post(self, request):
form = HomeForm(request.POST)
if form.is_valid():
post = form.save(commit=False)
post.user = request.user
post.save()
text = form.cleaned_data['post']
form = HomeForm()
return HttpResponseRedirect('/Feed/')
args = {'form': form, 'text': text}
return render(request, self.template_name, args)
feed.html:
{% for post in posts %}
<p class="name">{{ post.user.username }}</p>
<h3>{{ post.post }}</h3>
{% if not post in likes %}
<li-r><a class="like" href="{% url 'like' operation='add' id=post.id %}"> {{ post.total_likes }} </a></li-r>
{% endif %}
{% if post in likes %}
<li-r><a class="unlike" href="{% url 'like' operation='remove' id=post.id %}"> {{ post.total_likes }} </a></li-r>
{% endif %}
<p class="date">{{ post.created }}</p>
{% endfor %}
urls.py:
urlpatterns = [
url(r'^Feed/$', FeedView.as_view(), name='feed'),
url(r'^like/(?P<operation>.+)/(?P<id>\d+)/$', views.like, name='like')
]
I have tried putting the function inside of the Feed class but I don't know how to write the url to include the class along with the "(?P<operation>.+)/(?P<id>\d+)" section or even if that would solve my problem. But I think I can use ajax though i have no idea how.
You need to use Ajax here. Use onclick event listener on the anchor tags for like/dislike, make an ajax call instead and update the count based on the response.
$('.like, .unlike').click(function(e){
e.preventDefault();
var url = $(this).attr('href'));
// make a get call on this url, and update the total_likes based on response
$.get(url, function( data ) {
$(this).text(data.total_likes); //something like that
});
});
I'm trying to fix this problem... I made a simple post form with forms.py but it doesn't show up at the HTML file. I searched at google but I still don't know how to fix it
views.py
from django.shortcuts import render
from contact.forms import contactForm
def contact(request):
form = contactForm(request.POST)
if form.is_valid():
return request.POST
context = locals()
template = 'contact.html'
return render(request, 'contact/contact.html')
contact.html
{% block content %}
<h1>
Contact doesn't appears..
</h1>
<form method = "POST">{% csrf_token %}
{{ form.as_p }}
<input type = "submit" value = "submit form" class = 'btn btn-default' />
</form>
{% endblock %}
forms.py
from django import forms
from django.shortcuts import render
class contactForm(forms.Form):
name = forms.CharField(required = False, max_length = 100, help_text='100 characters max.')
email = forms.EmailField(required = True)
comment = forms.CharField(required = True, widget = forms.Textarea)
You need to pass in the objects you want in the render function.
def contact(request):
...
context = {'form': form}
return render(request, 'news/year_archive.html', context)
As you can see you are passing the dictionary labeled context inside the render which should now be able to be accessed by your template.
Django view example
I'm new to django and trying to create my first app and I think I might need some little help :)
I have a ModelForm on a site to submit and want to show the data on the same page. I'm having trouble to set up two functions on the same page, I think i might have to use a class and set it in urls.py but I'm not able to make it work :( the code looks like this:
forms.py:
from django import forms
from .models import Eintrag
class NameForm(forms.ModelForm):
class Meta:
model = Eintrag
fields = ['Anmeldung', 'Essen']
urls.py
from django.urls import path
from . import views
app_name = 'form'
urlpatterns = [
path('', views.get_name, name='form'),
]
views.py
from django.shortcuts import render
from django.utils import timezone
from django.contrib.auth.decorators import login_required
from .forms import NameForm
from .models import Eintrag
#login_required()
def get_name(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = NameForm(request.POST)
# check whether it's valid:
if form.is_valid():
eintrag = form.save(commit=False)
# process the data in form.cleaned_data as required
# ...
# redirect to a new URL:
eintrag.Name = request.user # Set the user object here
eintrag.pub_date = timezone.now() # Set the user object here
eintrag.save()
return render(request, 'form/name.html', {'form': form})
# if a GET (or any other method) we'll create a blank form
else:
form = NameForm()
return render(request, 'form/name.html', {'form': form})
def post_list(request):
posts = Eintrag.objects.all()
return render('form/post_list.html', {'posts': posts})
name.html
...
{% include "form/post_list.html" %}
<form action="/form/" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit" />
</form>
...
post_list.html
{% for post in posts %}
{{ post }}
{% endfor %}
So the problem is in urls.py only get_name is handled and I'm clueless how I should include post_list. I rather not want to use different url's, do I have to?
Thanks for any help and advice!
You don't need a separate URL or view for the list. Just include the queryset in the context of your get_name view.
posts = Eintrag.objects.all()
return render(request, 'form/name.html', {'form': form, 'posts': posts})
with [Class Based View] it would be better.
But with your view, you can send multiple data via context.
#login_required()
def get_name(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
''' codes '''
eintrag.save()
return HttpResponseRedirect(request.path) # generate an empty form
# if a GET (or any other method) we'll create a blank form
else:
form = NameForm()
posts = Eintrag.objects.all() # the queryset is here, and sent via context
return render(request, 'form/name.html', {'form': form,'posts':posts})
I your html remain the same, but keep your form action='' empty
{% include "form/post_list.html" %}
<form action="" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit" />
</form>