Form inside page in Django - python

I want to make a DetailView page, like:
class TaskDetailView(DetailView):
model = Task
template_name = 'todo/task_detail.html'
and place form inside this page, so user can add this task.
Its easy, if create new page for this form:
forms.py
class TaskForm(ModelForm):
class Meta:
model = task
fields = __all__
views.py
def TaskForm_view(request, pk):
if request.method == 'POST':
form = TaskForm(request.POST)
if form.is_valid(): # All validation rules pass
task.save()
return HttpResponseRedirect('/admin/') # Redirect after POST
else:
form = TaskForm() # An unbound form
return render(request, 'todo/add_task.html', {
'form': form,
})
urls.py:
url(r'^(?P<pk>\d+)/add/', 'todo.views.TaskForm_view', name='add')
but how to create a DetailView page with form inside? I cant find an exemple, help plz!

You can add the form in a context variable, so you can access to it from the template as: form
class TaskDetailView(DetailView):
model = Task
template_name = 'todo/task_detail.html'
def get_context_data(self, **kwargs):
context = super(TaskDetailView, self).get_context_data(**kwargs)
context['form'] = TaskForm()
return context

Consider using CreateView, UpdateView, DeleteView.
DetailView are designed to display data.
Here is described Form handling with class-based views in django

Related

How to track which user is creating object for a model and how to show the object details only to that user in django

I am doing an online classroom project in Django where I created a model named create_course which is accessible by teachers. Now I am trying to design this as the teacher who creates a class only he can see this after login another teacher shouldn't see his classes and how to add students into that particular class I created
the course model
class course(models.Model):
course_name = models.CharField(max_length=200)
course_id = models.CharField(max_length=10)
course_sec = models.IntegerField()
classroom_id = models.CharField(max_length=50,unique=True)
created_by = models.ForeignKey(User,on_delete=models.CASCADE)
here if I use "the created_by" field in forms it appears to be a drop-down menu where every user is showing but I want to automatically save the user who creates the object
views.py
def teacher_view(request, *args, **kwargs):
form = add_course(request.POST or None)
context = {}
if form.is_valid():
form.save()
return HttpResponse("Class Created Sucessfully")
context['add_courses'] = form
return render(request, 'teacherview.html', context)
forms.py
from django import forms
from .models import course
class add_course(forms.ModelForm):
class Meta:
model = course
fields = ('course_name', 'course_id', 'course_sec', 'classroom_id')
You can inject the logged in user to the .created_by of the .instance in the form, so:
from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect
#login_required
def teacher_view(request, *args, **kwargs):
if request.method == 'POST':
form = add_course(request.POST, request.FILES)
if form.is_valid():
form.instance.created_by = request.user
form.save()
return redirect('name-of-some-view')
else:
form = add_course()
return render(request, 'teacherview.html', {'add_courses': form})
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.
Note: You can limit views to a view to authenticated users with the
#login_required decorator [Django-doc].
Note: Usually a Form or a ModelForm ends with a …Form suffix,
to avoid collisions with the name of the model, and to make it clear that we are
working with a form. Therefore it might be better to use CourseForm instead of
add_course.
Note: Models in Django are written in PascalCase, not snake_case,
so you might want to rename the model from course to Course.
Note: In case of a successful POST request, you should make a redirect
[Django-doc]
to implement the Post/Redirect/Get pattern [wiki].
This avoids that you make the same POST request when the user refreshes the
browser.
In your view use commit=False to stop the form from saving until you add the created_by field.
def teacher_view(request, *args, **kwargs):
form = add_course(request.POST or None)
context = {}
if form.is_valid():
course = form.save(commit=False)
course.created_by = request.user
course.save()
return HttpResponse("Class Created Sucessfully")
context['add_courses'] = form
return render(request, 'teacherview.html', context)

What causes "no attribute 'object_list' when I purposely csuse HTML error

