Prepopulate ModelMultipleChoiceField Django - 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

Related

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>

How to use ModelMultipleChoiceField

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):

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.

Issue extending django User model

I have a website where the user should be able to sign up as a "worker" or a "customer", an uber model type of site. I created the two models WorkerProfile and CustomerProfile and the two forms, but each time I submit either the customer or worker form, the new user gets put in both the Customer profile's and Worker profile's in the database at http://127.0.0.1:8000/admin/ , how do I prevent this from happening?
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
class WorkerProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
university = models.CharField(max_length=30, blank=True)
birth_date = models.DateField(null=True, blank=True)
role = models.CharField(max_length = 10, default = 'USER')
def __str__(self):
return self.user.username
#receiver(post_save, sender=User)
def create_worker_profile(sender, instance, created, **kwargs):
if created:
WorkerProfile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_worker_profile(sender, instance, **kwargs):
instance.workerprofile.save()
class CustomerProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
university = models.CharField(max_length=30, blank=True)
birth_date = models.DateField(null=True, blank=True)
role = models.CharField(max_length = 10, default = 'CUSTOMER')
needLaundryDone = models.BooleanField(default = False)
def __str__(self):
return self.user.username
#receiver(post_save, sender=User)
def create_customer_profile(sender, instance, created, **kwargs):
if created:
CustomerProfile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_customer_profile(sender, instance, **kwargs):
instance.customerprofile.save()
forms.py:
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
class WorkerSignUpForm(UserCreationForm):
#birth_date and university fields need to be declared seperately because they are not apart of User:
birth_date = forms.DateField(help_text='Required. Format: YYYY-MM-DD')
university = forms.CharField()
class Meta:
model = User
fields = ('username',
'email',
'first_name',
'last_name',
'birth_date',
'university',
'password1',
'password2', )
class CustomerSignUpForm(UserCreationForm):
#birth_date and university fields need to be declared seperately because they are not apart of User:
birth_date = forms.DateField(help_text='Required. Format: YYYY-MM-DD')
university = forms.CharField()
class Meta:
model = User
fields = ('username',
'email',
'first_name',
'last_name',
'birth_date',
'university',
'password1',
'password2', )
views.py:
def signup(request):
if request.method == 'POST':
form_worker = WorkerSignUpForm(request.POST)
form_customer = CustomerSignUpForm(request.POST)
if form_worker.is_valid():
user = form_worker.save()
user.refresh_from_db() # load the profile instance created by the signal
user.workerprofile.birth_date = form_worker.cleaned_data.get('birth_date')
user.workerprofile.university = form_worker.cleaned_data.get('university')
user.save() # explicitly save custom fields not in User model
raw_password = form_worker.cleaned_data.get('password1')
user = authenticate(username=user.username, password=raw_password)
login(request, user) # login user after signup
return redirect('home')
elif form_customer.is_valid():
user = form_customer.save()
user.refresh_from_db() # load the profile instance created by the signal
user.customerprofile.birth_date = form_customer.cleaned_data.get('birth_date')
user.customerprofile.university = form_customer.cleaned_data.get('university')
user.save() # explicitly save custom fields not in User model
raw_password = form_customer.cleaned_data.get('password1')
user = authenticate(username=user.username, password=raw_password)
login(request, user) # login user after signup
return redirect('home')
else:
form_worker = WorkerSignUpForm(request.POST)
form_customer = CustomerSignUpForm(request.POST)
return render(request, 'core/signup.html', {'form_worker': form_worker,'form_customer': form_customer })
signup.html:
{% extends 'core/base.html' %}
{% block head %}
<title> Sign Up</title>
{% endblock %}
{% block body %}
<h3>Sign Up As Worker</h3>
<form method="post">
{% csrf_token %}
{{ form_worker.as_p }}
<button type="submit">Sign up</button>
</form>
<h3>Sign Up As Customer</h3>
<form method="post">
{% csrf_token %}
{{ form_customer.as_p }}
<button type="submit">Sign up</button>
</form>
{% endblock %}
Don't use signals here. They both fire on save of User, and each create their related object.
You should remove those signals and instead do this in the view. In the is_valid block for each form you can create only the specific object you need.
if form_worker.is_valid():
user = form_worker.save()
worker = WorkerProfile(user=user)
worker.birth_date = form_worker.cleaned_data.get('birth_date')
worker.university = form_worker.cleaned_data.get('university')
worker.save()
raw_password = form_worker.cleaned_data.get('password1')
...
elif form_customer.is_valid():
user = form_customer.save()
customer = CustomerProfile(user=user)
...
This is normal :
user = models.OneToOneField(User, on_delete=models.CASCADE)
If you call this in both models, so during the save(), it will create both.
What I propose you, is to modify your models. Why don't you just create a model 'Profil' and put a boolean field 'is_customer' True/False ?