How to use ModelMultipleChoiceField - django

I am trying to create a website that allows users to follow certain stocks and read articles based on what they follow. I am having trouble creating a form for them to follow stocks as a user's Profile and Stocks have a many to many relationship, I believe I am supposed to use ModelMultipleChoiceField but cannot get it to work.
models.py
from django.db import models
from django.contrib.auth.models import User
from django.dispatch import receiver
from django.db.models.signals import post_save
class Stock(models.Model):
name = models.CharField(max_length = 50)
ticker = models.CharField(max_length = 50)
def __str__(self):
return self.name
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
followed_stocks = models.ManyToManyField(Stock, blank=True)
def __str__(self):
return self.user.username
#receiver(post_save, sender=User)
def update_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
instance.profile.save()
class Article(models.Model):
stock = models.ForeignKey(Stock, on_delete=models.CASCADE, default = 0 )
title = models.CharField(max_length = 200)
url = models.URLField()
description = models.TextField()
def __str__(self):
return self.title
forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from .models import Stock
from django.forms import ModelMultipleChoiceField
class ProfileRegistrationForm(UserCreationForm):
class Meta:
model = User
fields = ('username', 'password1', 'password2', 'email', 'first_name' ,'last_name')
class StockFollowForm():
stocks = forms.ModelMultipleChoiceField(queryset=Stock.objects.all())
views.py
def test(request):
if request.method == "POST":
form = StockFollowForm(request.POST)
if form.is_valid():
request.user.profile.followed_stocks = form.cleaned_data.get('stocks_selected')
request.user.save()
return redirect('index')
else:
form = StockFollowForm()
return render(request, 'core/test.html',{'form': form})
template:
{% block body %}
<div class = "container">
<h2 class = "text-center">Register</h2>
<form method = 'post'>
{% csrf_token %}
{{ form }}
<div class = "text-center">
<br/>
<button class="btn btn-primary" type = 'submit'>Login</button>
</div>
</form>
</div>
{% endblock %}
When I run this code no form is displayed. Thanks in advance for your help!

I think your form class has to inherit from djangos form, like the docs show.
Change
class StockFollowForm():
to
from django import forms
class StockFollowForm(forms.Form):

Related

Having trouble in creating forms in django

This is my models.py file
from django.db import models
# Create your models here.
class Blog(models.Model):
name = models.CharField(max_length=120)
created_on = models.DateTimeField(auto_now_add=True)
class Article(models.Model):
blog = models.ForeignKey(Blog,
on_delete=models.CASCADE)
created_on = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=120)
body = models.TextField()
draft = models.BooleanField(default=False)
This is my forms.py file
from blog.models import Article
from django import forms
class ArticleForm(forms.ModelForm):
class Meta:
model = Article
fields = ['title', 'body', 'draft']
Here is the views.py file
from django.shortcuts import render
from django.http import HttpResponse
from blog.forms import ArticleForm
# Create your views here.
def add_article(request):
if request.method == 'POST':
form = ArticleForm(request.POST)
if form.is_valid():
form.save()
return HttpResponse("Article created")
else:
context = {'form': ArticleForm()}
return render(request, 'add_article.html', context)
context = {'form': ArticleForm()}
return render(request, 'add_article.html', context)
Can someone tell me how do I insert the first attribute of class Article which is blog in class Articleform?
I am learning django and some help will be appreciated.
You can check these steps:
be sure you added {{form}} in your add_article.html.
be sure you added method="POST" in your <form> tag.
e.g.:
<form method="POST">
{{form}}
<input type="submit">Post</input>
</form>

How to automatically create relationship between user model and custom group in Django?

