Django form throws select valid choice - django

I have read every answer for this question but none of them solved my problem completely. I hope someone can help me understand what is wrong in my code. I have a field in my model and I want all the values in that field to be displayed in a dropdown in my form. I was able to achieve that but when I try to save, it says "Select a valid choice. That choice is not one of the available choices." Any help would be greatly appreciated.
models.py
class Item(models.Model):
Product = models.ForeignKey("Product", related_name = "Items")
Name = models.CharField(max_length=1000, blank=True, null=True)
Tag = models.CharField(max_length=1000, blank=True, null=True)
forms.py
class ItemForm(ModelForm):
items = Item.objects.values_list('Name', flat=True)
item_choices = [(item, item) for item in items]
Name = forms.ModelChoiceField(items, widget=forms.Select())
class Meta:
model = Item
fields = ['Name', 'Tag']
views.py
def newknowledgebase(request):
itemformset = modelformset_factory(Item, form=ItemForm, extra=2)
items = itemformset(queryset=Item.objects.none(), prefix='items', )
if request.method=='POST':
items = itemformset(request.POST, queryset=Item.objects.none(), prefix='items', )
item = request.POST.get('items')
for form in items:
form.fields['Name'].choices = [(item, item)]
if items.is_valid():
items.save()
context = {
'items':items,
}
return render(request, 'newknowledgebase.html', context )
html file
<div id="items" class="panel-collapse collapse">
<table class="table table-bordered">
<tbody>
{{ items }}
</tbody>
</table>
</div>

Try this
Name = forms.ChoiceField(item_choices, widget=forms.Select())

Related

How to fix add to cart functionality in django?

I'm building an ecommerce platform and I want to create the add to cart functionality in the website. But for some reason the Product Id is showing null.
Here's the codes:
models.py
class Products(models.Model):
user = models.ForeignKey(User, on_delete = models.CASCADE)
title = models.CharField(max_length = 255)
product_category = models.CharField(choices = CATEGORY_CHOICES, max_length = 100)
description = models.TextField()
price = models.FloatField(max_length= 5)
class Cart(models.Model):
user = models.ForeignKey(User, on_delete = models.CASCADE)
products = models.ForeignKey(Products, on_delete = models.CASCADE)
views.py
def add_cart(request):
product_id = Products.id
new_product = Cart.objects.get_or_create(id=product_id, user=request.user)
return redirect('/')
templates
<div class="product-wrapper">
<h1 style="font-size:24px">{{product.title}}</h1>
<div class="product-price">
<p style="text-decoration-line:line-through;">$ {{product.price}}</p>
<a href="{% url 'add-product' product.product_id %}">Add to cart<a>
</div>
When I try to click this link it gives me this error: Field 'id' expected a number but got <django.db.models.query_utils.DeferredAttribute object at 0x000002468A4F8550>.
Any suggestion will be really helpful. Thank you
Finally, I've fixed this.
view.py
def add_to_cart(request, slug):
products = Products.objects.get(slug=slug)
ncart = Cart.objects.create(user=request.user, products=products)
ncart.save()
return redirect('/')
template
<div class="product-wrapper">
<h1 style="font-size:24px">{{product.title}}</h1>
<div class="product-price">
<p style="text-decoration-line:line-through;">$ {{product.price}}</p>
<a href="{% url 'add-to-cart' product.slug %}">Add to cart<a>
</div>
urls.py
path('cart/add/<slug:slug>', views.add_to_cart, name = 'add-to-cart')
Considering you've got Products instance already, in that case
Query directly like:
new_product = Cart.objects.get_or_create(products=Products)
If you want to query from the product_id, do it like that:
product_id = Products.pk
new_product = Cart.objects.get_or_create(products_id=product_id)
In addition:
request.user contains a dictionary, you can't pass it directly to query. And the user field has name buyer, so change that query like that:
product_id = Products.pk
new_product = Cart.objects.get_or_create(products=Products, buyer_id=request.user['pk'])

Django can't display data from two models

