The users are able to create an aircraft post at this url:
url(r'^upload/aircraft/$', aircraft_create, name="aircraft_create"),
I've created a summary page where all of the users posts are displayed. They're able to edit and delete their posts here. The url:
url(r'^account/uploads/$', upload_overview, name="account_uploads"),
However, I want the user to be able to edit their posts on their summary page. The way I got it set it now, is that they can edit at upload/aircraft/edit, but I want to to be account/uploads/edit.
I've set it up like that but it's not doing anything? Any clues as to what it might be?
Aircraft/views.py
def aircraft_create(request):
form = aircraft_form(request.POST or None)
if form.is_valid():
instance = form.save(commit=False)
instance.user = request.user
instance.save()
messages.success(request, "Your upload has been successfully added!")
return HttpResponseRedirect(instance.get_absolute_url())
else:
messages.error(request, "There seems to be something wrong. Have a look again..!")
context = {"form":form,}
return render(request,'aircraft/aircraft_form.html', context)
Update view
def aircraft_update(request, id=None):
aircraft = get_object_or_404(Aircraft, id=id)
form = aircraft_form(request.POST or None, instance=aircraft)
if form.is_valid():
form.save()
messages.success(request, "Your edit has been successfully been saved!")
return HttpResponseRedirect(aircraft.get_absolute_url())
return render(request,'aircraft/aircraft_form.html',
{"aircraft": aircraft, "form": form})
Template
{% if UploadedAircraft %}
{% for upload in UploadedAircraft %}
<div class="col-lg-offset-0 col-md-4 col-sm-3 item">
<div class="box"><img src="{{ upload.image.url }}" width="200px" height="200px" alt="{{ upload.title }}"/>
<h3 class="name">{{ upload.name }}</h3>
<button class="btn">Edit</button>
<button class="btn">Delete</button>
</div>
Summary page view
def upload_overview(request):
uploaded_aircraft = Aircraft.objects.filter(user=request.user)
return render(request,'account/upload_overview.html',{'UploadedAircraft':uploaded_aircraft)
url.py
#aircraft/detail/1
url('^aircraft/detail/(?P<id>\d+)/$', aircraft_detail, name='aircraft_detail'),
#account/uploads (Display Users uploads)
url(r'^account/uploads/$', upload_overview, name="account_uploads"),
#upload/aircraft (Create Aircraft)
url(r'^upload/aircraft/$', aircraft_create, name="aircraft_create"),
#Edit/aircraft
url('^account/uploads/$', aircraft_update, name='aircraft_update'),
EDIT
def airline_update(request, id=None):
airline = get_object_or_404(Airline, id=id)
form = airline_form(request.POST or None, instance=airline)
if form.is_valid():
form.save()
return HttpResponseRedirect(airline.get_absolute_url())
return render(request,'airline/airline_form.html',
{"airline": airline, "form": form})
Url
#account/upload/edit/ (Edit airline)
url(r'^account/uploads/edit/(?P<id>[0-9]+)$', airline_update, name='airline_update'),
Template
<button class="btn">Edit</button>
Assuming you're trying to edit an aircraft with a specific ID, you would need something like this in url.py (assuming that the IDs are integers):
url('^account/uploads/edit/(?P<id>[0-9]+)$', aircraft_update, name='aircraft_update')
And in your template you would need to update your anchor link to include the ID:
<a href="{% url 'aircraft_update' id=upload.id %}">
NOTE that this assumes that the upload object (in your template's loop) includes an id property, and that the id property corresponds to the aircraft ID that you want to update. (It is possible that you have named this property something else.)
EDIT: This would be sufficient for executing a GET request. However, I notice that your view definition for aircraft_update also attempts to check whether a form is valid. Where is this form in your template? It does not appear to be in your loop.
Related
I have a functioning dropdown menu filled with some objects from a database. When a user selects one, they should be directed to the objects appropriate page. Each object is a "Workout" and each workout has "Exercises". It is working, however, I am struggling to get the appropriate 'id' from the object that has been selected by the user. Below I will provide the view, template, url, and form.
view.py
#login_required
def routines(request):
"""This view will provide a dropdown list of all of the workouts of a specific user.
Once one is selected, the user will hit a submit button.
After submitted, a new page will show all the exercises for that workout"""
if request.method == "GET":
#if we have a GET response, provide a form with filled data
form = RoutineForm(request.GET, user=request.user)
#data needs to equal the object that was selected from the GET form
data = 1
if form.is_valid():
data=form.cleaned_data("workout")
form.instance.owner = request.user #make sure we have the right user
form.save()
return HttpResponseRedirect('routine_workouts_app:routines')
context = {'form':form, 'data':data}
return render(request, 'routine_workouts_app/routines.html', context)
#login_required
def routine(request, data):
"""I think this is the view that will display the information of a workout as of now.
Should be similar to the workout view."""
a_workout = Workout.objects.get(id=data)
#Make sure the topic belongs to the current user
if a_workout.owner != request.user:
raise Http404
exercises = a_workout.exercise_set.order_by('exercise_name')
context = {'a_workout': a_workout, 'exercises':exercises}
return render(request, 'routine_workouts_app/routine.html', context)
routines.html
<form action="{% url 'routine_workouts_app:routine' data %}" method="get">
{% csrf_token %}
{{ form.as_p }}
<button name="submit">Make Workout</button>
</form>
urls
path('routines/', views.routines, name='routines'), #this one deals with selecting a workout and submitting a form
#via routine/ shows the specific workout. just like workouts/int
path('routines/<int:data>/', views.routine, name='routine'), #this one displays the information based on the form
and the forms.py
class RoutineForm(forms.ModelForm):
"""This creates a form to work for Routine making"""
def __init__(self, *args, user=None, **kwargs): #this code helps to manage ownership of workouts.
super().__init__(*args, **kwargs)
self.fields['workout'].queryset = Workout.objects.filter(owner=user)
#info comes from the Routine model. Only field is 'workout' and labels is how we are going to identify the field on the webpage
class Meta:
model = Routine
fields = ['workout']
labels = {'workout': 'Workout'}
Basically, I would like to have data equal to the object that the user has selected in my routines function in views.py. From there, I can obtain the objects ID and direct the user to the right page. As of now, no matter when the use picks, they will be directed to the "Workout" with the ID of 1 (hence, why it is functioning but not to my desire).
I appreciate the help in advance. Also, may anyone recommend any textbooks that help improve Django skills such as this?
picture for reference:
You can use the redirect shortcut to make a redirection to a named url with arguments after validating the form. The argument are the workout id, which is stored in the routine instance created by the form.
<form action="{% url 'routine_workouts_app:routines' %}" method="get">
{% csrf_token %}
{{ form.as_p }}
<button name="submit">Make Workout</button>
</form>
from django.shortcuts import redirect
#login_required
def routines(request):
form = form = RoutineForm(request.GET or None, user=request.user)
if form.is_valid():
# workout_instance = form.cleaned_data("workout")
routine_instance = form.save(commit=False)
routine_instance.owner = request.user # make sure we have the right user
routine_instance.save()
return redirect('routine_workouts_app:routine', args=(routine_instance.workout.pk,))
context = {'form': form}
return render(request, 'routine_workouts_app/routines.html', context)
I have a very basic Django view:
def myview(request):
if request.method == 'POST':
if 'button1' in request.POST:
form1 = form = myForm(request.POST)
# check whether it's valid:
if form.is_valid():
profile = form.save()
profile.user = request.user
profile.save()
messages.success(request, f"Success")
return HttpResponseRedirect(request.path_info)
else:
form = myForm()
return render(request,
"main/mytemplate.html",
context={"form":form})
And its template:
<form method="post" novalidate>
{% csrf_token %}
{% include 'main/includes/bs4_form.html' with form=form %}
<button name="button1" type="submit" class="btn btn-primary">SUBMIT</button>
</form>
Everything works here, when this form is used, some data is saved on my DB. What i would like to change, though, is the page reload after the form is used.
When the Submit button is hit, the page will be refreshed. Since it makes the navigation way slower, i would like to have the view not refreshing the page each time the form is used.
Is it possible to accomplish this in Django? For example, instead of refreshing the page, i would like to only load part of it, or to have a 'Reload' icon while the view is doing its work.
I'm pretty new to Ajax, so i don't know how to get started on this.
I am a newbie to Django and a form I created is giving me a bit of trouble.
I have create a form in Django for user authentication and login. But the form is not redirecting to the link I've specified after hitting submit. I think this is because the authentication function in views.py is returning the user as None. But this should not happen because the user exists in the database. I've confirmed this by going to http://127.0.0.1:8000/admin/, which is Django's internal developer server.
The URL that I'm trying to redirect it to exists. No problems there.
The python files related to this are:
forms.py:
from django.contrib.auth.models import User
from django import forms
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ['username', 'email', 'password']
views.py:
I've omitted all the imports in the following code. No problems there.
class UserFormView(View):
form_class = UserForm
template_name = 'music/registration_form.html'
def get(self, request): # This function is executed if the server obtains a GET request.
form = self.form_class(None)
return render(request, self.template_name, {'form': form})
'''
The server gets a GET request every time a new user wants to register, i.e they want an empty form.
That's why we pass None in the function above.
It gets a POST request every time a filled form is submitted.
'''
def post(self, request): # This function is executed if the sever recevies a POST request.
form = self.form_class(request.POST)
if form.is_valid():
user = form.save(commit=False) # This creates an object, but does not save it to the database.
# Therefore, we can do some changes.
username = form.cleaned_data['username']
password = form.cleaned_data['password']
# Here, cleaned_data is converted data to suitable format. Like the date entered is converted to a
# suitable format as its format is different all around the world.
# Now you can change the username by user.username = 'some_name' or you can change the password by
# user.set_password(new_password)
user.save() # This line of code actually saves the code.
user = authenticate(username=username, password=password)
# This checks if the user actually exists in the database.
if user is not None:
if user.is_active: # This if the user is not banned or anything like that.
login(request, user) # This logs in the user.
return redirect('music:index') # Redirects the user to index page.
else:
return render(request, self.template_name, {'form': form})
else:
form = self.form_class(None)
return render(request, self.template_name, {'form': form})
# This returns the filled form again if the the form is not valid.
The registration form template is (html file) :
{% extends 'music/base.html' %}
{% block title%}Registration Form {% endblock %}
{% block body %}
{% load staticfiles %}
<link rel="stylesheet" type="text/css" href="{% static 'music/index_style.css' %}" />
<div class="block">
<form action="" method="post" >
{% csrf_token %}
<fieldset> <!-- Gives it a better look by putting a heading and background around the form -->
<legend>Create a new account:</legend><!-- This the common heading for the form -->
{% include 'music/form_template.html' %}
<br>
<input type="submit" value="Submit">
</fieldset>
</form>
</div>
{% endblock %}>
The form_template.html included in the registration form template is:
{{ form.non_field_errors }}
{{ form.errors }}
{{ form.as_p }}
Also, one other thing that is not normal is that whenever I create a new user by using the above form, the password for that user is being shown as:
"Invalid password format or unknown hashing algorithm."
This can be seen at http://127.0.0.1:8000/admin/ where we can edit the current users.
There are a few issues here.
You correctly call save with commit=False, to allow you to set the hashed password before saving properly (as the comments state), but you never actually do so, so the user is saved with an unhashed password. This will never validate.
Similarly, you never set the user's is_active property, so the check a bit further down will always fail.
user = form.save(commit=False)
password = form.cleaned_data['password']
user.set_password(password)
user.is_active = True
user.save()
I'm familar with using templates to collect the data, but on displaying is there a smart way that Django will display the fields and populate them with the right values. I can do it manually of course, but the model knows the field type. I didn't see any documentation on this. For example I collect data from the template with:
<strong>Company Name</strong>
<font color="red">{{ form.companyname.errors }}</font>
{{ form.companyname }}
where form is my company model containing all the fields. How would I go about ensuring that I could use this type of methodology such that Django would render the text fields and populate with the current values. For example is there a way to send in values in the following way:
myid = int(self.request.get('id'))
myrecord = Company.get_by_id(myid)
category_list = CompanyCategory.all()
path = os.path.join(os.path.dirname(__file__), 'editcompany.html')
self.response.out.write(template.render(path, {'form': myrecord, 'category_list': category_list}))
Can I do the same this with records and will the template populate with values sent in? Thanks
It sounds like you may be confused about the difference and proper usage of Form vs ModelForm
Regardless of which type of form you use, the templating side of forms stays the same:
Note: all of the values in your form (as long as its bound to POST or has an instance) will be prepopulated at render.
<form class="well" action="{% url member-profile %}" method="POST" enctype="multipart/form-data">{% csrf_token %}
<fieldset>
{{ form.non_field_errors }}
{{ form.display_name.label_tag }}
<span class="help-block">{{ form.display_name.help_text }}</span>
{{ form.display_name }}
<span class="error">{{ form.display_name.errors }}</span>
{{ form.biography.label_tag }}
<span class="help-block">{{ form.biography.help_text }}</span>
{{ form.biography }}
<span class="error">{{ form.biography.errors }}</span>
<input type="submit" class="button primary" value="Save" />
</fieldset>
</form>
if you want to be populating a form from a record (or submit a form as a record) its probably best to use ModelForm
EX a profile form that doesn't display the User FK dropdown:
class ProfileForm(forms.ModelForm):
"""Profile form"""
class Meta:
model = Profile
exclude = ('user',)
The View:
def profile(request):
"""Manage Account"""
if request.user.is_anonymous() :
# user isn't logged in
messages.info(request, _(u'You are not logged in!'))
return redirect('member-login')
# get the currently logged in user's profile
profile = request.user.profile
# check to see if this request is a post
if request.method == "POST":
# Bind the post to the form w/ profile as initial
form = ProfileForm(request.POST, instance=profile)
if form.is_valid() :
# if the form is valid
form.save()
messages.success(request, _(u'Success! You have updated your profile.'))
else :
# if the form is invalid
messages.error(request, _(u'Error! Correct all errors in the form below and resubmit.'))
else:
# set the initial form values to the current user's profile's values
form = ProfileForm(instance=profile)
return render(
request,
'membership/manage/profile.html',
{
'form': form,
}
)
notice that the outer else initializes the form with an instance: form = ProfileForm(instance=profile) and that the form submit initializes the form with post, BUT still binds to instance form = ProfileForm(request.POST, instance=profile)
If you're looking at forms, it would seem like a good idea to start with Django's forms framework, specifically forms for models.
I already used the answer to this question, but for some reason I'm not getting a good result.
I'm trying to use the same template for my edit form and my add form. Here's my urls.py:
url(r'^app/student/new/$', 'edit_student', {}, 'student_new'),
url(r'^app/student/edit/(?P<id>\d+)/$', 'edit_student', {}, 'student_edit'),
And my views.py:
def edit_student(request, id=None, template_name='student_edit_template.html'):
if id:
t = "Edit"
student = get_object_or_404(Student, pk=id)
if student.teacher != request.user:
raise HttpResponseForbidden()
else:
t = "Add"
student = Student(teacher=request.user)
if request.POST:
form = StudentForm(request.POST, instance=student)
if form.is_valid():
form.save()
# If the save was successful, redirect to another page
redirect_url = reverse(student_save_success)
return HttpResponseRedirect(redirect_url)
else:
form = StudentForm(instance=student)
return render_to_response(template_name, {
'form': form,
't': t,
}, context_instance=RequestContext(request))
And my forms.py:
class StudentForm(ModelForm):
class Meta:
model = Student
exclude = ('teacher',)
And finally my template student_edit_template.html:
<h1>{{ t }} Student</h1>
<form action="/app/student/edit/{{ student.id }}" method="post"> {% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
For some reason, this is throwing a 404:
Page not found (404)
Request Method: POST
Request URL: http://192.168.1.3:5678/app/student/edit/
I'm probably missing something easy here, but at this point I need another set of eyes on it at the very least.
Thanks in advance!
You're getting the 404 because /student/edit/ requires an id at the tail end otherwise there's no route, and when you're coming from /student/new/ you don't have an id yet. Create a route and view for /student/edit/ and put logic in there to handle the case for when you're creating a record on POST.