Editing the form in Django - django

I have created a form in my app where I can take details of a suer. Now I want to create a form which can allow me to edit a form.
My urls.py:
url(r'^home/editform/(?P<userpk>[^/]+)/$', 'lexuseditform', name='lexuseditform'),)
My view.py:
#login_required
def lexuseditform(request,userpk):
if int(userpk) != request.user.pk:
return HttpResponseForbidden()
else:
form = AdultForm()
if request.method == 'POST': # If the form has been submitted...
form = AdultForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
form.save()
redirect_url = reverse('lexus/lexusedited.html')
return HttpResponseRedirect(redirect_url) # Redirect after POST
else:
form = AdultForm() # An unbound form
return render('lexus/lexuseditform.html', {'form': form})
My models.py:
class AdultForm(ModelForm):
"""
Edit Profile Information
"""
class Meta:
model = Adult
fields = ('user', 'email','fullname','created')
But i am getting an error msg:
No ReverseMatch: Reverse for 'lexuseditform' with arguments '()' and keyword arguments '{}' not found
Can't seem to solve this error. Need some help...

In you POST handling, reverse should be passed URL name not the pattern. So correct it whatever name you have given to that url.
redirect_url = reverse('lexus/lexusedited.html') <----- Incorrect.
If your urlname is 'lexusedited'
redirect_url = reverse('lexusedited')
Tip: you can directly do:
return HttpResponseRedirect(reverse('lexusedited'))

Related

Do I really need to accommodate both GET and POST request formats in a django form?

I'm new to django but something I don't understand is the need for accommodating both the GET and POST request types when developing a form. Please refer to code below from django docs:
from .forms import NameForm
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():
# process the data in form.cleaned_data as required
# ...
# redirect to a new URL:
return HttpResponseRedirect('/thanks/')
# if a GET (or any other method) we'll create a blank form
else:
form = NameForm()
return render(request, 'name.html', {'form': form})
The reason this confuses me is because I have developed a GET based form and it is working and I have no need for the POST portion above? See below:
# views.py
def simplifier_form(request):
form = LabelForm()
return render(request, "simplifier.html", {"form": form})
def process_simplifier(request):
label_name = request.GET.get('labels')
results = Disturbance.objects.filter(labeldisturbances__label_name=label_name)
painsresults = Pain.objects.filter(disturbances__pk__in=results).distinct()
total_disturbances = Disturbance.objects.filter(pain__pk__in=painsresults)
total_labels = Label.objects.filter(disturbances__pk__in=total_disturbances).distinct()
context = {'results': results, 'painsresults': painsresults, 'total_disturbances': total_disturbances, 'total_labels': total_labels}
return render(request,'process_simplifier.html', context)
# forms.py
class LabelForm(ModelForm):
labels = forms.ModelChoiceField(
queryset=Label.objects.all(),
to_field_name='label_name',
widget=forms.Select(attrs={'class': 'labels'}),
)
class Meta:
model = Label
fields = ['labels']
So why do the django docs and most examples include code for both methods when you only really use one like in my example above?
The question is... How do you want to process your from when submitted on POST?
Remember, your form can also be submitted on GET... You can decide what you would want to do if submitted on GET.

Views are different but rendering same template