I am writing a django ListView with FormMixin, but it can't handle form errors. The model limits input to 140 characters, when I inspect and change limit to 200 and submit I get
'PostListView' object has no attribute 'object_list'"
Here's the code
class PostListView(FormMixin, generic.ListView):
model = Post
form_class = PostForm
paginate_by = 10
template_name = 'index.html'
def get_success_url(self):
return reverse('index')
def post(self, request, *args, **kwargs):
form = PostForm(request.POST)
if form.is_valid():
form.save()
return super().form_valid(form)
else:
return self.form_invalid(form)
With everything working normally, it saves the data and displays the list. On error, no error, it fails.
EDIT
As #crimsonpython24 has said, ListView is for displaying data. I opted to use a basic view
def index(request):
'''deal with post method first'''
if request.method == 'POST':
form = PostForm(request.POST)
if form.is_valid():
form.save()
return redirect(reverse('index'))
else:
form = PostForm
posts = Post.objects.all()
return render(request, 'index.html', {'form':form, 'posts':posts})
This allows for invalid form data to be returned for correction, and also allows viewing of posts
The point is that ListView is only supposed to view objects. If you have a form in your view, try to go for one of the edit views, which lets you create, update, and delete (now I'm assuming that you also handle a form in this view).
I can't exactly describe how ListView causes your problem other than it does not fit your purpose and there are better alternatives.
EDIT
Now you're concatenating a FormView and ListView. However, I will still recommend going for a FormView as a ListView doesn't have a form_class attribute. It's easy, though. Let's say you have this FormView class:
class ContactView(FormView):
template_name = 'contact.html'
form_class = ContactForm # Now you can simply do this to your form
success_url = '/thanks/'
def form_valid(self, form):
form.send_email()
return super().form_valid(form)
and then simply pass in context data to make it behave partially like a ListView:
class ContactView(FormView):
# whatever you have here already
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['now'] = timezone.now()
return context
So now your new view will render both your form and context data. Seeing as both these views don't require a primary key to operate, I don't see any problem implmenting this.

Django add data to manyToManyField on form submission

I would like to automatically add the User who submitted the form to the users many to many field on the below-given model when the form submits, how could I do this from the view?
The model:
class Project(MainAbstractModel):
users = models.ManyToManyField(User)
title = models.CharField(max_length=25, default="Conflict")
The view:
def myconflicts(request):
if request.method == "POST":
form = ProjectForm(request.POST)
if form.is_valid():
form.save()
else:
form = ProjectForm()
return render(request, 'conflictmanagement/myconflicts.html')
And my form is simply:
class ProjectForm(ModelForm):
class Meta:
model = Project
fields = ["title"]
You can add the user in the view, for example with:
from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect
#login_required
def myconflicts(request):
if request.method == 'POST':
form = ProjectForm(request.POST)
if form.is_valid():
project = form.save()
project.users.add(request.user)
return redirect('name-of-some-view')
else:
form = ProjectForm()
return render(request, 'conflictmanagement/myconflicts.html', {'form': form})
Note: In case of a successful POST request, you should make a redirect
[Django-doc]
to implement the Post/Redirect/Get pattern [wiki].
This avoids that you make the same POST request when the user refreshes the
browser.
Note: You can limit views to a view to authenticated users with the
#login_required decorator [Django-doc].

What is the appropriate way to set up a form and view in Django to accommodate both creating and updating a model

I am working with sensitive code and I am not able to share specifics based on rules at my job. However, I have a pretty specific issue that should be easy to help with without code. I am new to Django and I am using legacy code. My issue is that I need to build a form that will update an instance of the model if it already exists and if it does not exist, then the form will create and save a new instance of the model. Any suggestions or examples of what it might look like?
https://docs.djangoproject.com/en/dev/topics/forms/modelforms/
The only difference would be to pass the form an instance argument for existing objects.
myapp/models.py
from django.db import models
class Article(models.Model):
# Define fields here
myapp/forms.py
from django.forms import ModelForm
from myapp.models import Article
# Create the form class.
class ArticleForm(ModelForm):
class Meta:
model = Article
fields = ['pub_date', 'headline', 'content', 'reporter']
myapp/views.py
from django.core.urlresolvers import reverse
from django.shortcuts import render_to_response, redirect, get_object_or_404
from django.template import RequestContext
from myapp.models import Article
from myapp.forms improt ArticleForm
def create_entry(request):
if 'POST' == request.method:
form = ArticleForm(data=request.POST, files=request.FILES)
if form.is_valid():
obj = form.save()
return redirect('your-view')
else:
form = ArticleForm()
context = {'form': form}
render_to_response('myapp/create_entry.html', context, context_instance=RequestContext(request))
def edit_entry(request, article_id):
article = get_object_or_404(Article, pk=article_id)
if 'POST' == request.method:
form = ArticleForm(data=request.POST, files=request.FILES, instance=article)
if form.is_valid():
obj = form.save()
return redirect('your-view')
else:
form = ArticleForm(instance=article)
context = {'form': form}
render_to_response('myapp/edit_entry.html', context, context_instance=RequestContext(request))

Django model form not submitting correctly

I've created a model form which is then rendered in a context processor as the form is included on every page. Once the form is submitted it should re-direct to a 'thank you' page. However it just seems to re-load the page and remove the form. I had it all working when rendering on a page via a URL. Since moving the function to my context processor it doesn't redirect correctly.
It also saves the information that's provided into the model, in the admin. So I'm guessing it is something to do with redirect.
Here is my context processor:
from django.conf import settings
from contact_enquiries import forms
from django.shortcuts import render
from django.http import HttpResponseRedirect
def contact(request):
if request.method == 'POST':
form = forms.ContactUsForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/thanks/')
else:
form = forms.ContactUsForm()
return {
'contact_form' : form,
}
forms.py
class ContactUsForm(ModelForm):
class Meta:
model = ContactUs
fields = ['name', 'contact_number', 'email', 'enquiry']
models.py
class ContactUs(models.Model):
name = models.CharField(max_length=200)
contact_number = models.IntegerField(max_length=50)
email = models.EmailField(max_length=300)
enquiry = models.TextField()
class Meta:
verbose_name_plural = "Contact Us"
def __unicode__(self):
return self.name
A context processor should always return a dictionary, it shouldn't return an http response.
One option is to make your contact form post to a different view. You do this by changing the action attribute of the form in your template.
<form action="{% url 'contact' %}" method="post">
Your contact view and url patterns would look something like this:
url('^/contact/$', contact, name="contact"),
def contact(request):
if request.method == 'POST':
form = forms.ContactUsForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/thanks/')
else:
form = forms.ContactUsForm()
return render(request, "contact.html", {
'contact_form' : form,
})
Your context processor then simplifies to:
def contact(request):
form = forms.ContactUsForm()
return {'contact_form' : form}

Categories