I am struck with inline formsets in Django. Each time I submit the formset it is considered invalid and hence the data doesn't get saved. I am a newbie in full-stack development and am learning Django. I am following Dennis Ivy's playlist on youtube and coding along with him. It is kind of an E-commerce portal where people can order stuff. Here is a link to the video where he implements inline formsets Video. It was working fine when I accepted orders through normal form i.e. one order at a time. I have done exactly as he did in his video. I also tried consulting my friends who are learning with me and also asked my mentor about it but no one could figure out what is wrong here. I browsed through the documentation but that too didn't help. Please help me out in fixing this.
Github Repo link
views.py
from django.forms import inlineformset_factory
def createOrder(request, pkCrteOrder):
OrderFormSet = inlineformset_factory(customer, order, fields=('product','status'), extra=7)
CustomerOrderOwner = customer.objects.get(id=pkCrteOrder)
formSet = OrderFormSet(queryset = order.objects.none(), instance=CustomerOrderOwner)
if(request.method == 'POST'):
print("post request detected")
formSet = OrderFormSet(request.POST, instance=CustomerOrderOwner)
if formSet.is_valid():
formSet.save()
return(redirect('/'))
else:
print("formset was invalid")
context = {'formSet': formSet}
return(render(request, 'accounts/orderForm.html', context))
Brief explaination: From a particular customer's page we can place order. So pkCrteOrder represents the id of customer. I fetch the customer and pass it as instance for the formset and then send the formset to template. If form is submitted I check if it's valid and then save else i print "formset was invalid"
order model:
class order(models.Model):
STATUS = (
('Pending', 'Pending'),
('Out for delivery', 'Out for delivery'),
('Delivered', 'Delivered'),
)
customer = models.ForeignKey(customer, null = True, on_delete=models.SET_NULL)
product = models.ForeignKey(products, 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)
template:
{% extends 'accounts/base.html' %} {% load static %} {% block content %}
<div class="row">
<div class="col-md-6">
<div class="card card-body">
<form method="POST" action="">
{% csrf_token %}
{{formset.management_form}}
{% for form in formSet %}
{{form}}
<hr />
{% endfor %}
<input type="submit" value="Submit" />
</form>
</div>
</div>
</div>
{% endblock content %}
Thank you
In your template you have {{formset.management_form}}. But really the variable containing the forms you are sending from the view is called fromSet (notice the capital S). So change that code into {{formSet.management_form}} and it should work fine.
Related
Well, I am creating a user profile where the user can see his all posts which he has been uploaded. But I don't understand one thing that how could I possibly grab the fields of Post model from Posts/models.py and show them on the template which I have created in another app (Profiles) templates.
The reason I am trying to access them on other app is that I want to show them in the userprofile.html template. Just like Facebook posts. And please tell me if you know that it is not possible with django?
posts/models.py :
class Post(models.Model):
username = models.ForeignKey(User, verbose_name=("user name"), on_delete=models.CASCADE)
description = models.CharField(('Description'),max_length=250)
title = models.CharField(('Content Title'), max_length=250)
create_date = models.DateTimeField(default = timezone.now)
image_data = models.ImageField(upload_to='User_Posts', height_field=None, width_field=None, max_length=None)
def __str__(self):
return self.title
profiles/views.py
from posts.model import Post
from django.views.generic import ListView
class UserPostListView(ListView):
model = Post
context_object_name = 'userpost_list'
template_name = 'profiles/userprofile.html'
def get_queryset(self):
user = get_object_or_404(User, username = self.kwargs.get('username'))
return Post.object.filter(username = user).order_by('-create_date')
profiles/templates/profiles/userprofile.html
<div class="jumbotron">
{% for post in userpost_list %}
<div class="post">
<h1>{{ posts.post.title }} <img src="" alt="not found" height="60" width="60" style="float:right ;border-radius: 20px;" ></h1>
<div class="date">
<p>
<!-- Published on: {{ object.author.post.create_date|date:"D M Y" }} -->
</p>
</div>
</div>
{% endfor %}
</div>
</div>
You can access any app from any other app. You just need to do the necessary model imports which you are doing. Looks like you just need to tweak your line of code in the template from:
<h1><a href="">{{ posts.post.title }}...
to:
<h1><a href="">{{ post.title }}...
and when you decide to use it.
<!-- Published on: {{ object.author.post.create_date|date:"D M Y" }} -->
to:
<!-- Published on: {{ post.create_date|date:"D M Y" }} -->
The reason is that your queryset is returning a dataset of the Post model. So you are already in it.
It just done by importing model from the app you want to use model to other app. And that it. This is python OOP(object oriented programming) concept.
I try to remove comment so, I tried the first time by the class-based view then I hashed it to try the second way by normal function to know what's going on here. so, when I try to delete the comment by ID nothing does happen it's just directing me to the web page without deleting the comment so in this case the program runs but doesn't remove the object so, what is going on here?
Note: the posts and comments on the same page and slug field on that page are following by post not comment.
if the title of the post is: new title so, the slug will be new-title depending on the post
question_view.html
<div class="user-answer">
<div class="row">
<div class="col-xs-12">
{% for comment in my_question.comment_set.all %}
<div class="comments">
<div class="col-xs-0">
<div class="avatar">
<a href="{% url 'account:view_profile' comment.username %}">
<img class="img-circle img-thumbnail" style="width:50px; height: 50px;" src="{{ comment.logo }}">
</a>
</div>
</div>
<div class="col-xs-10">
<!-- --Comment itself-- -->
<div class="user_comment">
<p>{{ comment }}</p>
<div class="fa fa-caret-left comment-arrow"></div>
</div>
<!-- start Options in comment -->
<div class="sub-options">
{% if request.user.username == comment.username %}
<!-- --Edit comment-- -->
<div class="edit-comment">
<a>Edit</a>
</div>
<!-- --Delete comment-- -->
<div class="delete-comment">
<form method="post" action="{% url 'community:delete_comment' comment.pk %}">
{% csrf_token %}
<input type="hidden" name="delete-comment" value="{{ comment.comment }}">
<input type="submit" value="delete">
</form>
</div>
{% endif %}
<!-- end Options in comment -->
<!-- --comment Date-- -->
<div style="display: inline-block;color: #8e8e8e" class="comment-date">
<p>{{ comment.date|time }}</p>
</div>
</div>
</div>
<div class="clearfix"></div>
</div>
{% endfor %}
</div>
</div>
</div>
views.py
# Delete post
# class DeleteComment(DeleteView, SingleObjectMixin):
# model = Comment
# pk_url_kwarg = 'pk'
# template_name = 'community/question_view.html'
# queryset = Comment.objects.all()
#
# def get_success_url(self):
# title = UserAsking.objects.get(title=self.object)
# slug = UserAsking.objects.get(title=title).ask_slug
# return reverse_lazy('community:question_view', kwargs={'user_slug': slug})
#
# def get_object(self, queryset=None):
# request_comment = self.request.POST['delete-comment']
# return self.get_queryset().filter(pk=request_comment).get()
def delete_comment(request, pk):
if request.method == 'POST':
comment = Comment.objects.get(pk=pk)
del comment
return redirect('community:user_questions')
urls.py
urlpatterns = [
# path('delete-comment/<int:pk>/', views.DeleteComment.as_view(), name="delete_comment"),
path('delete-comment/<int:pk>/', views.delete_comment, name="delete_comment"),
]
models.py
class Comment(models.Model):
userasking = models.ForeignKey(UserAsking, on_delete=models.CASCADE)
comment = models.TextField(max_length=500, blank=True)
date = models.DateTimeField(auto_now_add=True)
userprofile = models.ForeignKey(UserProfile, on_delete=models.CASCADE, default=1)
name = models.CharField(max_length=30, blank=False, default='empty')
logo = models.ImageField(upload_to='images/', default='images/default-logo.jpg', blank=True)
username = models.CharField(max_length=30, blank=False, default='empty')
def __str__(self):
return self.comment
I hope if you can explain by class based-view what's happening I will appreciate that.
note that: if you could understand exactly what's happening you will know that is no error appears to me, therefore, I get no exception or traceback. thank you in advance.
Try this:
def delete_comment(request, pk):
if request.method == 'POST':
comment = Comment.objects.get(pk=pk).delete()
return redirect('community:user_questions')
Your function only deletes the object but not the database entry since you don't trigger a valid SQL operation (delete in this case).
You just delete the object comment again which was assigned previously, but you don't affect the database entry:
def delete_comment(request, pk):
if request.method == 'POST':
comment = Comment.objects.get(pk=pk)
del comment
return redirect('community:user_questions')
More on delete() in the official docu:
Deleting objects¶
Update on your comment:
You can't use Python's del statement to interact with database entries in Django.
Pythons del statement is used to delete objects initially created by Python like lists, variables, etc. etc.
In order to interact with your database in Django, you have to use the toolbox of Django's built-in Model instance which basically translates raw SQL operations into easy to use methods.
So maybe you can adapt a proper wording to highlight the differences by calling database "objects" entries and python objects: well, objects..
However, Django still offers the option to use raw SQL as fallback.
I am looking to create a dropdown in a template where the values of the dropdown come from a field (reference) within my Orders model in models.py. I understand creating a dropdown where the values are set statically, but since I am looking to populate with values stored in the DB, I'm unsure of where to start.
I've created the model and attempted playing around with views.py, forms.py and templates. I am able to get each of the order numbers to display but not in a dropdown and I am struggling with how to write my template.
models.py
from django.db import models
class Orders(models.Model):
reference = models.CharField(max_length=50, blank=False)
ultimate_consignee = models.CharField(max_length=500)
ship_to = models.CharField(max_length=500)
def _str_(self):
return self.reference
forms.py
from django import forms
from .models import *
def references():
list_of_references = []
querySet = Orders.objects.all()
for orders in querySet:
list_of_references.append(orders.reference)
return list_of_references
class DropDownMenuReferences(forms.Form):
reference = forms.ChoiceField(choices=[(x) for x in references()])
views.py
def reference_view(request):
if request.method == "POST":
form = references(request.POST)
if form.is_valid():
form.save()
return redirect('index')
else:
form = references()
return render(request, 'proforma_select.html', {'form': form})
proforma_select.html
{% extends 'base.html' %}
{% block body %}
<div class="container">
<form method="POST">
<br>
{% for field in form %}
<div class="form-group row">
<label for="id_{{ field.name }}" class="col-2 col-form-label"> {{ field.label }}</label>
<div class="col-10">
{{ field }}
</div>
</div>
{% endfor %}
<button type="submit" class="btn btn-primary" name="button">Add Order</button>
</form>
</div>
{% endblock %}
All I get when I render the template is each of the reference #s listed out but NOT within a dropdown. This leads me to believe my problem is mainly with the template, but I'm unsure as I am new to using Django.
Are you using Materialize CSS? If yes, then Django forms renders dropdowns differently from how Materialize expects them. So you will want to override the form widget. You can do something like so:
forms.py:
class DropDownMenuReferences(forms.Form):
reference = forms.ChoiceField(choices=[(x) for x in references()],
widget=forms.Select(choices=[(x) for x in references()], attrs={'class':
'browser-default'}))
This overrides the parameters passed into html. You can also pass any name tags in the attrs too.
The issue:
https://github.com/Dogfalo/materialize/issues/4904
I am trying to save multiple fields of data. I've also changed the database connection from the default sqlite3 to MySQL. And I don't know how to do this
Here's my views.py
def customerview(request):
if request.POST:
form = CustomerForm(request.POST)
if form.is_valid():
if form.save():
return redirect('sales')
else:
return redirect('index')
else:
return redirect('index')
else:
form = CustomerForm
return render(request, 'customer.html', {'form':form})
def salesview(request):
if request.POST:
form = SalesForm(request.POST)
if form.is_valid():
if form.save():
return redirect('index')
else:
return redirect('index')
else:
return redirect('index')
else:
form = SalesForm
data = Customer.objects.latest('id')
return render(request, 'sales.html', {'form':form, 'range':range(data.number_of_transactions)})
Here's my models.py
class Customer(models.Model):
customer_name = models.CharField(max_length=200)
number_of_transactions = models.IntegerField()
class Sales(models.Model):
product_type = models.CharField(max_length=100)
product_code = models.CharField(max_length=100)
product_size = models.CharField(max_length=100)
product_quantity = models.IntegerField()
Here's my brands.html
<form class="form" role="form" action="" method="post"> {% csrf_token %}
{% for i in range %}
<div class="col">
<div class="col-sm-3">
<div class="">
{{ form.product_type | add_class:'form-control' }}
<label for="regular2">Product Type</label>
</div>
</div>
<div class="col-sm-3">
<div class="">
{{ form.product_code | add_class:'form-control' }}
<label for="regular2">Product Code</label>
</div>
</div>
</div>
{% endfor %}
<div class="col-md-12">
<hr>
<div class="card-actionbar-row">
<input type="submit" class="btn btn-flat btn-primary ink-reaction" value="SUBMIT">
</div>
</div>
</form>
The idea is to get the customer details and number of transactions to be performed then that determines the number of fields to be displayed in the sales view. And that works fine.
The problem is to get each of the transactions to be saved in the database. When I submit and check my database tables, only one transaction is saved.
It's clear that you're trying to run before you can walk here.
Firstly, you should concentrate on getting a simple list view to work, without getting confused about the additional complexity involved in displaying a list in a form view. So, make your view inherit from ListView, and remove all the methods. Then fix your template, so that it iterates over stock_list or object_list rather than just stock.
Secondly, once you've got that working, you could try to integrate it with a form. When you do that, learn what methods to override. get_queryset must return a queryset, it should not render a template. In any case, you should almost never need to render a template manually in a class-based view, because the existing logic will do that for you. And if you want to add a queryset to the template context in a create view, for example, you should be overriding get_context_data; which needs to return a dictionary.
Thirdly, if at some point you do need to render a template manually, read the documentation to learn the order of parameters to render: it is request, template_name, context, not as you have it.
Spent days reading, making relevant to my structure and combining/testing many suggestions...
Goal: Read data from contacts model, select records with Category: Sales,
display sales contacts, click on one email address, pass email address back to generic form (instead of hard-coded address - see the form below)
I am looking to make the email form recipient 'model dependent'. That way it can be flexible and the email addresses can be maintained in the DB.
...Model...
from django.db import models
class contacts(models.Model):
category = models.CharField(verbose_name="Category", max_length=30)
seq = models.IntegerField(verbose_name="Order")
position = models.CharField(verbose_name="Position", blank=True, max_length=50)
name = models.CharField(verbose_name="Name", blank=True, max_length=100)
email = models.CharField(verbose_name="Email", max_length=100)
class Meta:
ordering = ['category', 'seq'] #sets order in Django Admin
verbose_name_plural = "contacts" #stops contactss in Django Admin
Django Admin Add/Change works as intended.
...Sample Data...
Inquiry, 1, {Position blank}, {Name blank}, inquiry#domain.com
Sales, 1, Sales Desk, {Name blank}, salesdesk#domain.com
Sales, 2, Sales Manager, John Smith, johnsmith#domain.com
Found the following about forms, explored the self, and put them together to pass an email address to the form. This is the end goal.
The following works to set up the generic email form (except default_recepient is hard-coded):
...forms.py...
from django import forms
class ContactForm(forms.Form):
def __init__(self):
super(ContactForm, self).__init__()
self.default_recepient = '<pass email address here>' #Any address hard coded here goes to email form
self.sender = forms.EmailField(max_length=50, required=True)
self.subject = forms.CharField(max_length=100, required=True)
self.message = forms.CharField(widget=forms.Textarea(attrs={'cols': 200, 'rows': 12}))
self.cc_myself = forms.BooleanField(required=False)
...email.html...
{% block body %}
<header>
Home Logout<br><br>
<h1>Test Site</h1>
<h2>Email to: {{form.default_recepient}}<h2>
</header>
<form action="/email/" method="post">
{% csrf_token %}
<p><label for="id_sender">Sender:</label>
<input type="text" name="sender" id="id_sender" maxlength="50" />
<label for="id_cc_myself">cc Myself:</label>
<input type="checkbox" name="cc_myself" id="id_cc_myself" /></p>
<p><label for="id_subject">Subject:</label>
<input id="id_subject" type="text" name="subject" maxlength="100" /></p>
<p><label for="id_message"></label>
Message:<br>
<textarea name="message" id="id_message" cols=200 rows=12>
</textarea></p>
<p>
<div class="form-actions">
<button type="submit">Send</button>
</div>
</form>
{% block content %}{% endblock %}
{% endblock %}
Found and explored various examples of using dictinaries and came up with the following:
...sales_views.py...
from django.shortcuts import render_to_response
from django.contrib.auth.decorators import login_required
from portal.models import contacts
#login_required
def support_page(request):
contacts.object.all()
context = RequestContext(request)
category_list = contacts.objects.filter(category='Sales').order_by('category', 'seq')
context_dict = {'contacts': category_list}
return render_to_response('portal/support.html', context_dict, context)
...available_contacts.html...
{% if contacts %}
{% for contact in contacts %}
<p>
{{ contact.position}} <br>
{{ contact.name }} <br>
Email: {{ contact.email }}
{% endfor %}
{% else %}
<strong>There are no available contacts.</strong>
{% endif %}
However it will display all 3 data samples and ignores the 'Sales Only' from the objects.filter. I tried various methods like deleting from the dictionary and creating another dictionary. Same result: all 3 listing.
Started with Django Polls Tutorial and found Randall Degges on modifying the login (#login_required, and other login aspects...) Excellent job Randall!
I am not sure which direction to go from here. Some things get me so far, but not all the way. I realize I may require something like an inquiry_views.py to start the inquiry list off, but hopefully the other pieces can be static.