i want to use slug field in both url which is
path('<slug:title>/',views.news_read,name="news_read"),
path('<slug:title>/',views.movie_read,name="movie_read"),
but both the url picking same template instead of their template i am trying to create blog site
i don't understand both the url are uniques so why django is picking wrong template
my views for both the url
def movie_read(request, title):
movie = Movie.objects.filter(urltitle=title)
if request.method == 'POST':
form = Commentform(request.POST)
if form.is_valid():
form.save()
messages.success(request, 'Thank You For Your Comment')
else:
form = Commentform()
return render(request,'movie_read.html',{'movie':movie,'form':form})
def news_read(request, title):
news = News.objects.filter(urltitle=title)
if request.method == 'POST':
form = Commentform(request.POST)
if form.is_valid():
form.save()
messages.success(request, 'Thank You For Your Comment')
else:
form = Commentform()
return render(request,'news_read.html',{'news':news,'form':form})
but i when do some change like this it work
path('<slug:title>/news',views.news_read,name="news_read"),
path('<slug:title>/movie',views.movie_read,name="movie_read"),
but this doesn't look good any idea what to do solve the issue
Django will "fire" the first path that matches the URL. This thus means that for every slug you enter, news_read will fire.
You can solve this by trying to query both models, and then decide which to use, like:
def my_view(request, title):
is_movie = Movie.objects.filter(urltitle=title).exists()
if is_movie:
return movie_read(request, title)
else:
return news_read(request, title)
def movie_read(request, title):
# …
def news_read(request, title):
# …
and then thus trigger the my_view function if it is a slug:
path('<slug:title>/', views.my_view, name='news-movie-read'),
but a more elegant solution is to simply define two non-overlapping URL patterns:
path('news/<slug:title>/', views.news_read,name='news_read'),
path('movie/<slug:title>/', views.movie_read,name='movie_read'),
This also will prevent clashes where a Movie object and a News object have both the same url_title since in that case, it will always use the movie_read view.
I seems that tou url path is the same, that is why django picking wrong view.
Try to change urls to this:
path('news/slug:title/',views.news_read,name="news_read"),
path('movies/slug:title/',views.movie_read,name="movie_read"),

Django returning None instead of a HTTP response

OK im probably doing this all wrong!
I am trying to run a function in a view which calls another view.
This seems to pass my request into the next function as a POST method before loading the form from the second function.
my views.py
''' This section of hte code seems to function correctly '''
#login_required()
def joinLeague(request):
if request.method == 'POST':
league = JoinLeagueQueue(user=request.user)
form = JoinLeagueForm(instance=league, data=request.POST)
if form.is_valid():
form.save()
context = int(league.id) # displays id of model, JoinLeagueQueue
return HttpResponseRedirect(confirmLeague(request, context))
else:
form = JoinLeagueForm()
context = {'form':form}
return render(request, 'userteams/joinleagueform.html', context)
This section of the views file is not working correctly.
it seems to run the POST request without displaying the GET request with the form first.
#login_required()
def confirmLeague(request, league):
# gets ID of application to join league
joinleagueid=JoinLeagueQueue.objects.get(id=league)
pin = joinleagueid.pin # gets pin from application
user = joinleagueid.user # get user from application
leagueinquestion=League.objects.get(leaguePin=pin) # gets the league record for applied league
manager=leagueinquestion.leagueManager # Gets the league manager for league applied for
leaguename=leagueinquestion.leagueName # Gets the league name for league applied for
if request.method == 'POST':
if 'accept' in request.POST:
LeaguesJoinedTo.objects.create(
leaguePin = pin,
playerjoined = user,
)
return redirect('punterDashboard')# user homepage
else:
print("Error in POST request")
else:
context = {'leaguename':leaguename, 'pin':pin, 'manager':manager}
return render(request, 'userteams/confirmleague.html', context)
I now get an error saying Page not found (404)
Request Method: GET
Request URL: http://127.0.0.1:8000/userteams/None
Using the URLconf defined in fanfoo_proj.urls, Django tried these URL patterns, in this order:
... im skipping a list of the patterns.
10. userteams/ confirmLeague [name='confirmLeague']
Ok i think the better way would be a HttpRedirect to the second view:
return confirmLeague(request, context)
should change to something like:
return redirect(confirmLeague,args=league)
django doc to urlresolvers: https://docs.djangoproject.com/en/3.0/topics/http/shortcuts/#redirect
def joinLeague(request):
if request.method == 'POST':
league = JoinLeagueQueue(user=request.user)
form = JoinLeagueForm(instance=league, data=request.POST)
if form.is_valid():
form.save()
context = league.id
return HttpResponseRedirect( reverse("your_confirmLeague_url",kwargs={'league':context}) )
else:
form = JoinLeagueForm()
context = {'form':form}
return render(request, 'userteams/joinleagueform.html', context)
def confirmLeague(request, league):
league = get_object_or_404(JoinLeagueQueue, pk=league)
pin = league.pin
if request.method == 'POST':
if 'accept' in request.POST: # This refers to the action from my form which is waiting for a button press in a html form.
LeaguesJoinedTo.objects.create(
leaguePin = pin,
playerjoined = request.user.id,
)
return redirect('punterDashboard')
else:
context = {'league':league}
return render(request, 'userteams/confirmleague.html', context)