As a newbie to Django, all things are still not clear to me. I'm having some issues while working on my project. Whenever I register as a new student, it lets me to login. But I cannot upload profile picture. It throws me an error:
ValueError at /account_settings/
The 'profile_pic' attribute has no file associated with it.
When I login as an admin and want to see the new student, I just see a blank space, not the new student. Here is the screenshot of my admin view:
If I see from admin page, there is also a blank space. Here is admin page view:
I have to manually create a student and an user from admin page, and make relationship between them. Please anyone explain me what actually happens behind the scenario. I'm a noob, I'll be grateful if anyone kindly makes it clear for me. Thanks in advance.
Here is my models.py:
from django.db import models
from django.contrib.auth.models import User
class Student(models.Model):
user = models.OneToOneField(User, null=True, blank=True, on_delete=models.CASCADE)
name = models.CharField(max_length=200)
phone = models.CharField(max_length=200, null=True)
email = models.CharField(max_length=200, null=True)
profile_pic = models.ImageField(default= 'default-picture.jpg', null= True, blank= True)
date_created = models.DateTimeField(auto_now_add=True, null=True)
def __str__(self):
return str(self.name)
class Tag(models.Model):
name = models.CharField(max_length=200, null=True)
def __str__(self):
return self.name
class Books(models.Model):
CATEGORY = (
('Physics', 'Physics'),
('Chemistry', 'Chemistry'),
('Mathematics', 'Mathematics'),
)
name = models.CharField(max_length=200)
author = models.CharField(max_length=200, null=True)
price = models.FloatField(null=True)
category = models.CharField(max_length=200, null=True, choices=CATEGORY)
description = models.CharField(max_length=200, null=True, blank=True)
date_created = models.DateTimeField(auto_now_add=True, null=True)
tags = models.ManyToManyField(Tag)
def __str__(self):
return self.name
class Issue(models.Model):
STATUS = (
('Pending', 'Pending'),
('Out for delivery', 'Out for delivery'),
('Delivered', 'Delivered'),
)
student = models.ForeignKey(Student, null=True, on_delete= models.SET_NULL)
book = models.ForeignKey(Books, null=True, on_delete= models.SET_NULL)
date_created = models.DateTimeField(auto_now_add=True, null=True)
status = models.CharField(max_length=200, null=True, choices=STATUS)
def __str__(self):
return self.book.name
Here is my forms.py:
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from django.forms import ModelForm
from .models import Issue
from .models import Student
class IssueForm(ModelForm):
class Meta:
model = Issue
fields = '__all__'
class CreateUserForm(UserCreationForm):
class Meta:
model = User
fields = ['username', 'email', 'password1', 'password2']
class StudentForm(ModelForm):
class Meta:
model = Student
fields = '__all__'
exclude = ['user']
It's my decorators.py file:
from django.http import HttpResponse
from django.shortcuts import redirect
def unauthenticated_user(func):
def wrapper(request, *args, **kwargs):
if request.user.is_authenticated:
return redirect('home')
else:
return func(request, *args, **kwargs)
return wrapper
def allowed_user(allowed_roles=[]):
def decorator(func):
def wrapper(request, *args, **kwargs):
group = None
if request.user.groups.exists():
group = request.user.groups.all()[0].name
if group in allowed_roles:
return func(request, *args, **kwargs)
else:
return HttpResponse('You are not authorized to view this page.')
return wrapper
return decorator
def admin_only(func):
def wrapper(request, *args, **kwargs):
group = None
if request.user.groups.exists():
group = request.user.groups.all()[0].name
if group == 'Student':
return redirect ('user_page')
else:
return func(request, *args, **kwargs)
return wrapper
It's my registration, login and account_setting method in views.py file:
from django.shortcuts import render, redirect
from django.http import HttpResponse, HttpResponseRedirect
from django.forms import inlineformset_factory
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import Group
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.urls import reverse
from .models import *
from .forms import IssueForm, CreateUserForm, StudentForm
from .filters import IssueFilter
from .decorators import unauthenticated_user, allowed_user, admin_only
#unauthenticated_user
def registerPage(request):
form = CreateUserForm()
if request.method == "POST":
form = CreateUserForm(request.POST)
if form.is_valid():
user =form.save()
username = form.cleaned_data.get('username')
group = Group.objects.get(name = 'Student')
user.groups.add(group)
Student.objects.create(
user = user
)
messages.success(request, 'Account successfully created for ' + username)
return redirect ('login')
context = {'form': form}
return render(request, 'accounts/register.html', context)
#unauthenticated_user
def loginPage(request):
if request.user.is_authenticated:
return redirect('home')
else:
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
return redirect ('home')
else:
messages.info(request, 'Username or Password is incorrect')
return render(request, 'accounts/login.html')
#login_required(login_url='login')
#allowed_user(allowed_roles=['Student'])
def accountSettings(request):
user = request.user.student
form = StudentForm(instance=user)
if request.method == 'POST':
form = StudentForm(request.POST, request.FILES, instance=user)
if form.is_valid():
form.save()
context = {'form': form}
return render(request, 'accounts/account_settings.html', context)
And my account_seetings.html template:
{% extends 'accounts/main.html' %}
{% load static %}
{% block content%}
<style>
.profile-pic{
max-width: 300px;
max-height: 300px;
margin: 0 auto;
border-radius: 70%;
}
</style>
<br>
<div class="row">
<div class="col-md-3">
<div class="card card-body">
<a class="btn btn-warning" href="{% url 'home' %}"> ← Back to Profile</a>
<hr>
<img class="profile-pic" src="{{request.user.student.profile_pic.url}}">
</div>
</div>
<div class="col-md-9">
<div class="card card-body">
<form method="POST" action="" enctype="multipart/form-data">
{% csrf_token %}
{{form.as_p}}
<input class="btn btn-primary" type="submit" name="Update Information">
</form>
</div>
</div>
</div>
{% endblock %}
It should be noted that I have two groups in admin page. These are Student and Admin.

