Django Formset issue - POST doesn't seems to work - django

I'm trying to use django formset for the first time in order to combine both forms on the same page.
My form is well displayed but I don't overvome to save data in my database. When I click on submit button, nothing happens.
This is my model.py file :
class Publication(models.Model):
title = models.CharField(max_length=512, verbose_name=_('title'), null=False)
category = models.ForeignKey(Category, verbose_name=_('category'), null=False)
creation_date = models.DateTimeField(auto_now_add=True, verbose_name=_('creation date'), null=False)
modification_date = models.DateTimeField(auto_now=True, verbose_name=_('modification date'), null=False)
class Meta:
verbose_name = _('publication')
verbose_name_plural = _('publication')
def __str__(self):
return f"{self.title}"
class Document(models.Model):
FORMAT_CHOICES = (
('pdf', 'pdf'),
('epub', 'epub'),
)
format = models.CharField(max_length=10, verbose_name=_('format'), choices=FORMAT_CHOICES, null=False)
title = models.CharField(max_length=512, verbose_name=_('title'), null=False)
publication = models.ForeignKey(Publication, verbose_name=_('publication'), null=False)
upload = models.FileField(upload_to='media/', default="")
creation_date = models.DateTimeField(auto_now_add=True, verbose_name=_('creation date'), null=False)
modification_date = models.DateTimeField(auto_now=True, verbose_name=_('modification date'), null=False)
class Meta:
verbose_name = _('document')
verbose_name_plural = _('document')
def __str__(self):
return f"{self.age_id} : {self.title}"
My form file is very simple too with defined Formset :
class PublicationForm(forms.ModelForm):
class Meta:
model = Publication
fields = ('title', 'category')
class DocumentForm(forms.ModelForm):
class Meta:
model = Document
fields = ['publication', 'format', 'title', 'upload']
DocumentFormSet = inlineformset_factory(Publication, Document, form=DocumentForm, extra=1)
My view is a bit more complicated :
class PublicationCreateUpdateView(AgePermissionRequiredMixin, UpdateView):
""" Display a form to create or update a publication
Only for age admin.
**Context**
``subtitle``
Title of the page
**Template:**
:template:`app/category_form.html`
"""
model = Publication
form_class = PublicationForm
success_url = reverse_lazy('app:app-publication-list')
template_name = 'app/publication_form.html'
permission_required = 'publication.change_webapplication'
def get_object(self, queryset=None):
try:
return super(PublicationCreateUpdateView, self).get_object(queryset)
except AttributeError:
return None
def get_title(self):
if self.object:
return _('Edit publication: ') + str(self.object)
return _('Add new publication')
def get_context_data(self, **kwargs):
context = super(PublicationCreateUpdateView, self).get_context_data(**kwargs)
if self.request.POST :
context['documents'] = DocumentFormSet(self.request.POST)
else :
context['documents'] = DocumentFormSet()
context.update({
'subtitle': self.get_title(),
})
return context
def form_valid(self, form):
context=self.get_context_data()
documents = context['documents']
with transaction.atomic():
self.object = form.save()
if documents.is_valid():
documents.instance = self.object
documents.save()
return super(DocumentCreateUpdateView, self).form_valid(form)
And finally my template looks like this :
{% extends "publication/base_backend.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block main %}
<form method="post" novalidate>
{% csrf_token %}
{% crispy form %}
{{ documents.management_form }}
{{ documents.non_form_errors }}
{% crispy documents %}
<br>
<input type="submit" class="btn btn-default" value="{% trans 'Save' %}" />
{% trans 'Cancel' %}
</form>
{% endblock main %}
I don't understand where I could make a mistake, furthermore I'm pretty new with Django Class Based View.

Related

OneToOne related other model field converted to boolean field check box in form to show or hide model fields doesn’t work

I have these two django blog models in models.py
`
class Snippet(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
created = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=100, blank=True, default='')
code = models.TextField()
...
class Post(models.Model):
# id = models.AutoField(primary_key=True) # the same field in comment model for multi-inheritance (post_id)
id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True, primary_key=True)
slug = models.SlugField(max_length=200, db_index=True, unique=True, editable=False) # add unique=True in slug (never repeat)
title = models.CharField(max_length=200, db_index=True, default='')
tag = models.ManyToManyField(Tag, blank=True, help_text="Select a tag for this post", related_name='post_tags')
snippet = models.OneToOneField(Snippet, on_delete=models.CASCADE, related_name='post_snippets')
...
and i have forms to add new post as follows
class PostModelChoiceField(ModelChoiceField):
def label_from_instance(self, obj):
return "Post #%s) %s" % (obj.id, obj.title)
class SnippetForm(forms.ModelForm):
post = PostModelChoiceField(queryset=Post.objects.all())
class Meta:
model = Snippet
fields = '__all__'
class PostForm(forms.ModelForm):
class Meta:
model = Post
#fields = '__all__'
#fields = ['title', 'tag', 'maintainer', 'post_img', 'content', 'snippet', 'genre', 'language', 'video', 'post_type', 'urls', 'views', 'status' ]
labels = {'snippet': _('Add Code'),}
exclude = ('creator', 'slug',)
widgets = {
'snippet': forms.CheckboxInput(attrs={'type': 'checkbox', 'class': 'checkbox', 'id': 'post-snippet'})
}
def clean(self):
snippet = self.cleaned_data.get('snippet')
if snippet:
self.fields_required(snippet.title, snippet.code, snippet.title, snippet.linenos, snippet.language, snippet.style, snippet.highlighted) # ['title', 'code', 'linenos', ....]
else:
self.cleaned_data['snippet'] = False
return self.cleaned_data
def __init__(self, *args, **kwargs):
super(PostForm, self).__init__(*args, **kwargs)
self.queryset = Post.objects.filter(snippet=True)
and views logic to render template
def add_post(request):
if request.method == 'POST':
post_form = PostForm(request.POST, request.FILES, instance=request.user)
snippet = post_form.cleaned_data['snippet']
if snippet:
#snpt = modelformset_factory(Snippet, fields=('title', 'code', 'linenos', 'language', 'style', 'highlighted'))
snpt = Snippet.objects.create(post = request.post, snippet_id = request.post.id)
snippet_form = SnippetForm(request.POST, instance=snpt)
if post_form.is_valid() and snippet_form.is_valid():
post = post_form.save(commit=False)
snpt = snippet_form.save(commit=False)
post.creator = request.user
post.snippet = snpt
post.slug = slugify(post_form.cleaned_data['title'])
post.save() and snpt.save()
obj = post_form.instance
alert = True
return redirect('blog:post_list')
#return render(request, "add_post.html",{'obj':obj, 'alert':alert})
#return HttpResponseRedirect('blog/post_list/success/')
else:
post_form = PostForm()
return render(request, 'blog/add_post.html', {'form': post_form})
`
Now i can’t get the snippet fields in my template when i tick the check box in the template
Here is the form
<form method='POST' class="form" enctype='multipart/form-data'>
{{ form.non_field_errors }} {% csrf_token %} {% for field in form %}
<div class="apply">
{% if field.errors %}
<ol>
{% for error in field.errors %}
<li><strong>{{ error|escape }}</strong></li>
{% endfor %}
</ol>
{% endif %} {% if field.help_text %}
<p class="help">{{ field.help_text|safe }}</p>
{% endif %}
</div>
{% endfor %} {% bootstrap_form form %}
<button class="boxed-btn3 w-100" type="submit">Post</button>
</form>
what’s wrong in this logic why the snippet form doesn’t show up in the template and how to get it live immediately when i check the boolean field add code (snippet) in the page form
please help me
i tried to get all the Snippet model fields into add post model form to show all fields in one form
but can't get the fields while i have all post model fields rendered well but when i checked the
check box field snippet that has been converted into boolean in post form , nothing happens

Djago time widget not showing up

All I want to do is add time widget to my form so I can easily pick the time. Everything is very simple, the page is loading but the widgets don't show up. No error nothing. I am thinking maybe I didn't set up the form widgets correctly but not sure what I did wrong. Here is my Forms.py-
from django.contrib.admin import widgets
from django.contrib.admin.widgets import AdminDateWidget, AdminTimeWidget, AdminSplitDateTime
class WorkOutForm(ModelForm):
class Meta:
model = WorkOut
fields = '__all__'
widgets={
'start':AdminTimeWidget(),
'end':AdminTimeWidget(),
}
Here is the Models.py. You will notice "start" and "end" fields are timefield-
class WorkOut(models.Model):
date=models.DateField(auto_now_add=True, auto_now=False, blank=True)
day=models.DateField(auto_now_add=True, auto_now=False, blank=True)
start=models.TimeField(null=True)
name=models.CharField(max_length=100, choices=move)
weight=models.CharField(max_length=100, blank=True)
rep=models.CharField(max_length=100, blank=True)
pedal= models.CharField(max_length=100, blank=True)
stretchtype =models.CharField(max_length=100, blank=True)
end=models.TimeField(null=True)
note=models.TextField(max_length=300, blank=True)
def __str__(self):
return self.name
And here are the views linked to it even though I don't think it has much relevance-
def workout(request):
form=WorkOutForm()
if request.method=="POST":
form=WorkOutForm(request.POST)
if form.is_valid():
form.save()
context={'form':form}
return render(request, 'myapp/enter_workout.html', context)
def update_workout(request, pk):
order=WorkOut.objects.get(id=pk)
form=WorkOutForm(instance=order)
if request.method=='POST':
form=WorkOutForm(request.POST, instance=order)
if form.is_valid():
form.save()
context={'form':form}
return render(request, 'myapp/enter_workout.html', context)
And the form on HTML page is also very basic,so don't think there is any issue there either-
<form action="" method="POST">
{% csrf_token %}
{{form}}
<input type="submit" value="Submit">
</form>
What have I done wrong here? How can I make those widgets to show up?
You can try to fill the default values with the current time.
from datetime import datetime
class WorkOut(models.Model):
move = (("1", "Tom"), ("2", "Sara"), ("3", "Emilia"),)
date = models.DateField(auto_now_add=True, auto_now=False, blank=True)
day = models.DateField(auto_now_add=True, auto_now=False, blank=True)
start = models.TimeField(default=datetime.now, null=True)
name = models.CharField(max_length=100, choices=move)
weight = models.CharField(max_length=100, blank=True)
rep = models.CharField(max_length=100, blank=True)
pedal = models.CharField(max_length=100, blank=True)
stretchtype = models.CharField(max_length=100, blank=True)
end = models.TimeField(default=datetime.now,null=True)
note = models.TextField(max_length=300, blank=True)
def __str__(self):
return self.name
Update 22.10.2022
Made fields with time selection on bootstrap.
For this you need to install:
pip install django-bootstrap4
pip install django-bootstrap-datepicker-plus
In the WorkOutForm class in init set the styles for all fields.
forms.py
from bootstrap_datepicker_plus.widgets import TimePickerInput
class WorkOutForm(ModelForm):
class Meta:
model = WorkOut
fields = "__all__"
widgets = {
"start": TimePickerInput(),
"end": TimePickerInput(),
}
def __init__(self, *args, **kwargs):
super(WorkOutForm, self).__init__(*args, **kwargs)
for field in iter(self.fields):
self.fields[field].widget.attrs.update({
"class": "form-control"
})
templates
{% load bootstrap4 %}
{% bootstrap_css %}
{% bootstrap_javascript jquery='full' %}
{{ form.media }}
<form action="" method="POST" style="width: 20%">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit">
</form>

Related products

In my model I have a ManyToManyField to select related products. I'm wondering what would be the best way to bring these into my view and render them in my template.
models.py
class Product(models.Model):
title = models.CharField(max_length=80)
category = models.ManyToManyField(ProductCategory)
featured_image = models.ImageField(upload_to=image_dir)
about_this_product = models.TextField()
standard_features = models.TextField(null=True)
featured = models.BooleanField(default=False)
related_models = models.ManyToManyField("self", blank=True, null=True)
model_slug = AutoSlugField(null=True, default=None,
unique=True, populate_from='title')
class Meta:
verbose_name_plural = "Products"
def __str__(self):
return self.title
views.py
def model_detail_view(request, category_slug, model_slug):
product_model = get_object_or_404(Product, model_slug=model_slug)
context = {
"title": "Products | %s" % product_model.title,
"product": product_model,
}
return render(request=request, template_name='main/product_model_detail.html', context=context)
You can use .prefetch_related(..) just like you do on any one-to-many relation in the view:
def my_view(request):
products = Product.objects.prefetch_related('related_models')
return render(request, 'some_template.html', {'products': products})
Then in the template, you can iterate over the .related_models collection:
{% for product in products %}
{{ product.title }}
related:
{% for rel in product.related_models.all %}
{{ rel.title }}
{% endfor %}
{% endfor %}

Limit dropdown results in generic UpdateView

Working on my first Django project! I have an UpdateView and I want to limit the dropdown results of program_code so it only shows items that the user owns. I think I have to pass kwargs to the view to limit the queryset but not sure where to begin or how to go about doing that. Any advice would be greatly appreciated.
View:
class ContactsUpdateView(LoginRequiredMixin, UserPassesTestMixin, SuccessMessageMixin, UpdateView):
model = Contact
fields = ['first_name1', 'last_name1','address1','address2','city','province','postal_code','country','active_status','program_code']
template_name = 'contacts/contacts_form.html'
success_message = "Contact was updated successfully"
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
def test_func(self):
contact = self.get_object()
if self.request.user == contact.author:
return True
return False
model:
class Contact(models.Model):
first_name1 = models.CharField(max_length=100, verbose_name='First Name', null=True)
last_name1 = models.CharField(max_length=100, verbose_name='Last Name', null=True)
address1 = models.CharField(max_length=100, verbose_name='Address 1', null=True)
address2 = models.CharField(max_length=100, verbose_name='Address 2', null=True, blank=True)
city = models.CharField(max_length=100, verbose_name='City', null=True)
province = models.CharField(max_length=2, choices=PROVINCE_CHOICES, default='Ontario', verbose_name='Province')
postal_code = models.CharField(max_length=7, verbose_name='Postal Code', null=True)
country = models.CharField(max_length=100, verbose_name='Country', null=True, default='Canada')
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
active_status = models.BooleanField(default=True)
program_code = models.ForeignKey(Program, on_delete=models.CASCADE)
def __str__(self):
return self.first_name1 + ' ' + self.last_name1
def get_absolute_url(self):
return reverse('contacts-home')
template form:
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-2 mt-2">Update Contact</legend>
<p>Created by: {{ object.author }}, Last Updated: {{ object.date_posted }}</p>
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-info" type="submit">Update</button>
<div class="mt-4"><a class="btn btn-outline-danger btn-sm" href="{% url 'contacts-delete' object.id %}" role="button">Delete Contact</a></div>
</div>
</form>
You can try like this:
# form
class ContactForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None) # This will be sent from View
super(ContactForm, self).__init__(*args, **kwargs)
self.fields['program_code'].queryset = Program.objects.filter(owner=user)
class Meta:
model = Contact
fields = ['first_name1', 'last_name1','address1','address2','city','province','postal_code','country','active_status','program_code']
#view
class ContactsUpdateView(LoginRequiredMixin, UserPassesTestMixin, SuccessMessageMixin, UpdateView):
model = Contact
from_class = ContactForm
template_name = 'contacts/contacts_form.html'
success_message = "Contact was updated successfully"
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
def get_form_kwargs(self):
# Sending user information to Form
kwargs = super(ContactsUpdateView, self).get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
Here in the View, we are overriding the get_form_kwargs method to pass current user information to the Form. And inside the form, we are overriding the __init__ method to catch the user data sent from View, and use it to override default queryset value of the field program_code.