Create, get and edit user information in same form and template

I'm trying to retrieve data from user. The form where i want to show the user information is also the same that i use to update this information.
Update3
After some updates I make this work and this is my code. If somenone have a better way to do this can share it :)
models.py
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class informacionFacturacion(models.Model):
usuario = models.ForeignKey(User, on_delete=models.CASCADE)
apellidos = models.CharField(max_length=100)
nombres = models.CharField(max_length=100)
[More fields...]
def __str__(self):
self.apellidos
forms.py
from .models import informacionFacturacion
#Create your forms here.
class informacionFacturacionForm(ModelForm):
class Meta:
model = informacionFacturacion
fields = [
"usuario",
"apellidos",
"nombres",
[More fields...]
]
views.py
#login_required
def datosPersonales(request):
#Filter query by user ID
query = informacionFacturacion.objects.filter(usuario=request.user)
form = informacionFacturacionForm()
#If query has content, edit record, else, create a new record
if query:
if request.method == "POST":
form = informacionFacturacionForm(request.POST or None, instance=query[0])
if form.is_valid():
edit_content = form.save()
edit_content.save()
else:
if request.method == "POST":
form = informacionFacturacionForm(request.POST)
if form.is_valid():
create_content = form.save(commit=False)
create_content.save()
return HttpResponseRedirect(reverse('datosPersonales'))
context = {
"titulo": "Datos personales | Co.",
"body_class": "class= sidebar_main_open sidebar_main_swipe",
"form": form,
"infoFacturacion": query,
}
template = "micuenta/datosPersonales.html"
return render(request, template, context)
Thanks for the support.
At first glance, it seems that the informacionFacturacion table is not being populated. Have you checked that the instance.save() is reached? (in other words, that the form is valid)
Second, in the template you want to use the informacionFacturacion object as the form elements, and you are handling them separately. Do:
if request.POST:
form = informacionFacturacionForm(request.POST)
if form.is_valid():
instance = form.save(commit=False)
instance.save()
else:
# handle here the form error's, maybe report it in the template
else:
query = informacionFacturacion.objects.filter(usuario=request.user)
form = informacionFacturacionForm(instance=query[0])
and render the form parameter insead of infoFacturacion:
{{ form.as_p }}
finally, make sure that your template form id's matches the form element names, otherwise the form won't be filled.
UPDATE
Based on your edit, now the error is in this line:
form = informacionFacturacionForm(request.POST, instance=query_id)
query_id is an int, and it is expecting a model. Change the following line:
query_id = informacionFacturacion.objects.get(usuario=request.user).id
to
query = informacionFacturacion.objects.get(usuario=request.user)
and the faulty line to:
form = informacionFacturacionForm(request.POST, instance=query)
that should work for now, although code can be simplified a lot.
EDIT 2
Here is what I assume you want:
#login_required
def datosPersonales(request):
query = informacionFacturacion.objects.filter(usuario=request.user)
if request.method == "POST": # This will handle the template form's POST
form = informacionFacturacionForm(request.POST)
if form.is_valid():
asd = form.save(commit=False)
asd.save()
# Here you may want to redirect to somewhere else
# Im not sure here, I guess that you want to handle the GET method if
# there is no form in the request. Post your template form to see what
# is happening.
else:
form = informacionFacturacionForm(instance=query)
# you dont need to save it, it is already in DB
context = {
"titulo": "Datos personales | Co.",
"body_class": "class= sidebar_main_open sidebar_main_swipe",
# I think here is your main issue, you are handling a form object
# AND a infoFacturacion object. You need to use just the
# form object in the template and render it accordingly.
"form": form,
"infoFacturacion": query,
}
template = "micuenta/datosPersonales.html"
return render(request, template, context)
Well, I was with the same problem on my sytem, so I made this solution, maybe it works to you! =D
I'm changing the value of the submit button and using the same form:
<button type="submit" id="submitButton" name="button" value="">Save</button>
If is a new task, I change the value of the button with JQuery:
$('#submitButton').val('new');
And if is an edition, I change the value again:
$('#submitButton').val('edit');
On my views.py, I check if is an edit or a new save by the value of the button:
def index(request):
tasks = Task.object.filter()
context = {
'tasks': tasks
}
if request.method == 'POST':
form = NewTask(request.POST or None)
if request.POST['button'] == 'new':
if form.is_valid():
context['is_valid'] = True
form.save()
form = NewTask()
else:
context['is_valid'] = False
if request.POST['button'] == 'edit':
instance = Task.object.filter(pk=request.POST['id']).first()
form = NewTask(request.POST, instance=instance)
if form.is_valid():
context['is_valid'] = True
form.save()
else:
context['is_valid'] = False
else:
form = NewTask()
context['form'] = form
return render(request, 'index.html', context)