I am trying to display data from two different models. The two models have a one-to-many relationship but I am not sure why it is not displaying the data from the MembersPresent model. Here are my models
and view
class fly_minute(models.Model):
mode = (
('Email', 'Email'),
('Zoom', 'Zoom'),
('Alternative', 'Alternative'),
)
mode_of_meeting = models.CharField(max_length=100, choices=mode, blank=False, )
date = models.DateField()
Time = models.TimeField()
minute_prepared_by = models.CharField(max_length=25)
location = models.CharField(max_length=25)
authorize_by = models.CharField(max_length=25)
item = models.TextField()
owner = models.CharField(max_length=25)
def __str__(self):
return self.mode_of_meeting
class MembersPresent(models.Model):
flyminute = models.ForeignKey(fly_minute, on_delete=models.CASCADE)
name = models.CharField(max_length=25)
status = models.CharField(max_length=25)
email = models.EmailField(max_length=25)
phone = models.IntegerField()
def __str__(self):
return self.name
#login_required(login_url='login_page')
def MinutesReport(request, minute_id):
report = fly_minute.objects.filter(id=minute_id)
return render(request, 'minute_report.html', locals())
{%for rpt in report%}
<tbody>
<tr class="table-active">
<td>{{rpt.flyminute.name}}</td>
<td>{{rpt.flyminute.status}}</td>
<td>{{rpt.flyminute.email}}</td>
<td>{{rpt.flyminute.phone}}</td>
</tbody>
{%endfor%}
You need to use 'prefetch_related()'
Returns a QuerySet that will automatically retrieve, in a single batch, related objects for each of the specified lookups.
This has a similar purpose to select_related, in that both are designed to stop the deluge of database queries that is caused by accessing related objects, but the strategy is quite different.
models.py
class MembersPresent(models.Model):
flyminute = models.ForeignKey(
fly_minute,
related_name='memberspresent_set', # this will be the default name, incase of need of change provide a new one
on_delete=models.CASCADE
)
...
views.py
#login_required(login_url='login_page')
def MinutesReport(request, minute_id):
report = fly_minute.objects.filter(id=minute_id).prefetch_related('memberpresent_set')
return render(request, 'minute_report.html', locals())
For further control, you can use Prefetch along with prefetch_related()
Note:
locals() returns a dict of all the locally defined variables in the current scope and this may result in exposing sensitive info. Instead of that create a custom dict and return it.
...
context = {
'report': report,
...
}
return render(request, 'minute_report.html', context)
You are referencing and querying in the opposite way. Your fly_minute model doesn't contain MembersPresent model as the Foreign Key. You are filtering the fly_minute model and trying to access MembersPresent model. So, you should change your fly_minute to in this way:
class fly_minute(models.Model):
mode = (
('Email', 'Email'),
('Zoom', 'Zoom'),
('Alternative', 'Alternative'),
)
mode_of_meeting = models.CharField(max_length=100, choices=mode, blank=False, )
date = models.DateField()
Time = models.TimeField()
minute_prepared_by = models.CharField(max_length=25)
location = models.CharField(max_length=25)
authorize_by = models.CharField(max_length=25)
item = models.TextField()
owner = models.CharField(max_length=25)
member = models.ForeignKey(MembersPresent, on_delete=models.CASCADE)#add this line and remove fly_minute in MembersPresent model
def __str__(self):
return self.mode_of_meeting
Then in template file change it to in this way:
{%for rpt in report%}
<tbody>
<tr class="table-active">
<td>{{rpt.member.name}}</td>
<td>{{rpt.member.status}}</td>
<td>{{rpt.member.email}}</td>
<td>{{rpt.member.phone}}</td>
</tbody>
{%endfor%}
I guess it works
Thanks, I ended up using fetch-related and had to make adjustments to my template.
<tr>
<th>Name</th>
<th>Status</th>
<th>Email</th>
<th>Phone</th>
</tr>
</thead>
{%for rpt in report%}
{%for rpts in rpt.memberspresent_set.all%}
<tbody>
<tr class="table-active">
<td>{{rpts.name}}</td>
<td>{{rpts.status}}</td>
<td>{{rpts.email}}</td>
<td>{{rpts.phone}}</td>
</tbody>
{%endfor%}
{%endfor%}

Django printing many to many children not in same order as input

