Django Saving selected values of ManytoMany Field - django

Here I am trying to save selected fields in the manytomany field.
When I try to save the selected fields all fields other than selected are also saved. How can i save only the selected fields.
here is my model..
#model
class Products(models.Model):
name = models.CharField(max_length=128)
product_code = models.CharField(max_length=128)
cmp_id = models.ManyToManyField(Components, blank=True)
bay_id = models.ManyToManyField(ScanningBay, blank=True)
def __str__(self):
return self.name
#form
class ProductForm(forms.ModelForm):
name = forms.CharField(max_length=15,widget=forms.TextInput(attrs={'class':'form-control','placeholder': 'Product Name','size': '40'}))
product_code = forms.CharField(max_length=15, widget=forms.TextInput(
attrs={'class': 'form-control', 'placeholder': 'Product Code', 'size': '40'}))
bay = forms.ModelMultipleChoiceField(queryset=ScanningBay.objects.all())
component = forms.ModelMultipleChoiceField(queryset=Components.objects.all())
​
class Meta:
model = Products
fields = ('name', 'product_code','bay','component')"
​
#views
def products(request):
if request.method == 'POST':
p_form = ProductForm(request.POST or None)
new = p_form.save(commit=False)
new.save()
z = p_form.save_m2m()
print (z)
return HttpResponse("success")
else:
pdct_form = ProductForm()
return render(request, 'app/products.html', {'pdct':pdct_form})
this is the template rendered ​
<form id="test" class="impexform" action="{%url 'products'%}" method="POST">
{% csrf_token %}>
{{pdct}}
<button type="submit" class="btn btn-sm btn-danger mt-3"
style="background:#ed2526; border-radius: 30px; width: 8rem;">Add Product</button>
</form>

The fields in your form don't match the fields on your model:
class ProductForm(forms.ModelForm):
...
cmp_id = forms.ModelMultipleChoiceField(queryset=Components.objects.all())
​
class Meta:
model = Products
fields = ('name', 'product_code','bay','cmp_id')"

Related

How do i edit a record but show existing value selected of a drop-down box