What URL patterns should I have for a multi-page signup form (using Django)?

First Post, so forgive any noob-iness -- I'm trying to create a multi-page product sign-up form. I can get the form to display and the submit button, but I can't find any examples of URL patterns for my urls.py file. I found another similar question with the following suggestions:
"You need to write a view to handle your request.(did that) You need to edit urls.py to map your quiz url to the function in views.py (trying, but failing). So when a request with that quiz url comes Django applies that view function.
When I Redirect the user to the new url is the problem. I can't seem to find an example of what the next pattern should be. Here's my urls.py code (index.html and details.html are my templates so far):
url(r'^signup/$', 'signup.views.select_product', name='select_product'),
url(r'^signup/(?P<product_id>\d+)/$', 'signup.views.subscriber_signup', name='subscriber_signup'),
#...
Here's my view code:
def select_product(request):
title = "get yourself an e-edition. wurd."
pform = ProductForm(request.POST)
if request.method == 'POST': # If the form has been submitted...
pform = ProductForm(request.POST) # A form bound to the POST data
if pform.is_valid(): # All validation rules pass
# Process the data in form.cleaned_data
# ...
return HttpResponseRedirect('signup/index.html') # Redirect after POST
else:
form = ProductForm() # An unbound form
return render_to_response('signup/index.html', {'title': title, 'pform': pform}, context_instance=RequestContext(request))
def subscriber_signup(request, product_id):
signup = Product.objects.get(id=product_id)
title = "get yourself an e-edition. wurd."
sform = SubscriberForm(request.POST)
if request.method == 'POST': # If the form has been submitted...
sform = SubscriberForm(request.POST) # A form bound to the POST data
if sform.is_valid(): # All validation rules pass
# Process the data in form.cleaned_data
# ...
return HttpResponseRedirect('signup/detail.html') # Redirect after POST
else:
sform = SubscriberForm() # An unbound form
return render_to_response('signup/detail.html', {'title': title, 'sform': sform, 'signup': signup,}, context_instance=RequestContext(request))
Or use Django's form wizard which was designed for this.
so part of the problem was I was using the (User) model in my Subscriber class, which the SubscriberForm was based. I ditched that and made a form based on a normal class with the objects defined individually.
Here's the URL patterns that eventually worked.
url(r'^signup/$', 'signup.views.select_product', name='select_product'),
url(r'^signup/(?P<product_id>\d+)/$', 'signup.views.subscriber_signup', name='subscriber_signup'),
url(r'^signup/(?P<product_id>\d+)/thankyou/$', 'signup.views.thankyou', name='thankyou'),
thanks for the responses.
Anthony