Django add data to manyToManyField on form submission - python

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].

Related

Django ModelForm ignores the data supplied via form and saves the superuser name in the table

I'm new at using Django forms (Django altogether), and on my first form, I have encountered this error. No matter what data I post via the form it saves the superuser name in all the fields.
Here are the files,
forms.py
from django.forms import ModelForm
from .models import *
class NewCustomer(ModelForm):
class Meta:
model = Customer
fields = ('name', 'mobile_number', 'email', 'address')
Views.py
from django.shortcuts import render, get_object_or_404, redirect
from .models import *
from .forms import *
# Create your views here.
def customers(request):
customers = Customer.objects.all().order_by('id')
return render(request, "customers.html", {'customers': customers, 'custactive': "active"})
def customer_details(request, pk):
customer = get_object_or_404(Customer, pk=pk)
return render(request, "customer_details.html", {'customer': customer})
def new_customer(request):
if request.method == 'POST':
form = NewCustomer(request.POST)
if form.is_valid():
customer = form.save(commit=False)
customer.name = request.user
customer.mobile_number = request.user
customer.email = request.user
customer.address = request.user
customer.save()
return redirect ('customers')
else:
form = NewCustomer()
return render(request, "new_customer.html", {'form': form})
Can someone tell me what's wrong with the code? Understandably I need to save new data that I supply with the form.
Really appreciate your help...
The problem is that you need to tell the form which fields to get from User object.
Now if you have extended the User model and have name, mobile_number, address specified, you need to modify your code.
def new_customer(request):
if request.method == 'POST':
form = NewCustomer(request.POST)
if form.is_valid():
customer = form.save(commit=False)
customer.name = request.user.name
customer.mobile_number = request.user.mobile_number
customer.email = request.user.email
customer.address = request.user.address
customer.save()
return redirect ('customers')
The reason whz superuser's name is saved in all fields is because all models have their str method, which tells python what to print out if object itself is used.

Forms and views for custom User model with extra parameters [django 2.1]

Im trying to create a form that would allow me to add a profile picture to the custom User object. I know that there is OneToOne method, although I want it to be stored directly in User.
You need to extend default User Model like this:
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
"""Add more fields to default user model."""
profile_pic = models.ImageField(upload_to='profile_pics', blank=True, null=True)
Now you need to edit your settings.py to make your custom User model the default auth model. Add this line in your settings.py:
AUTH_USER_MODEL = 'myApp.User'
myApp is the name of app in whose models.py your created your Custom User Model.
And that's all, now the default auth model is your custom model User which is exactly the same as the Django default auth model except it has an additional field profile_pic to store an image.
Form to add picture should be like this:
class profilepictureForm(forms.ModelForm):
"""Form to add profile picture to User model."""
class Meta:
"""Meta class for profilepictureForm."""
model = User
fields = ('profile_pic', )
And in your views you should use this form like this:
def add_profile_picture(request):
if request.method == 'POST':
form = profilepictureForm(request.POST, request.FILES, instance=request.user)
if form.is_valid():
form.save()
return HttpResponseRedirect('/success/url/')
else:
form = profilepictureForm(instance=request.user)
return render(request, 'userpanel/profilepicture.html', {'form': form})
Have a look on below code
from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import UploadFileForm
# Imaginary function to handle an uploaded file.
from somewhere import handle_uploaded_file
def upload_file(request):
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
handle_uploaded_file(request.FILES['file'])
return HttpResponseRedirect('/success/url/')
else:
form = UploadFileForm()
return render(request, 'upload.html', {'form': form})
For more information please check https://docs.djangoproject.com/en/dev/topics/http/file-uploads/

Django views.register returning none instead of a HTTPresponse