I have a Tourguide model with a many to many relationship with Places. Both models are defined as :
class Tourguide(models.Model):
id = models.AutoField(db_column='ID', primary_key=True, unique=True)
title = models.CharField(db_column='Title', max_length=255, blank=True)
places = models.ManyToManyField(Place, db_column='placesdj')
places_app = models.CharField(max_length=255, db_column='places')
created_on = models.DateTimeField(db_column='Created_On', default = now)
class Meta:
managed = False
db_table = 'tourguide'
def __str__(self):
return self.title
class Place(models.Model):
place_id = models.AutoField(db_column='ID', primary_key=True)
place_name = models.CharField(db_column='Place_Name', max_length=255)
address_line_1 = models.CharField(db_column='Address_Line_1', max_length=255)
address_line_2 = models.CharField(db_column='Address_Line_2', max_length=255)
area = models.CharField(db_column='Area', max_length=255)
class Meta:
managed = False
db_table = 'Place'
def __str__(self):
return self.place_name
THE PROBLEM
When I try to print the places in a tourguide using :
{% for place in tour.places.all %}
<tbody>
<td>{{ forloop.counter }}</td>
<td>id: {{place.place_id}}, {{ place.place_name }} </td>
<td> {{ place.description }} </td>
</tbody>
{% endfor %}
The order of the places is all random and not the same as the order I inputed it as. I want to print the places in the same order that I placed them in. My view for listing the tourguides and places within them is as so.
def tour_list(request, template_name='tourguides/tour_list.html'):
tourguide_list = Tourguide.objects.all()
paginator = Paginator(tourguide_list,6)
page = request.GET.get('page')
tourguides = paginator.get_page(page)
data = {}
data['tourguides'] = tourguides
return render(request, template_name, data)
Update
I have an array of place id's in the tourguide table, is there a way i can use that?
Relational databases do not sort rows by default, and since they are internally stored in all kinds of weird data structures, there is no "input order" either.
As a workaround, you can use the automatically generated place_id field as a sort key as it is pretty much guaranteed to go up as new entries are created. You can add a default sorting to your Place class, for example:
class Place(models.Model):
...
class Meta:
...
ordering = ('place_id',)
That would guarantee that any queries that will return a Place queryset will be ordered by place_id by default (i.e. unless you have an explicit .order_by() clause).

Identifying & modifying single field in Django Model

I'm using Django to build a small system to control the lending and borrowing of some stuff our Students Café lend to students.
I'm having trouble identifying an object after a form submit, I want to mark the object as 'unaivalable' (disponible means available, so I want to set it to False) so next time someone comes to ask for THAT object, it will not show up in the 'lending' form.
All I need is a hint on how to achieve it, I've been looking through Django docs, and this site, with no success. Thanks in advance for the tips!
models.py
class Mate(models.Model):
color = models.CharField(max_length=2,
choices=COLOR_CHOICES, default=u'RO')
disponible = models.BooleanField(default=True)
def __unicode__(self):
return self.color
class Prestamo(models.Model):
cliente = models.ForeignKey(Usuario, null=False, blank=False)
mate = models.ForeignKey(Mate, null=False, blank=False)
termo = models.ForeignKey(Termo, null=False, blank=False)
bombilla = models.ForeignKey(Bombilla, null=False, blank=False)
fecha = models.DateTimeField(null=False, blank=False)
devuelto = models.BooleanField(default=False)
fecha_devolucion = models.DateTimeField(null=True, blank=True)
def __unicode__(self):
return str(self.pk)
views.py
#login_required
# Add_prestamo means 'Add lending' this basically deals with prestamo model, but i want to alter 'mate' objects here too.
def add_prestamo(request):
if request.method == 'POST':
form = PrestamoForm(request.POST,
auto_id=False, error_class=DivErrorList)
if form.is_valid():
prestamo = form.save(commit=False)
if request.POST.get('usuarios'):
miuser = request.POST.get('usuarios', '')
else:
miuser = ''
prestamo.cliente = Usuario.objects.get(nombre__exact=miuser)
# I KINDA NEED SOMETHING RIGHT HERE
prestamo.fecha = timezone.now()
prestamo.devuelto = False
prestamo.save()
return HttpResponseRedirect(reverse('list-prestamos'))
else:
form = PrestamoForm()
return TemplateResponse(request,
'gester/add_prestamo.html', {'form': form, })
add_prestamo.html
<form action="" method="post">
{% csrf_token %}
<table>
<tr>
<td>
<div class="ui-widget">
<label for="usuarios">Usuario: </label></td><td>
<input id="usuarios" name="usuarios">
</div>
</td>
</tr>
{{ form.as_table }}
</table>
<input class="btn" type="submit" value="Crear" />
</form>
In the template I show the form with a {{ form.as_table }} it display a select, but many of them (mates) have the same color, so when I get through POST in my view, how do I identify the exact object to alter the 'disponible' field value?
I really don't understand your codes but because you mention disponible, I hope this is what you mean.
prestamo.fecha = timezone.now()
prestamo.devuelto = False
//Because Prestamo model has a foreignkey for Mate model.
//The Mate model contains the disponible field which you want to access
// (to set it to False or unavailable)?
//This is how to access and update it.
prestamo.mate.disponible = False
prestamo.mate.save()
prestamo.save()

