I am beginner in django (using django 1.7) and trying to create a form using crispy-forms in order to add new product to db. The problem is, form is working but it is not creating new product in database.
when I logged, if i click to save button nothing happen and shows below in address bar.
http://127.0.0.1:8000/add_product/?csrfmiddlewaretoken=kfGpEA6ZC32Lad9m9uwWZEhElwBGLHPA&csrfmiddlewaretoken=kfGpEA6ZC32Lad9m9uwWZEhElwBGLHPA&Category_IDCategory=66&DealType=Rent&Title=kkjkj&Price=78&Description=kjjk&save=Save
if I logged out and click to save button it directs me to the homepage as I provide in form but still no new product in database.
The problem looks like related to user and csrf, but still couldnt figure out the exact problem even I searched need your help.
models.py
class Product(models.Model):
DealType_Choice = (
("Sale", "Sale"),
("Rent", "Rent"),
("Swap", "Swap"),
("Free", "Free"),
("Announ", "Announ"),
)
DealType = models.CharField(max_length=11, blank=True, choices=DealType_Choice)
Title = models.CharField(max_length=70)
Description = models.TextField(blank=False)
Price = models.IntegerField(max_length=11, null=True)
User_IDUser = models.ForeignKey(User)
Category_IDCategory = models.ForeignKey(Category)
PubDate = models.DateField("Publication Data")
def __str__(self):
return self.Title
views.py
def add_product(request):
product_form= ProductForm(request.POST)
if product_form.is_valid():
form=product_form.save(commit=False)
form.User_IDUser= request.user
form.save()
return HttpResponseRedirect('/')
else:
product_form= ProductForm()
return render(request, 'add_productts.html', {'product_form':product_form})
forms.py
class ProductForm(forms.ModelForm):
Category_IDCategory=forms.ModelChoiceField(queryset=Category.objects.all(), label="Category")
DealType=forms.ChoiceField(widget=forms.Select, choices=Product.DealType_Choice, label="DealType")
Title=forms.CharField(label='Title', max_length=70)
Price=forms.IntegerField(min_value=0, label='Price')
Description=forms.CharField(widget=forms.Textarea(), label="Description")
def __init__(self, *args, **kwargs):
self.helper = FormHelper()
self.helper.form_method = "POST"
self.helper.form_action= "/"
self.helper.layout= Layout(
Field('Category_IDCategory',css_class='input-sm'),
Field('DealType',css_class='input-sm'),
Field('Title',css_class='input-sm'),
Field(PrependedText('Price', 'TL', '.00'),css_class='input-sm'),
Field('Description',css_class='input-sm', rows=5),
FormActions(
Submit('save', 'Save', css_class='btn btn-labeled btn-info'))
)
super(ProductForm, self).__init__(*args, **kwargs)
class Meta:
model=Product
fields= ['Category_IDCategory','DealType', 'Title','Price', 'Description']
template
{% extends "index.html" %}
{% load crispy_forms_tags %}
{% block content %}
<h1>Add Product</h1>{% csrf_token %}
{% crispy product_form %}
{% endblock %}
urls.py
urlpatterns = patterns('',
...
url(r'^add_product/$', add_product),
...
)
I think this is wrong:
self.helper.form_action= "/"
form_action should refer to add_product function:
self.helper.form_action= "/add_product/"
Related
the image will not upload if done thru the form. if the image is uploaded thru the admin interface it works properly.. after several hours of researching the docs and google I cannot figure out whats wrong
if anyone has any clue I would be greatly appreciative
model
class Event(models.Model):
TYPE = [
('CYCLING','cycling'),
('STAIR CLIMB','stair climb'),
('RUNNING','running'),
]
id = models.UUIDField(
primary_key=True,
default=uuid.uuid4,
editable=False
)
event_name = models.CharField('Event Name', max_length=100)
event_location = models.CharField('Event Location', max_length=100)
event_date = models.DateField('Event Date')
event_description = models.TextField('Event Description')
event_type = models.CharField('Event Type', max_length=30, choices=TYPE, default='CYCLING')
event_img = models.ImageField( upload_to="eventImg/", blank=True, null=True )
def __str__(self):
return self.event_name
def get_absolute_url(self):
return reverse('event-detail',args=[str(self.id)])
form.py
class AddEventForm(forms.ModelForm):
class Meta:
model = Event
fields = ('event_name','event_date','event_location','event_type','event_description','event_img')
template
{% extends '_base.html' %}
{% load materializecss %}
{% block title %} Add Event{% endblock title %}
{% block content %}
<div class="container" >
<h1>Add Event </h1><i class = 'material-icons large'>pedal_bike</i><i class = 'material-icons large blue-text'>directions_walking</i><i class = 'material-icons small green-text'>
directions_running</i>
</i>
<form method = 'POST' enctype="multipart/form-data">
{% csrf_token %}
{{form|materializecss}}
<button type = 'submit' class = 'btn waves-effect waves-light amber lighten-2 black-text hoverable'>Add Event
<i class = 'material-icons right'>send</i></button>
</form>
</div>
{% endblock content %}
urls.py
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
# Knight Ryders Admin
path('admin/', admin.site.urls),
# User Management
path('accounts/', include('allauth.urls')),
path('accounts/', include('django.contrib.auth.urls')),
# local apps
path('', include('knightryders_app.urls')),
]+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
I have edited this question and added the views.py file for the form
again any help is appreciated
def add_event(request):
submitted = False
if request.method == 'POST':
form = AddEventForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/Event/List/')
else:
form = AddEventForm()
if 'submitted' in request.GET:
submitted = True
return render(request,'add-event.html', {'form':form, 'submitted':submitted })
You need to pass the request.FILES to the form as well, request.POST only contains the items filled in in the form, but not the files uploaded:
def add_event(request):
submitted = False
if request.method == 'POST':
form = AddEventForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return HttpResponseRedirect('/Event/List/')
else:
form = AddEventForm()
submitted = 'submitted' in request.GET
return render(request,'add-event.html', {'form':form, 'submitted':submitted })
request.POST just contain texting fields not images or files
you need also pass request.FILES for getting file or image.
def add_event(request):
submitted = False
if request.method == 'POST':
form = AddEventForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return HttpResponseRedirect('/Event/List/')
else:
form = AddEventForm()
if 'submitted' in request.GET:
submitted = True
return render(request,'add-event.html', {'form':form,
'submitted':submitted })
I am trying to create a form to submit a blog post on an author detail page, so that the blog post will automatically use the current author as its "blog_author" foreign key. I'm aware that this approach isn't "secure" - it's a project site, and I'm trying to learn a new design pattern.
The Django docs recommended using 1 parent view and 2 subviews to handle get and post respectively (https://docs.djangoproject.com/en/3.0/topics/class-based-views/mixins/).
The page renders fine with the get, but the post gives me an error reading "Page not found (404) - no blog post found matching the query." The exception is raised by my parent view (blog.views.AuthorDetail), but there is no traceback.
Edit: Form should have been a ModelForm from the beginning
Here are my views:
class BlogAuthorDetailView(generic.DetailView):
model = BlogAuthor
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['form'] = BlogSubmitForm()
return context
class BlogSubmit(SingleObjectMixin, FormView):
template_name = 'blogauthor_detail.html'
form_class = BlogSubmitForm
model = BlogPost
def post(self, request, *args, **kwargs):
if not request.user.is_authenticated:
return HttpResponseForbidden()
self.object = self.get_object()
#Should I be overriding form_valid() to use the line above? Not sure if I'm doing my data
#handling in the right place
return super().post(request, *args, **kwargs)
def form_valid(self, form):
blogpost = form.save(commit=False)
blogpost.blog_author = self.object
blogpost.save()
return redirect('blog_author-detail', pk=self.object.id)
class AuthorDetail(View):
def get(self, request, *args, **kwargs):
view = BlogAuthorDetailView.as_view()
return view(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
view = BlogSubmit.as_view()
return view(request, *args, **kwargs)
URLs:
urlpatterns = [
path('', views.index, name='index'),
path('blogs/', views.BlogPostListView.as_view(), name='blogs'),
path('blog/<int:pk>', views.BlogPostDetailView.as_view(), name='blogpost-detail'),
path('bloggers/', views.BlogAuthorListView.as_view(), name='bloggers'),
path('blogger/<int:pk>', views.AuthorDetail.as_view(), name='blog_author-detail'),
path('blog/<int:pk>/create', views.BlogCommentCreate.as_view(), name='comment_create')
]
the template:
{% extends "base_generic.html" %}
{% block content %}
<h1>Title: {{ blogauthor.title }}</h1>
<p><strong>Author:</strong> {{ blogauthor }}</p>
<p><strong>Biography:</strong> {{ blogauthor.biography }}</p>
<p><strong>User:</strong> {{ blogauthor.user }}</p>
<p><strong>Posts:</strong>
{% for blog in blogauthor.blogpost_set.all %}
<p> {{ blog.title }} </p>
{% endfor %} </p>
<form action="" method="post">
{% csrf_token %}
<table>
{{ form.as_table }}
</table>
<input type="submit" value="Submit">
</form>
<div style="margin-left:20px;margin-top:20px">
<h4>Comments: Coming Soon!</h4>
{% endblock %}
Model:
class BlogPost(models.Model):
date_created = models.DateField(blank=False, default = date.today)
blog_author = models.ForeignKey('BlogAuthor', on_delete = models.SET_NULL, null=True)
title = models.TextField(max_length=70)
content = models.TextField(max_length=400, null=False)
class Meta:
ordering = ['date_created']
def get_absolute_url(self):
"""Returns the url to access a particular blog post instance."""
return reverse('blogpost-detail', args=[str(self.id)])
def __str__(self):
return self.title
And the forms.py:
class BlogSubmitForm(forms.Form):
title = forms.CharField()
content = forms.CharField(widget=forms.Textarea(attrs={'cols': 40, 'rows': 8}))
date_created = forms.DateField()
At this point, I suspect that the problem is related to my redirect() call in the form_valid override.
The things I have tried include:
Changing the form’s action from blank to the same URL as in my URL paths (possible I did this wrong)
Changing the code in form_valid() to read form.instance.blog_author = self.object (same exact error message, so I don’t think it’s this)
Fiddling with the form_valid()’s redirect call, including: using self.object instead or a URL, using a hardcoded url, getting rid of the second argument, and changing the 2nd arg to pk=, slug=.
Adding a get_success_url override (don’t really know why this would work)
edit: one of the excepted post calls that showed up in my local server went to blog/blogger/4, which is the url I want. Not sure what the issue is.
This is confusing on how you are using the template. Anyway, I think the simplest solution here is to get the BlogAuthor data from request.user and that is most logical, otherwise, anyone can post anything from another user as long as they can predict their primary key(which is a security hole). Here is how you can try:
from django.contrib.auth.mixins import LoginRequiredMixin
class BlogSubmit(LoginRequiredMixin, CreateView):
template_name = 'blogauthor_detail.html'
form_class = BlogSubmitForm
model = BlogPost
def get_success_url(self):
return reverse('blog_author-detail', pk=self.object.id)
def form_valid(self, form):
form.blog_author = self.request.user.blogauthor # assuming BlogAuthor has OneToOne relation with User
return super(BlogSubmit, self).form_valid(form)
Update
Purpose of FormView is to collect data from Forms, where CreateView is to store and create a new instance. Anyway, you need to change your code like this to make it work:
class BlogSubmit(LoginRequiredMixin, SingleObjectMixin, FormView):
template_name = 'blogauthor_detail.html'
form_class = BlogSubmitForm
model = BlogAuthor
def get_success_url(self):
return reverse('blog_author-detail', pk=self.object.id)
def form_valid(self, form):
self.object = self.get_object()
form.blog_author = self.object
form.save()
return super(BlogSubmit, self).form_valid(form)
Also update the form:
class BlogSubmitForm(forms.ModelForm):
class Meta:
model = BlogPost
fields = ['title', 'date_created', 'content']
FYI, to make SingleObjectMixin work, you need to change the model from BlogPost to BlogAuthor
I created a ModelForm which renders correctly and displayed but whenever i try to submit the form I get a 405 error and the page doesnt redirect to success page.
Ive gone through the django 2.2 documentation trying many different things but nothing seems to work
My code is configured as such the template:
<form enctype="multipart/form-data" action="{% url 'order_thanks' %}"
method="post" novalidate>
{% csrf_token %}
{{ form|crispy }}
<input name="Submit" type="submit" class="btn btn-success" value="Git my
food!"></input>
The model:
from django.db import models
from django.forms import ModelForm, Textarea, Select,
CheckboxSelectMultiple, CheckboxSelectMultiple
from django import forms
BURGER_CHOICES = (("AFBB", "Aurion's Famous Beef Burger"), ("AIPB",
"Aurion's Infamous Pork Burger"), ("AULB", "Aurion's Undiscovered Lamb
Burger"), ("POG", "Pureed Otter Giblets"))
BUN_CHOICES = (("WHITE","White Bread"), ("RYE","Rye"), ("TPOODLE",
"Teacup Poodles"), ("AFOSSIL","Ammonite Fossils"))
TOPPING_CHOICES = (("CHEESE", "Cheese"), ("LETTUCE", "Lettuce"),
("TOMATOE", "Tomatoe"), ("ONION", "Onion"), ("WSHAVE", "Wood Shavings"))
SAUCES_CHOICES = (("OZTS", "Our Zesty Barbaque Sauce"), ("SEZBS",
"Someone Elses Zesty Barbaque Sauce"), ("VS", "Varmint Squeezings"))
EXTRAS_CHOICES = (("P", "Pinapple"), ("SG", "Soylent Green"), ("SB",
"Soylent Blue"), ("MWS", "More Wood Shavings"))
class Order(models.Model):
burger = models.CharField(max_length=50,choices=BURGER_CHOICES )
bun = models.CharField(max_length=50, choices=BUN_CHOICES)
toppings = models.CharField(max_length=60, choices=TOPPING_CHOICES)
sauces = models.CharField(max_length=60, choices=SAUCES_CHOICES)
extras = models.CharField(max_length=60, choices=EXTRAS_CHOICES)
# def get_absolute_url(self):
# return reverse('burger', kwargs={'pk': self.pk})
def __str__(self):
return self.burger
def get_absolute_url(self):
return reverse('order-thanks', kwargs={'pk': self.pk})
class OrderForm(ModelForm):
def __init__(self, *args, **kwargs):
super(OrderForm, self).__init__(*args, **kwargs)
self.fields['toppings'].widget = forms.CheckboxSelectMultiple()
for field_name in self.fields:
field = self.fields.get(field_name)
if field and isinstance(field , forms.TypedChoiceField):
field.choices = field.choices[1:]
self.fields['extras'].widget = forms.CheckboxSelectMultiple()
class Meta:
model = Order
fields = ['burger', 'bun', 'toppings', 'sauces', 'extras']
the view:
class OrderView(CreateView, FormView):
template_name = 'order_form.html'
form_class = OrderForm
success_url = 'order/thanks/'
def form_valid(self, form):
form.instance.created_by = self.request.user
return super().form_valid(form)
def get(self, request):
return Response(code=200)
class OrderThanksView(TemplateView):
template_name = 'order_thanks.html'
the urls:
urlpatterns = [
path('admin/', admin.site.urls),
path('', views.HomePage.as_view(),name='home'),
path('about/', views.AboutPage.as_view(),name='about'),
path('order/', views.OrderView.as_view(),name='order'),
path('order/thanks/',
views.OrderThanksView.as_view(),name='order_thanks'),
]
Appologies I dont know how to display the code correctly in the post.
I added some debugging to the code and it turns out that the form is not valid so the redirect doesnt happen?
===============
I got the redirect working by making the multiple choice checkboxes as blank=True and setting the action in the template to "{% url 'order' %}
There seems to be an issue with the form when you select multiple options with eh check-boxes. Any help would be appreciated.
I am trying to create a online Phone Book for my locality. I am getting problem with the app's entry creation view.
Here is my PhoneEntry model:
# coding=utf-8
from django.urls import reverse_lazy
from django.db import models
from django.template.defaultfilters import slugify
from phonenumber_field.modelfields import PhoneNumberField
class PhoneEntry(models.Model):
# Name of the organisation
org_name = models.CharField(max_length=100, verbose_name="Organisation's Name")
org_details = models.CharField(max_length=500, blank=True, verbose_name="Organisation's Details")
slug = models.SlugField(default='slug', unique=True)
# Verified or not
verified = models.BooleanField(default=False, blank=True)
# Dates when the entry was added and verified
added_date = models.DateField(auto_now_add=True, editable=False)
verified_date = models.DateField(auto_now_add=True)
last_edited_date = models.DateField(blank=True, null=True, auto_now_add=True)
# The phone numbers of the organisation
primary_ph_number = PhoneNumberField(verbose_name="Primary Phone Number")
secondary_ph_number = PhoneNumberField(verbose_name="Secondary Phone Number", blank=True)
def save(self, force_insert=False, force_update=False, using=None,
update_fields=None):
super(PhoneEntry, self).save(force_insert, force_update, using, update_fields)
self.slug = slugify(self.org_name+"-"+str(int(self.id)))
super(PhoneEntry, self).save(force_insert, force_update, using, update_fields)
#staticmethod
def get_absolute_url():
return reverse_lazy('phbook:index')
def __str__(self):
return self.org_name+"-"+str(self.primary_ph_number)
class Meta:
verbose_name_plural = "Phone Entries"
And this the EntryCreateForm:
class EntryAddForm(forms.ModelForm):
"""org_name = forms.CharField(max_length=100, label="Enter your organisation name: ")
org_details = forms.CharField(max_length=100, widget=forms.Textarea,
label="Enter your organisation details: ", required=False)"""
primary_ph_number = PhoneNumberField(label="Enter your primary phone number: ")
secondary_ph_number = PhoneNumberField(label="Enter your secondary phone number: ", required=False)
class Meta:
model = PhoneEntry
exclude = ['slug', 'last_edited_date', 'added_date', 'verified_date', 'verified']
And this the EntryAddView:
class EntryCreateView(CreateView):
model = PhoneEntry
form_class = EntryAddForm
template_name = 'phbook/form.html'
success_url = 'phbook:index'
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
print("Data is", form.instance)
model = form.save(commit=False)
print(model.org_name, model.org_details, model.primary_ph_number, model.secondary_ph_number)
model.save()
return self.get_success_url()
And the template form.html
{% extends 'base.html' %}
{% block head %}
<title>Add your Organisation's Entry | PhoneBook</title>
{% endblock %}
{% block body %}
{% load crispy_forms_tags %}
<form method="post" action="{% url 'phbook:add' %}" enctype="multipart/form-data">
<button type="submit" value="Submit">Submit</button>
{% csrf_token %}
{% crispy form %}
</form>
{% endblock %}
The base.html contains only the static links for the foundation css and js files.
In the EntryCreateView, when the line print("Data is ", form.instance) is executed it produced this result
Please tell me what I am doing here??
You've overridden post on the view, and are therefore bypassing all the calls to validation that the CreateView would normally do. There is rarely any good reason to override the get or post methods; you should always define a more specific method; in this case, form_valid would be more appropriate, if all you want to do is print out the submitted data. If that's just for debugging, then you may not need to override any methods at all.
I am trying to save simple form add_product, I don't have any error but the new product doesn't appear in admin or on a page. I really not sure what I am doing wrong. Any suggestion would be great! Thank you.
my views.py
def add_product(request):
author = request.user
product_form = ProductForm(request.POST, request.FILES, instance=author)
if product_form.is_valid():
form = product_form.save(commit=False)
form.save()
return HttpResponseRedirect('/products/')
else:
product_form = ProductForm()
return render(request, 'products/add_product.html', {'product_form': product_form})
my forms.py
class ProductForm(forms.ModelForm):
class Meta:
model = Product
fields = ('title', 'content', 'picture',)
urls.py
urlpatterns = patterns('',
url(r'^$', views.all, name='all'),
url(r'^add/$', views.add_product, name='add_product'),
url(r'^(?P<slug>[\w-]+)/$', views.single_product, name='single_product'),
)
template: products/add_product.html
<h1>Add Product</h1>
<form method="post" action="" enctype="multipart/form-data"> {% csrf_token %}
{{ product_form.as_p }}
<input type="submit" value="Add">
</form>
models.py
class Product(models.Model):
title = models.CharField(max_length=100)
author = models.ForeignKey(User)
content = models.CharField(max_length=300)
slug = models.SlugField(unique=True)
picture = models.ImageField(upload_to='products/picture/', blank=True)
def __unicode__(self):
return self.title
def get_absolute_url(self):
return reverse('single_product', kwargs={'slug': self.slug})
I fixed my view.py by adding following line :
form.author = request.user
and I removed the first line : author = request.user plus the instance as well.
So now works fine :)
Your code doesn't seem to be valid. And there should be errors.
The first thing that is notice is following:
author = request.user
product_form = ProductForm(request.POST, request.FILES, instance=author)
You are passing user instance as a instance to author form. That doesnt make any sense. For product form instance should a product, not a user. If you want to set a author field you can do following :
form = product_form.save(commit=False)
form.author = author
form.save()
Also its not good to call this variable form, because its not a form anymore, its a product object that is returned by save function.