saving forms via TemplateView

I am trying to save forms via Post by TemplateView, but when def Post calls, forms are not saved.
using inline formset . Book Title is saved by Author,1 author can have multiple books .
Codes below are what I am using:
This is the view , Posting content of Inlineformset , if it is get , shows the form , if it is post it must save the data .
#view.py
from django.shortcuts import render
# Create your views here.
from django.views.generic import TemplateView,UpdateView
from django.forms import inlineformset_factory
from .models import Author,Book
from django.shortcuts import redirect
class BookView(TemplateView):
template_name ="index.html"
def get(self, request, *args, **kwargs):
return self.render_preview(request)
def post(self,request,*args,**kwargs):
return self.save_book(request)
def save_book(self,request,**kwargs):
BookFormSet = inlineformset_factory(Author, Book, fields=('title',),can_delete=False)
author = Author.objects.get(name='John')
formset = BookFormSet(instance=author)
if formset.is_valid():
formset.save()
return redirect('/')
context = super(BookView, self).get_context_data(**kwargs)
context['formset'] = formset
return self.render_to_response(context)
def render_preview(self, request, **kwargs):
BookFormSet = inlineformset_factory(Author, Book, fields=('title',),can_delete=False)
author = Author.objects.get(name='John')
formset = BookFormSet(instance=author)
context = super(BookView, self).get_context_data(**kwargs)
context['formset'] = formset
return self.render_to_response(context)
#Models
This is the models.py
# Create your models here.
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class Book(models.Model):
author = models.ForeignKey(Author, on_delete=models.CASCADE)
title = models.CharField(max_length=100)
def __str__(self):
return self.title
index.html
<form action="" method="post" >
<div class="html">
{% csrf_token %}
{% for form in formset %}
{{form }}
{%endfor %}
<button type="submit">save</button>
</form>
</div>
I was having this same issue not so long ago and I solved it a bit different than by using a FormSet (which I am not so familiar with), hope it helps you out:
Models.py
from django.db import models
class Author(models.Model)
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class Book(models.Model)
author = models.ForeignKey(Author, on_delete=models.CASCADE)
title = models.CharField(max_length=100)
def __str__(self):
return self.title
Forms.py
from django import forms
from Appname.models import Author, Book
class Author(forms.ModelForm):
class Meta:
model = Author
fields = ['name']
class Book(forms.ModelForm):
class Meta:
model = Book
fields = ['author', 'title']
Views.py
class BookView(TemplateView):
template_name ="index.html"
author_form_class = Author
def get_context_data(self, **kwargs):
context = super(BookView, self).get_context_data(**kwargs)
context['author_form'] = self.author_form_class
context['book_form'] = self.book_form_class
return context
def post(self, request):
author_form_class = Author(request.POST or None)
book_form_class = Book(request.POST or None)
if author_form_class.is_valid():
author_form_class.save()
return redirect('/')
if book_form_class.is_valid():
book_form_class.save()
return redirect('/')
index.html
<form method="post">
{{ csrf_token }}
{{ author_form}}
<input type="submit" value="submit">
</form>

Prepopulate ModelMultipleChoiceField Django