I'm trying to make a custom user registration form
Here is my views.py code
from django.shortcuts import render, redirect
from django.views.generic import TemplateView
from .forms import RegistrationForm
# Create your views here.
def register(request):
if request.POST:
form = RegistrationForm(request.POST)
if form.is_valid():
form.save()
return redirect("profile/")
else:
form = RegistrationForm()
context = {'form': form}
return render(request, 'accounts/registration.html', context)
Here is my forms.py code
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
class RegistrationForm(UserCreationForm):
email = forms.EmailField(required=True)
class Meta:
model = User
fields = [
'username',
'first_name',
'last_name',
'email',
'password1',
'password2',
]
def save(self, commit=True):
user = super(RegistrationForm, self).save(commit=False)
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
user.email = self.cleaned_data['email']
if commit:
user.save()
return user
When I run this code it's working but when I try to register a user it is returning
ValueError at /accounts/registration/
The view accounts.views.register didn't return an HttpResponse object. It
returned None instead.
Here accounts is the name of my Django app
In your views.py, you're only returning redirect() if the request is of type POST and the form is valid; or if you receive any other request type. You're not handling the case in which the request type is POST and the form is invalid. This can be easily fixed by extending the statement:
def register(request):
# Always use request.method to check whether it's a POST or GET request
if not request.method == 'POST':
form = RegistrationForm()
context = {'form': form}
return render(request, 'accounts/registration.html', context)
form = RegistrationForm(request.POST)
if not form.is_valid():
# Handle the case in which the form is invalid here.
# Make sure you return redirect() or render() here.
# Now we're in the case in which the form _is_ valid
form.save()
return redirect("profile/")
I have also made your code a little more pythonic and reduced the complexity of the if-statements. Please note to always use request.method to validate the type of the incoming request. In any case, your view should always return a redirect() or render() object to avoid the error quoted in your question.
Move the last two lines of your view back one indent level, so that they execute in all cases.

Using an extended usermodel, how can I create two model instances with two modelforms in the same view?

First off, I want to say that I am new to django though I understand most of it, forms have always been confusing to me.
I have two models in which I need to create an instance from, the standard built in User model and my own UserProfile model.
The problem I am facing is that really do not know how to display two forms (one for each model) in the template and on save() then tell django that the newly created UserProfile instance's User = model.ForeignKey belongs to the also newly created User.
My forms.py is fairly simple:
from django import forms
from django.forms import ModelForm
from django.contrib.auth.models import User
from .models import UserProfile
class UserForm(ModelForm):
class Meta:
model = User
fields = ('username', 'email', 'password')
class UserProfileForm(ModelForm):
class Meta:
model = UserProfile
fields = ('display_name', 'avatar', 'birthday', 'usertype', 'daw', 'usergenre')
In my views.py I've tried doing this:
from .forms import UserForm
from .forms import UserProfileForm
# Create your views here.
def RegisterView(request):
if request.method == 'POST':
form = UserForm(request.POST)
form2 = UserProfileForm(request.POST)
if form.is_valid():
if form2.is_valid():
return HttpResponseRedirect('/login/')
return render(request, 'register.html', {'form': form, 'form2': form})
But when I try to access /register I get this error:
http://dpaste.com/19NH2A6
You should use save() method.
Next time you have a problem, check the official Django documentation.
ModelForms - save() method
from .forms import UserForm
from .forms import UserProfileForm
from django.http import HttpResponseRedirect
def RegisterView(request):
if request.method == 'POST':
form = UserForm(request.POST, prefix='uf')
form2 = UserProfileForm(request.POST, prefix='upf')
if form.is_valid():
if form2.is_valid():
form.save()
form2.save()
return HttpResponseRedirect('/login/')
elif request.method == 'GET':
form = UserForm(prefix='uf')
form2 = UserProfileForm(prefix='upf')
return render(request, 'register.html', {'form': form, 'form2': form2})
When you hit /register page from browser, your view gets GET request, you have created form only for POST request
from .forms import UserForm
from .forms import UserProfileForm
# Create your views here.
def RegisterView(request):
if request.method == 'POST':
form = UserForm(request.POST, prefix='uf')
form2 = UserProfileForm(request.POST, prefix='upf')
if form.is_valid():
if form2.is_valid():
return HttpResponseRedirect('/login/')
elif request.method == 'GET':
form = UserForm(prefix='uf')
form2 = UserProfileForm(prefix='upf')
return render(request, 'register.html', {'form': form, 'form2': form2})
You should read the traceback yourself so that you can find the error easily.
It says;
Exception Type: NameError at /register/
Exception Value: name 'HttpResponseRedirect' is not defined
You've used HttpResponseRedirect but you didn't import it, therefore it is not defined.
Add this to top of your code.
from django.http import HttpResponseRedirect

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