Django get data of object from ManyToManyField form - django

Hello i created this form :
class CartForm(ModelForm):
class Meta:
model = Cart
fields =( 'products',)
from theses models :
class Product(models.Model):
title = models.CharField("Titre", max_length=120)
subtitle = models.CharField("Sous-titre", max_length=250)
description = models.TextField("Description")
picture = models.ImageField(upload_to='objects/')
enabled = models.BooleanField("Activé")
class Cart(models.Model):
products = models.ManyToManyField(Product)
and i want to display on my template an list of choice with their data
So i send form from views but i don't find any way to get the products description i only get their names !
here is my view :
def home(request):
categories = Category.objects.annotate(test=Count('product')).filter(test__gt=0)
# categories = Category.objects.order_by(
# 'id')
test = CartForm()
return render(request, 'boutique.html', {"categories": categories, "test":test})
and what i tried in my template :
{% for ee in test.products %}
{{ ee.description }}
<br />
{% endfor %}
please help me
have a nice day

Ok so theres a couple issues here:
First of all you actually need to define what is gonna happen when you submit the form, so in your view do this:
views.py
def home(request):
categories = Category.objects.annotate(test=Count('product')).filter(test__gt=0)
if request.method == 'POST':
test = CartForm(request.POST)
if form.is_valid():
cart = form.save(commit=False)
for product in request.POST.getlist('products'):
cart.add(product)
else:
pass
else:
form = CartForm()
return render(request, 'boutique.html', {"categories": categories, "test": test})
then in your template you actually have to render the form (test):
boutique.html
<form method="post">
{% csrf_token %}
{{ test.as_p }}
<button type="submit"> Add Items </button>
</form>
Now you should see the list of products in template.
edit
if you want to show a different model field in your form rewrite its __str__ method like this:
def __str__(self):
return self.description # to show description

Related

Creating a multiplechoice field using many to many relationship

Im trying to add a field called, interested_fields inside my personalInfo model which users can choose from and the choices themselves come from another models' objects with the help of ManyToMany relation between the two models. Here are my models.py codes(I simplified my personal model by removing some other fields like name, age, etc in order to make it more readable for you):
class Field(models.Model):
id = models.AutoField(primary_key=True)
slug = models.CharField(max_length=16, default='default')
title = CharField(max_length=32)
class PersonalInfo(models.Model):
id = models.AutoField(primary_key=True)
interested_fields = models.ManyToManyField(Field, blank=True)
then, I created a ModelForm like this:
class InterestedFieldsForm(forms.ModelForm):
interested_fields = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple, choices=Field.objects.all(), required=False)
class Meta:
model = PersonalInfo
fields = ['interested_fields']
and created a get and post functions inside my views like this:
class PersonalView(View):
template_name = 'reg/personal.html'
def get(self, request, *args, **kwargs):
context = {}
context['fields'] = Field.objects.all()
return render(request, self.template_name, context=context)
def post(self, request, *args, **kwargs):
user = request.user
if request.method == 'POST':
form = InterestedFieldsForm(request.POST)
if form.is_valid():
profile = form.save(commit=False)
profile.user = request.user
profile.save()
else:
form = InterestedFieldsForm()
return render(request, 'reg/done.html', context={'form': form})
and finally in template, inside the form I added this for loop:
{% for field in fields %}
<label class="containerq ant-col ant-col-md-6 ant-col-xs-8" >
<span>
<input type="checkbox" name="interested_fields" {% if field.slug in user.personalInfo.interested_fields %} checked="checked" {% endif %} value="{{field.title}}">
<span style="margin-left:7px" class="checkmark"></span>
</span>
<span>{{field.title}}</span>
</label>
{% endfor %}
when I submit the form it gives me this error:
cannot unpack non-iterable Field object
Im new to django so I really dont know what am I doing wrong. thank you for your answers
You should use a ModelMultipleChoiceField
interested_fields = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple, queryset=Field.objects.all(), required=False).

