saving forms via TemplateView - django

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>

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>

Django Comments Newbie

I started learning Django about a month ago and just finished Django for Beginners by William Vincent. The book ends with Ch.15: Comments and shows how the admin can add comments to posts.
Q: Can someone, please, show me or point me in the right direction as to how I can let registered users also add comments to posts? Is there perhaps a 3rd party app for that?
What I have so far:
Models:
class Article(models.Model):
title = models.CharField(max_length=255)
body = models.TextField()
date = models.DateTimeField(auto_now_add=True)
image = models.ImageField(upload_to='images/', null=True, blank=True, height_field=None, width_field=None)
upload = models.FileField(upload_to='files/', null=True, blank=True)
author = models.ForeignKey(
get_user_model(),
on_delete=models.CASCADE,
)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('article_detail', args=[str(self.id)])
class Comment(models.Model):
article = models.ForeignKey(Article, on_delete=models.CASCADE, related_name='comment')
comment = models.CharField(max_length=140)
date = models.DateTimeField(auto_now_add=True)
author = models.ForeignKey(
get_user_model(), on_delete=models.CASCADE,
)
def __str__(self):
return self.comment
def get_absolute_url(self):
return reverse('article_list')
forms.py
class PostForm(forms.ModelForm):
class Meta:
model = Article
fields = ('title', 'body', 'image', 'upload')
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ('comment', 'author')
Views:
class ArticleListView(LoginRequiredMixin, ListView):
model = Article
template_name = 'article_list.html'
comment_form = CommentForm
login_url = 'login'
class ArticleDetailView(LoginRequiredMixin, DetailView):
model = Article
template_name = 'article_detail.html'
login_url = 'login'
class ArticleUpdateView(LoginRequiredMixin, UpdateView):
model = Article
fields = ('title', 'body', 'image', 'upload')
template_name = 'article_edit.html'
login_url = 'login'
def dispatch(self, request, *args, **kwargs):
obj = self.get_object()
if obj.author != self.request.user:
raise PermissionDenied
return super().dispatch (request, *args, **kwargs)
class ArticleDeleteView(LoginRequiredMixin, DeleteView):
model = Article
template_name = 'article_delete.html'
success_url = reverse_lazy('article_list')
login_url = 'login'
def dispatch(self, request, *args, **kwargs):
obj = self.get_object()
if obj.author != self.request.user:
raise PermissionDenied
return super().dispatch (request, *args, **kwargs)
class ArticleCreateView(LoginRequiredMixin, CreateView):
model = Article
form_class = PostForm
template_name = 'article_new.html'
login_url = 'login'
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
URLs:
urlpatterns = [
path('<int:pk>/edit/', ArticleUpdateView.as_view(), name='article_edit'),
path('<int:pk>/', ArticleDetailView.as_view(), name='article_detail'),
path('<int:pk>/delete/', ArticleDeleteView.as_view(), name='article_delete'),
path('', ArticleListView.as_view(), name='article_list'),
path('new/', ArticleCreateView.as_view(), name='article_new'),]
Thank you for your attention.
Solved. In my views.py I added the following function:
def add_comment(request, pk):
article = get_object_or_404(Article, pk=pk)
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.article = article
comment.save()
return redirect('article_detail', pk=article.pk)
else:
form = CommentForm()
return render(request, 'add_comment.html', {'form': form})
Then the following .html file was added to templates:
add_comment.html
{% extends 'base.html' %}
{% block content %}
<h4>Add a Comment</h4>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<p>{{ form.as_p }}</p>
<button type="submit" class="btn btn-success">Submit</button>
</form>
{% endblock content %}
P.S.: Initially I was getting an ImportError: cannot import name 'add_comment' from 'articles.views'.
I thought it was a circular import problem and what worked for me was just getting the def add_comment indentation right.

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

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

__init__() got an unexpected keyword argument 'user' when I try to filter

I would like to filter through the restaurants that the request.user has done. following the docs but i keep getting __init__() got an unexpected keyword argument user when I try to filter
forms.py
from .models import Restaurant
from .models import Item
from django import forms
class LocationCreate(forms.ModelForm):
class Meta:
model = Item
fields = [
'restaurant'
'category',
'food_name'
]
def __init__(self, user=None, *args, **kwargs):
super(ItemCreate, self).__init__(*args, **kwargs)
self.fields['restaurant'].queryset = Restaurant.objects.filter(owner=user)
models.py
class Restaurant(models.Model):
restaurant_name = models.CharField(max_length=250)
restaurant_photo = models.ImageField(upload_to='roote_image')
category = models.ManyToManyField(Category)
timestamp = models.DateTimeField(auto_now_add=True, null=True)
updated = models.DateTimeField(auto_now=True, null=True)
owner = models.ForeignKey(User)
def get_absolute_url(self):
return reverse('post:detail', kwargs={'pk': self.pk})
class Item(models.Model):
restaurant= models.ForeignKey(Roote, on_delete=models.CASCADE, null=True)
food_name = models.CharField(max_length=1000)
category = models.CharField(max_length=250)
owner = models.ForeignKey(User)
def __str__(self):
return self.food_name
def get_absolute_url(self):
return reverse('post:detail', kwargs={'pk': self.pk})
views.py
class ItemCreate(CreateView):
model = Item
fields = ['restaurant','category ', 'food_name ']
success_url = reverse_lazy('post:index')
def form_valid(self, form):
if form.is_valid():
roote = restaurant.objects.filter(owner =self.request.user)
instance = form.save(commit=False)
instance.owner = self.request.user
return super(ItemCreate, self).form_valid(form)
def get_form_kwargs(self):
kwargs = super(ItemCreate, self).get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
detail.html
{% block body %}
<div class="col-sm-6 col-sm-offset-3">
<img src="{{ restaurant.restaurant_photo.url }}" style="width: 250px;" >
<h1>{{ restaurant.restaurant_name }}</h1>
{% for item in restaurant.item_set.all %}
{{ item.food_name }}: {{ item.category}}
<br>
{% endfor %}
The form works without the filter but it brings in every instance of a restaurant that has been made in the web site
full error:
return form_class(**self.get_form_kwargs())
TypeError: __init__() got an unexpected keyword argument 'user'
You forgot to add form_class attribute to your view
class ItemCreate(CreateView):
model = Item
success_url = reverse_lazy('post:index')
form_class = LocationCreate # <- here
def form_valid(self, form):
if form.is_valid():
roote = restaurant.objects.filter(owner=self.request.user)
instance = form.save(commit=False)
instance.owner = self.request.user
return super(ItemCreate, self).form_valid(form)
def get_form_kwargs(self):
kwargs = super(ItemCreate, self).get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
According to the docs, this is the signature of the __init__ method for a ModelForm:
def __init__(self, *args, **kwargs)
See that there is no user? This is what the error message is telling you.
If you want to get the user, try via self.request.user (or something similiar, depending on what middlewares you use).
Hope that helps!