I am creating a website that allows users to follow stocks and see articles based on those stocks. Upon registration the user follows Stocks for the first time. After this I would like them to be able to view a page that shows all Stocks and which ones they follow. How can I prepopulate a ModelMultipleChoiceField?
models.py:
class Stock(models.Model):
name = models.CharField(max_length = 50)
ticker = models.CharField(max_length = 50)
def __str__(self):
return self.name
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
followed_stocks = models.ManyToManyField(Stock, blank=True)
def __str__(self):
return self.user.username
#receiver(post_save, sender=User)
def update_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
instance.profile.save()
views.py:
def test(request):
if request.method == "POST":
form = StockFollowForm(request.POST)
if form.is_valid():
request.user.profile.followed_stocks = list(form.cleaned_data.get('stocks_selected'))
request.user.profile.save()
return redirect('index')
else:
form = StockFollowForm() #how do I prepopulate this if there are already followed Stock objects
return render(request, 'core/test.html',{'form': form})
template:
<div class = "container">
<h2 class = "text-center">Register</h2>
<form method = 'post'>
{% csrf_token %}
{{ form }}
<div class = "text-center">
<br/>
<button class="btn btn-primary" type = 'submit'>Follow/Unfollow Stocks</button>
</div>
</form>
</div>
forms.py:
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from .models import Stock
from django.forms import ModelMultipleChoiceField
class ProfileRegistrationForm(UserCreationForm):
class Meta:
model = User
fields = ('username', 'password1', 'password2', 'email', 'first_name' ,'last_name')
class StockFollowForm(forms.Form):
stocks = forms.ModelMultipleChoiceField(required =False,
widget=forms.CheckboxSelectMultiple,
queryset=Stock.objects.all())
Try specifying the initial value for the stocks field:
form = StockFollowForm(
initial={'stocks': request.user.profile.followed_stocks.all()}
)
For more on this, check out the Django docs on providing initial values to a ModelForm

Django Forms: Cannot get to data to save from ModelForm

I am creating a job board site. Right now I can successfully register an Employer but when I try to create a job listing while logged in as an Employer, the data from the form does not save to the database. I have the following models.py:
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.http import HttpResponse
# Create your models here.
class Employer(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
def __str__(self):
return self.user.first_name
#receiver(post_save, sender=User)
def create_employer(sender, instance, created, **kwargs):
if created:
Employer.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_employer(sender, instance, **kwargs):
instance.employer.save()
class Job(models.Model):
poster = models.ForeignKey(Employer, on_delete=models.CASCADE)
job_title = models.CharField(max_length=50)
establishment_name = models.CharField(max_length = 50)
details = models.TextField(max_length = 2000)
salary = models.CharField(max_length = 20)
address = models.CharField(max_length = 50)
state = models.CharField(max_length = 20)
zip_code = models.CharField(max_length = 10)
def __str__(self):
return self.job_title + " - " + self.establishment_name \
+ ", " + self.poster.user.first_name + " " +self.poster.user.last_name
A user can register as an employer just fine, but I am having problems getting Jobs to save to the database. Once a user registers/logs in as an employer they are redirected to employer_home.html, where an employer can post a job:
{% extends 'core/base.html' %}
{% block body %}
<h1>Post a Job</h1>
<form>
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Post</button>
</form>
{% endblock %}
Here is my forms.py:
from django.forms import ModelForm
from .models import Job
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
class EmployerSignupForm(UserCreationForm):
class Meta:
model = User
fields = ('first_name',
'last_name',
'email',
'username',
'password1',
'password2',)
class JobPostForm(ModelForm):
class Meta:
model = Job
fields= ('job_title',
'establishment_name',
'salary',
'address',
'state',
'zip_code',
)
and here is my employer_view(view to handle Job form):
def employer_home(request):
if request.method == 'POST':
form = JobPostForm(request.POST)
if form.is_valid():
form.save()
return HttpResponse('Working!')
else:
form = JobPostForm()
return render(request, 'core/employer_home.html', {'form': form})
employer_home.html displays a form with no problem, but when the form is submitted none of the data is saved to the database and the return HttpResponse('Working!') is never executed, it simply reloads the empty form. Does anyone know how to fix this?
Add method="POST" in your form. In your view do this:
def employer_home(request):
if request.method == 'POST':
form = JobPostForm(request.POST)
if form.is_valid():
job_object = form.save(commit=False)
job_object.poster = poster_object
job_object.save()
return HttpResponse('Working!')
else:
form = JobPostForm()
return render(request, 'core/employer_home.html', {'form': form})
A good example is shown here: example
Try <form method="post"> in your html template.
By default, the method is get.