Django Error: user_register_model matching query does not exist

How to fix This Error I'm Trying To Fix This Error But I Get Again And Again
i want to detect user who fill the form for example test fill the form but when i write the code down below i get this error
Any Help Will Be Appreciated!
ERROR
user_register_model matching query does not exist.
ERROR SCREENSHOT
Here is my Views.py
def buy_form(request):
if request.method == 'POST':
usr_buy = user_buy_form(request.POST)
if usr_buy.is_valid():
usr_buys = usr_buy.save(commit=False)
user_register_obj = user_register_model.objects.get(user=request.user)
usr_buys.users = user_register_obj
usr_buys.save()
else:
return print(usr_buy.errors)
else:
usr_buy = user_buy_form()
context = {'usr_buy':usr_buy}
return render(request,'user_buy.html',context)
Here is my Models.py
class user_register_model(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE)
join_date = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.user.username
class user_buy(models.Model):
users = models.ForeignKey(User,on_delete=models.CASCADE)
title = models.CharField(max_length=200)
payment_method = models.CharField(max_length=500)
price = models.IntegerField()
Trade_limits = models.IntegerField()
Location = models.CharField(max_length=1000)
def __str__(self):
return self.users.user.username
Here is my Forms.py
class user_buy_form(forms.ModelForm):
class Meta():
model = user_buy
fields = '__all__'
exclude = ('users',)
Here is my user_buy.html
{% extends 'base.html' %}
{% block body_block %}
<form class="form-control" method="POST">
{% csrf_token %}
{{usr_buy.as_p}}
<input type="submit" class="btn btn-primary" value="Submit">
</form>
{% endblock %}
I didn't see any points here to create the user_register_model.If you are trying to add the currently logged in user you can do this:
request.user will give you the currently logged in user so for this the user must be logged in.
#login_required
def buy_form(request):
if request.method == 'POST':
usr_buy = user_buy_form(request.POST)
if usr_buy.is_valid():
usr_buys = usr_buy.save(commit=False)
usr_buys.users = request.user
usr_buys.save()
return redirect('some_path') # redirect to some path after saving the form
Class names should normally use the CapWords convention.
I think the request.user is not present in the user_register_model model thats why it is giving matching query doesnot exist error, first create it in the user_register_model and then query it.

Show values in dropdown list in Django