Django template table formatting

I am building a student test results template but am having a problem. Currently I have created 2 tests (Maths and Spelling) in my Tests model. The problem is, if I enter the data (scores) for the second test (Spelling) for a student first, the score get incorrectly placed in the template - the score gets placed in the Maths column and not the Spelling column. It gets corrected/moved into the spelling column as soon as I enter the same student’s name in the Maths test. It is a minor issue, but the result still is being put in the wrong place and I don’t know why.
I must be doing something wrong. I am missing some sort of filtering I guess. Hopefully the code below will help explain it further. Thanks.
Models.py
class Student(models.Model):
first = models.CharField(max_length=100)
last = models.CharField(max_length=100)
gender = models.CharField(max_length=1)
teacher = models.ForeignKey(Teacher)
def __unicode__(self):
return "%s %s" % (self.first, self.last)
class Test(models.Model):
name = models.CharField(max_length=100)
Out_of = models.IntegerField(null=True, blank=True)
def __unicode__(self):
return self.name
class Meta:
ordering = ['name']
class Display(models.Model):
name = models.ForeignKey(Student, related_name='art')
test = models.ForeignKey(Test)
one = models.IntegerField(null=True, blank=True)
two = models.IntegerField(null=True, blank=True)
three = models.IntegerField(null=True, blank=True)
# views.py
def test(request):
return list_detail.object_list(
request,
queryset = Student.objects.all(),
template_name = 'display.html',
template_object_name = 'results',
# display.html
<table>
<tr>
<th>First</th>
<th>Name</th>
<th>Maths</th>
<th>Spelling</th>
</tr>
{% for item in results_list %}
<tr>
<td> {{ item.first }} </td>
<td> {{ item.last }} </td>
{% for x in item.art.all %}
<td> {{ x.one }} </td>
{% endfor %}
{% endfor %}
</tr>
</table>
# admin.py
class StudentInline(admin.TabularInline):
model = Display
class TestAdmin(admin.ModelAdmin):
inlines = [StudentInline]
The problem is you need to somehow order the item.art.all() in same order that of your table columns (ie. math numbers and then spelling). Also need to handle cases when only one of the test result is added.
But there isn't straight forward way of achieving this, you can't have foreign key (or relationship) member for ordering in Meta class.
So can have a method in your Display model to return list in preferred order and call it from template.
Sample solution below:
class Student(models.Model):
first = models.CharField(max_length=100)
last = models.CharField(max_length=100)
gender = models.CharField(max_length=1)
teacher = models.ForeignKey(Teacher)
def __unicode__(self):
return "%s %s" % (self.first, self.last)
#this would return in order as math, spelling
def get_result_list_in_order(self):
rlist = []
for tname in ['math', 'spelling']:
rtest = self.art.filter(test__name__iexact=tname)
if rtest:
rlist.append(rtest[0]) #add the first entry from filtered queryset
# or do
#rlist.extend(rtest)
else
rlist.append(None)
return rlist
So what you can in template is
{% for x in item.get_result_list_in_order %}
<td> {{x.one}} </td>
{% endfor %}