models.py
class Products(models.Model):
Name = models.CharField(max_length=100, verbose_name='Name of Product')
Category = models.CharField(max_length=100, verbose_name='Product Category')
Description = models.CharField(max_length=220, verbose_name='Product Description')
class Categories(models.Model):
Title = models.CharField(max_length=100, verbose_name='Category Title')
Description = models.CharField(max_length=100, verbose_name='Category Description')
Picture = models.ImageField(default='/gifts.png', upload_to='ffff/')
def __str__(self):
return self.Title
forms.py
class EditProduct(forms.ModelForm):
class Meta:
model = Products
fields = ['Name', 'Category', 'Description', 'Weight', 'Size', 'Cost', 'Personalised', 'Keywords',
'Picture1']
widgets = {
'Category': Select(),
}
def __init__(self, *args, **kwargs):
super(EditProduct, self).__init__(*args, **kwargs)
self.fields['Category'] = forms.ModelChoiceField(queryset=Categories.objects.all().order_by('Title'))
I've created records in models.py Categories (eg Title = 1, Title, 2, Title =3)
In models.py Products i have created some records (eg Name=Hat, Category=1; Name=Cap, Category=3)
I can add Product records easily with crispy forms and my drop down list appears for Category, select the choice and form saves. All works great
But when i try to EDIT the record, i use instance= and it brings the contents of the record back, but i also want a drop down list for category in the edit section, but if i put a drop-down list in, then it doesn't populate that field with existing value, i need to reselect it
My views.py
def products_edit(request, item_id):
pp = Products.objects.get(id=item_id)
my_form = EditProduct(instance=pp)
if 'first' in request.POST:
if request.method == 'POST':
my_form = EditProduct(request.POST, request.FILES, instance=pp)
if my_form.is_valid():
my_form.save()
messages.success(request, f'Thank you the Product has been amended!')
return redirect('frontpage-products')
context = {
'my_form': my_form,
'results': Products.objects.all().order_by('Name')
}
return render(request, 'frontpage/products_edit.html', context)
and my html
<form method="POST" class="form-section" enctype="multipart/form-data">
<div class="page_font search">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Edit Product</legend>
{{ my_form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-primary" type="submit" name="first">UPDATE</button>
</div>
</div>
</form>
How do i populate the drop-down list with existing value?

Unable to update individual items in Django

I am trying to update some information in my Django application but I am getting this error "Cannot assign "9": "Reservation.table" must be a "Tables" instance".
I have tried so manual method also but it still same error.
Error: Cannot assign "9": "Reservation.table" must be a "Tables" instance
views.py
#login_required
def UpdateReservation(request, pk):
table_exists = get_object_or_404(Reservation, id=pk)
form = ReservationForm(instance=table_exists)
if request.method == "POST":
form = ReservationForm(request.POST, instance=table_exists)
if form.is_valid():
form = ReservationForm(request.POST, instance=table_exists)
if form.is_valid():
form.save()
return redirect('view_reservations')
messages.success(request, "successfully updated table")
context = {"form": form}
return render(request, "dashboard/super/landlord/update_reserve.html", context)
models.py
class Reservation(models.Model):
status_choices = (
("pending", "pending"),
("confirmed", "confirmed")
)
first_name = models.CharField(max_length=200)
last_name = models.CharField(max_length=200)
email = models.EmailField()
phone = PhoneNumberField(blank=True)
people = models.IntegerField(default=1)
time = models.TimeField()
date_reserved = models.DateField()
date_booked = models.DateTimeField(auto_now_add=True)
status = models.CharField(max_length=10, choices=status_choices, default="confirmed")
comment = models.TextField(blank=True)
table = models.ForeignKey(Tables, on_delete=models.CASCADE)
def __str__(self):
return self.first_name
forms.py
class ReservationForm(forms.ModelForm):
time = forms.CharField(
widget=forms.TextInput(attrs={'id': 'timepicker',
'class': 'input-group',
'placeholder': '12:00:AM'}))
date_reserved = forms.DateField(widget=forms.TextInput(
attrs={'placeholder': 'yyyy-mm-dd',
'id': 'datepicker'}), required=True,)
comment = forms.CharField(widget=forms.TextInput(
attrs={'placeholder': 'Leave a message'}), required=True,)
first_name = forms.CharField(widget=forms.TextInput(
attrs={'placeholder': 'Leave a message'}), required=False,)
email = forms.CharField(widget=forms.TextInput(
attrs={'placeholder': 'Your Email Address'}), required=True,)
phone = forms.CharField(widget=forms.TextInput(
attrs={'placeholder': 'Your Telephone number'}), required=True,)
table = forms.IntegerField(widget=forms.TextInput(
attrs={'placeholder': 'Table Number'}), required=True,)
class Meta:
model = Reservation
fields = ['first_name', 'email', 'time', 'comment',
'phone', 'date_reserved', 'people', 'table']
template.html
<div class="panel-body">
<form class="form-horizontal" role="form" method="post" enctype="multipart/form-data">
{% csrf_token %}
{% for field in form %}
<div class="form-group">
<label class="col-md-2 control-label">{{ field.label }}</label>
<div class="col-md-10">
{{ field|attr:'class:form-control'}}
</div>
</div>
{% endfor %}
<div class="form-group">
<div class="col-md-10">
<center><button class="btn btn-primary" type="submit">Update Reservation</button></center>
</div>
</div>
</div>
You can not make use of an IntegerField, since it expects a Table, not an integer for table. You should use a ModelChoiceField and then use a TextInput as widget:
table = forms.ModelChoiceField(
queryset=Table.objects.all()
widget=forms.TextInput(attrs={'placeholder': 'Table Number'}),
required=True
)
In your form remove your table field from the field list above but keep the one in the Meta, its messing with it because the value is in Integer and you have to assign an object.

Many to many fields in widget form

I have problem with display many to many field in form widget.
Category is not display in template.
Title is ok (is display) but category isn't - category is empty.
What can I do to display many to many fields in my template form with multiplechoice checkboxes?
Why I cant display article categories in widget form?
MODELS.py
article model:
class Article(Created, HitCountMixin):
title = models.CharField(max_length=120)
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
category = models.ManyToManyField(ArticleCategory, related_name='articles')
category model:
class ArticleCategory(Created):
category_name = models.CharField(max_length=128)
slug = models.SlugField(null=False, unique=False)
VIEWS:
class UpdateArticleView(LoginRequiredMixin, UpdateView):
template_name = 'news/update_article.html'
form_class = EditArticleForm
model = Article
def get_success_url(self):
pk = self.kwargs["pk"]
slug = self.kwargs['slug']
return reverse_lazy("news:article_detail", kwargs={'pk': pk, 'slug': slug})
FORMS.py
class AddArticleForm(forms.ModelForm):
title = forms.CharField(
label="Tytuł",
max_length=120,
help_text="Tytuł newsa",
widget=forms.TextInput(attrs={"class": "form-control form-control-lg pr-5 shadow p-1 mb-1 bg-white rounded"}),
required=True,
)
category = forms.MultipleChoiceField(
widget=forms.CheckboxSelectMultiple,
)
And in my HTML TEMPLATE:
<form method="post" enctype='multipart/form-data'>
{% csrf_token %}
{{ form.media }}
{# {% crispy form %}#}
{{ form|crispy }}
<button type="submit" class="btn btn-outline-primary">EDYTUJ NEWS</button>
</form>
Your form_class in your view is a EditArticleForm, so you should be careful to use the correct form.
The form field for a ManyToManyField is normally a ModelMultipleChoiceField [Django-doc], but it is not necessary to specify the form field anyway. You can make use of the widgets option:
class EditArticleForm(forms.ModelForm):
title = forms.CharField(
label='Tytuł',
max_length=120,
help_text='Tytuł newsa',
widget=forms.TextInput(
attrs={'class': 'form-control form-control-lg pr-5 shadow p-1 mb-1 bg-white rounded'}
),
required=True,
)
class Meta:
model = Article
widgets = {
'category': forms.CheckboxSelectMultiple
}
you can customize the label with:
class EditArticleForm(forms.ModelForm):
title = forms.CharField(
label='Tytuł',
max_length=120,
help_text='Tytuł newsa',
widget=forms.TextInput(
attrs={'class': 'form-control form-control-lg pr-5 shadow p-1 mb-1 bg-white rounded'}
),
required=True,
)
class Meta:
model = Article
widgets = {
'category': forms.CheckboxSelectMultiple
}
labels = {
'category': 'label of category'
}

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 Formset issue - POST doesn't seems to work

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.