Django] Saving multiple images by formset doesn't work

I'm trying to save multiple Images and his parent's data together on the same template.
I have one parent's model(to save normal data) and child's model(to save images). In this case, saving parent's data is working very well. but images are not work.
There isn't any error message.
//model
class QuotationPanchok(models.Model):
whose = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
title = models.CharField(max_length=50, help_text='', default='')
many = models.IntegerField(default='1', help_text='')
design = models.CharField(max_length=3, choices=(('yes', 'yes'), ('no', 'no'),))
sian = models.CharField(max_length=3, choices=(('yes','yes'), ('no', 'no'),))
havefile = models.CharField(max_length=3, choices=(('yes','yes'), ('no', 'no'),))
deadline = models.DateField(blank=True)
addressto = models.CharField(max_length=50, default='', help_text='')
fulltext = models.TextField(max_length=150, blank=True)
status = models.CharField(max_length=7, choices=(('not','not'), ('finish', 'finish'),), default='not')
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.title
class ImagesForQuotation(models.Model):
whose = models.ForeignKey(QuotationPanchok, on_delete=models.CASCADE)
image = models.ImageField(upload_to='images/', blank=True, null=True)
def __str__(self):
return self.whose.title + " Image"
// views
def quotation_create(request):
ImageFormset = modelformset_factory(ImagesForQuotation, fields=('image',), extra=4)
if request.method == 'POST':
form = QuotationCreateForm(request.POST)
formset = ImageFormset(request.POST or None, request.FILES or None)
if form.is_valid() and formset.is_valid():
post = form.save(commit=False)
post.whose = request.user
post.save()
for f in formset:
try:
photo = ImagesForQuotation(whose=post, image=f.cleaned_date['image'])
photo.save()
except Exception as e:
break
return redirect('index')
else:
form = QuotationCreateForm()
formset = ImageFormset(queryset=ImagesForQuotation.objects.none())
context = {
'form': form,
'formset': formset,
}
return render(request, 'quotationapp/quotation_create.html', context)
//forms
class QuotationCreateForm(forms.ModelForm):
class Meta:
model = QuotationPanchok
fields = (
'title',
'many',
'design',
'sian',
'havefile',
'deadline',
'addressto',
'fulltext',
)
def __init__(self, *args, **kwargs):
super(QuotationCreateForm, self).__init__(*args, **kwargs)
for field_name, field in self.fields.items():
field.widget.attrs['class'] = 'form-control'
//template(quotation_create.html)
{% block content %}
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
{{ formset.as_table }}
<input type="submit" class="btn btn-primary" value="">
</form>
{% endblock %}
How can I solve this problem?
Thank you..