I want to add documents about different parts of my facility in my Django app.
So, I have the following models in my models.py:
class Parts(models.Model):
Name = models.CharField(max_length=50)
class Docs(models.Model):
Date = models.DateField(default=date.today)
Type = models.CharField(max_length=50)
Part = models.ForeignKey(Parts)
Link = models.FileField(upload_to='Docs/%Y/%m/%d')
forms.py:
class DocsForm(ModelForm):
class Meta:
model = Docs
fields = ['Date', 'Type', 'Part', 'Link']
class PartsForm(ModelForm):
class Meta:
model = Parts
fields = ['Name']
views.py:
def adddocs(request):
if request.method == 'POST':
f = DocsForm(request.POST, request.FILES)
if f.is_valid():
f.save()
return HttpResponseRedirect('')
else:
form = DocsForm()
return render(
request,
'adddocs.html',
{'form': form}
and the following fragment in my template:
<form action="{% url 'adddocs' %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<p> {{form.Date}} </p>
<p> {{form.Type}} </p>
<p> {{form.Part}} </p>
<p> {{form.Link}} </p>
<p><input type="submit" value="Add" /></p>
</form>
And everything works fine except one problem. Now I have two parts of my facility, for example 'tubes' and 'storage'. But if I want to choose them in dropdown list, I see the following variants in my browser:
Parts Object
Parts Object
What should I change to see names of parts like this
tubes
storage
?
You need the str() method in your Models.
The str() method is called whenever you call str() on an object. Django uses str(obj) in a number of places. Most notably, to display an object in the Django admin site and as the value inserted into a template when it displays an object. Thus, you should always return a nice, human-readable representation of the model from the str() method.
class Parts(models.Model):
Name = models.CharField(max_length=50)
# call to return name
def __str__(self):
return self.Name

How to create form field for every foreign key in django?

I am trying to build a form and I am not sure how this should be done correctly. These are my models:
class Country(models.Model):
name = models.CharField(max_length=250, null=False, blank=False, unique=True)
twocode = models.CharField(max_length=5, null=False, blank=False, unique=True)
class GeoBonus(models.Model):
name = models.CharField(max_length=250)
country = models.ForeignKey(Country, related_name='geo_bonuses')
bookmaker = models.ForeignKey(Bookmaker, related_name='geo_bonuses')
Bookmaker has bonuses, different for each country. For example:
Bookmaker has bonuses:
Slovakia: "eligible for 100% up to $200"
Afghanistan: "eligible for 100% up to €100!"
USA: "restricted country"
...
And I want to save text in quotes as name in GeoBonus. Of course I can write use simple model form, but I would have submit form 248 time(for each country). I would like to show all fields for each country.
If name is blank, GeoBonus will not be created.
If name is not blank, create GeoBonus object.
This is what it should look like:
How code in forms.py and views.py will look like? I also need to edit fields.
I tried to manually create new fields for countries:
<form method="post" action="" class="wide">
{% csrf_token %}
{%bootstrap_form form %}
<div class="form-group">
{%for country in countries%}
<label class="control-label" for="{{country.twocode}}">{{country}}</label>
<input class="form-control" id="{{country.twocode}}" maxlength="250" type="text" />
{%endfor%}
</div>
<input type="submit" class="btn btn-default" name="submit" value="Save">
</form>
Using this forms.py class:
class GeoBonusForm(forms.ModelForm):
class Meta:
model = GeoBonus
fields = ['bookmaker']
But request.POST does contain only bookmaker field.
EDIT1: Views.py
#staff_member_required
def geo_bonus_edit(request, bookmaker=None):
template = loader.get_template('geobonus/edit.html')
if request.method == 'POST':
form = GeoBonusForm(request.POST)
print request.POST
else:
form = GeoBonusForm()
context = RequestContext(request, {
'form': GeoBonusForm,
'countries': Country.objects.all(),
})
return HttpResponse(template.render(context))
I would suggest, that you generate the fields in your form dynamically. It could look like this:
class GeoBonusForm(forms.ModelForm):
countries = Country.objects.all()
def __init__(self, *args, **kwargs):
super(GeoBonusForm, self).__init__(*args, **kwargs)
for country in self.countries:
self.fields[country.name] = forms.CharField()
This allows you to generate a CharField for every Country you have.
Therefore the saving is a bit different than the normal ModelForm would expect it I would recommend to override the save method:
def save(self, commit=True):
super(GeoBonusForm, self).save(commit=False)
bookmaker = Bookmaker.objects.get(id=self.cleaned_data['bookmaker'].id)
for field in self.cleaned_data:
if field != 'bookmaker':
country = Country.objects.get(name=field)
geo_bonus, created = GeoBonus.objects.get_or_create(bookmaker=bookmaker, country=country)
geo_bonus.name = self.cleaned_data[field]
geo_bonus.save()
At first we try to get the chosen bookmaker. After that we iterate over the cleaned fields (for more about form cleaning take a look here) and try to get_or_create the GeoBonus object. Now we just fill in the value of the corresponding country field and save.
I adapted the code of your view a little bit:
def index(request, bookmaker=None):
template = loader.get_template('geobonus/edit.html')
if request.method == 'POST':
form = GeoBonusForm(request.POST)
if form.is_valid():
form.save()
else:
form = GeoBonusForm()
context = RequestContext(request, {
'form': GeoBonusForm,
})
return HttpResponse(template.render(context))
You don't need to pass the countries to the context anymore, because we generate the field in the form. On POST we check if the form is valid and save it, if it is.
For the template you only should only need this now:
<form action="." method="post">
{% csrf_token %}
{{ form }}
<input type="submit">
</form>
Hope I got it right and that this solves your problem.
Edit: Note, that this is a simple quick example. Of course you should clean the data and check if the input is valid and maybe prepare it for a more simple saving process.
You could use Django's inlinemodelformset for that, refer to using a formset in views and templates for example code.

django: How to use inlineformset within the formwizard?

I'm displaying two separate sample projects. The first is a Contact related and shows the principle of using the formwizard. The second is an ingredients to recipes related project which shows how to use inlines within a form. I want inlines to be in my formwizard the same way they work in a normal form.
I have a formwizard multistep form working. It is based off the example here. I've changed it slightly to use modelform.
models.py
from django.db import models
# Create your models here.
class Contact(models.Model):
subject = models.CharField(max_length=50)
sender = models.EmailField()
def __unicode__(self):
return self.subject
class Contact2(models.Model):
message = models.TextField(max_length=500)
def __unicode__(self):
return self.message
forms.py
class ContactForm1(forms.ModelForm):
class Meta:
model = Contact
class ContactForm2(forms.ModelForm):
class Meta:
model = Contact2
class ContactWizard(FormWizard):
#property
def __name__(self):
return self.__class__.__name__
def done(self, request, form_list):
# do_something_with_the_form_data(form_list)
return HttpResponseRedirect('/done/')
urls.py
(r'^contact/$', ContactWizard([ContactForm1, ContactForm2])),
Separately I have inlines being generated into another form. I'm doing this via inlineformset_factory in my view. This is not connected to the formwizard example above. This is an ingredients to recipes example.
I'm doing this like:
views.py
def add(request):
IngredientFormSet = inlineformset_factory(Recipe, Ingredient,
fk_name="recipe",
formfield_callback=curry(ingredient_form_callback, None))
if request.method == 'POST':
form = RecipeForm(request.POST)
formset = IngredientFormSet(request.POST)
if form.is_valid() and formset.is_valid():
recipe = form.save()
formset = IngredientFormSet(request.POST, instance=recipe)
formset.save()
return redirect("/edit/%s" % recipe.id)
else:
form = RecipeForm()
formset = IngredientFormSet()
return render_to_response("recipes_add.html", {"form":form, "formsets":formset}, context_instance=RequestContext(request))
recipes_add.html
<form method="post">
{% csrf_token %}
<table>
{{ form }}
</table>
<hr>
<h3>Ingredients</h3>
<div class="inline-group">
<div class="tabular inline-related last-related">
{{ formsets.management_form }}
{% for formset in formsets.forms %}
<table>
{{ formset }}
</table>
{% endfor %}
</div>
</div>
<p class="success tools">Add another row</p>
<input type="submit" value="Add">
</form>
How can I get the inlines to work within my formwizard multistep form?
The models.py now looks like this because I want books to be inlines to contact. I want the inlines to be on the first step of my formwizard. Then go through to step 2 and finish.
from django.db import models
# Create your models here.
class Contact(models.Model):
subject = models.CharField(max_length=50)
sender = models.EmailField()
def __unicode__(self):
return self.subject
class Contact2(models.Model):
message = models.TextField(max_length=500)
def __unicode__(self):
return self.message
class Book(models.Model):
author = models.ForeignKey(Contact)
title = models.CharField(max_length=100)
The formwizard included in Django (below version 1.4) doesn't support formsets. Beginning with version 1.4, there will be a much better implementation (see https://docs.djangoproject.com/en/dev/ref/contrib/formtools/form-wizard/)
Back to your question, if you can't wait for the next Django release - which I assume - you could stick to django-formwizard. The last release (1.0) is api compatible to the upcoming Django formwizard.
With the new formwizard implementation you can use FormSets the same way you use normal Forms.