How to show name instad of id in django ForeignKey? - django

I have a model with a ForeignKey to itself.
models.py
class Person(models.Model):
name = models.CharField(max_length=20)
important_name = models.ForeignKey('Person', on_delete=models.SET_NULL, blank=True, null=True, related_name='first', verbose_name='Very Important Name')
def __str__(self):
return self.name
def get_fields(self):
return [(field.verbose_name, field.value_from_object(self)) for field in self.__class__._meta.fields]
And when i want to show my data with DetailView CBV in view it show id instead of name.
views.py
class DetailPerson(DetailView):
model = Person
template_name = 'panel/detail_person.html'
detail_person.html
<table class="table">
{% for label, value in object.get_fields %}
<tr>
<td>{{ label }}</td>
<td>{{ value }}</td>
</tr>
{% endfor %}
</table>
How can i show name instead of id?

Here we can use getattr instead of value_from_object, which will return us the related instance of Person instead of an ID.
def get_fields(self):
return [(field.verbose_name, getattr(self, field.name)) for field in self.__class__._meta.fields]
example:
from base.models import Person
a = Person.objects.first()
a.get_fields()
Returns
[('ID', 1), ('name', 'Joe'), ('Very Important Name', <Person: Bob>)]
Now, we may access all of Bob's attributes in the template as well, if the need arose.

Related

How can i get all the product categories a suppliers product belongs

I am working a Supplier Management System. I need to make a particular type of query which I am having issue implementing. I have the user models, and then the user_type which is of two types the suppliers and the admin. Of Course, the filter I need to implement is based of the supplier because only the supplier is able to create product in which they have to specify what categories as well.
My Problem: How can I get all categories a supplier products belongs to.
My Problem Edit: How can get each suppliers products and pass into the templates on the <td> tag
models.py
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(max_length=254, unique=True)
def get_email(self):
return self.email
class user_type(models.Model):
is_admin = models.BooleanField(default=False)
is_supplier = models.BooleanField(default=False)
user = models.OneToOneField(User, on_delete=models.CASCADE)
def __str__(self):
if self.is_supplier == True:
return User.get_email(self.user) + " - is_supplier"
else:
return User.get_email(self.user) + " - is_admin"
#property
def get_categories(self):
return Category.objects.filter(product__user=self.id).distinct()
class Category(models.Model):
name = models.CharField(max_length=256)
def __str__(self):
return self.name
class Product(models.Model):
name = models.CharField(max_length=36)
price = models.PositiveIntegerField()
category = models.ForeignKey(Category, on_delete=models.CASCADE)
quantity = models.PositiveIntegerField()
user = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.name
views.py
def Viewsupplier(request):
title = "All Suppliers"
suppliers = User.objects.filter(user_type__is_supplier=True)
categories = Category.objects.filter(product__user='2').distinct()
context = {"suppliers":suppliers, "title":title, "categories":categories}
return render(request, 'core/view-suppliers.html', context)
view-suppliers.html
<table class="table table-borderless table-data3">
<thead>
<tr>
<th>No</th>
<th>Email</th>
<th>Telephone</th>
<th>Category(s)</th>
<th>Country</th>
</tr>
</thead>
<tbody>
{% for supplier in suppliers %}
<tr>
<td>{{forloop.counter}}</td>
<td>{{supplier.email}}</td>
<td>{{supplier.telephone}}</td>
<td>{{supplier.get_categories}}</td>
<td>{{supplier.country}}</td>
</tr>
{% empty %}
<tr><td class="text-center p-5" colspan="7"><h4>No supplier available</h4></td></tr>
{% endfor %}
</tbody>
</table>
You can filter with:
Category.objects.filter(product__user=myuser).distinct()
where myuser is the user you want to filter on.
The .distinct(…) [Django-doc] will prevent returning the same Category that many times as there are Products for that user.

Pass OneToOne relationships to Django Templates

I am trying to setup a OneToOne relationship in Django in order to show data from TableA and TableB for a specific record.
I am having issues figuring out how to display it in my view, examples are out there but some seem a bit outdated or have solutions that I am not familiar with.
I have tried with some different calls in the views file as well as in my templates file without any luck, any input would be highly appreciated!
My models.py
from django.db import models
# Create your models here.
class tableA(models.Model):
created = models.DateTimeField(default=None)
published = models.CharField(max_length=50, default=None)
publisher = models.CharField(max_length=50, default=None)
code = models.CharField(max_length=25, null=True, unique=True)
class Meta:
db_table = 'tableA'
unique_together = (("publisher", "published"),)
def __str__(self):
return self.created
class tableB(models.Model):
tableA = models.OneToOneField(tableA, on_delete=models.CASCADE, primary_key=True, default=None)
code = models.CharField(max_length=50, default=None, null=True)
url = models.CharField(max_length=100, default=None, null=True)
class Meta:
managed = True
def __str__(self):
return self.tableA.code
My views.py
def nani(request):
data = TableA.objects.all()
return render(request, 'site/home.html', {'data':data})
My template
{% for test in data %}
<tr>
<td>{{ test.published }}</td>
<td>{{ test.publisher }}</td>
<td>{{ test.TableB.url }}</td>
</tr>
{% endfor %}
If the uppercase/lowercase letters are like you said, just do this, I just tested it.
views.py
from .models import tableA
def nani(request):
data = tableA.objects.all()
return render(request, 'site/home.html', {'data': data})
in your site/home.html :
{% for test in data %}
{{ test.published }}
{{ test.publisher }}
{{ test.tableb.url }}
{% endfor %}
and also something wrong about your str method. datetime is not a string format. so in your models.py, you have to fix this line like this:
def __str__(self):
return str(self.created)

Working with checkboxes and querying the database in Django

My goal is to create a page that lists all the courses available in the database and have the user select which courses they would like to be a tutor for.
I have a CustomUser model, a courses model, and finally a TutorTeachesCourse model that takes user and courses as foreign keys.
# model.py
from django.contrib.auth.models import AbstractUser
class CustomUser(AbstractUser):
is_tutee = models.BooleanField(default=False)
is_tutor = models.BooleanField(default=False)
courses = models.ManyToManyField(Courses)
class Courses(models.Model):
course_name = models.CharField(max_length=100, null = False)
course_number = models.CharField(max_length=100, null = False)
department = models.ForeignKey(Department, on_delete=models.CASCADE)
course_description = models.CharField(max_length=1000, blank=True)
#tutor = models.ManyToManyField(CustomUser) #moved m2m relationship to user model
objects = models.Manager()
def __str__(self):
return self.course_name
# forms.py
class EditTutoredCoursesForm(forms.Form):
model = CustomUser
course = forms.ModelMultipleChoiceField(
queryset = Courses.objects.all(),
widget = forms.CheckboxSelectMultiple,
)
def clean(self):
cleaned_data = super(EditTutoredCoursesForm, self).clean()
is_tutor = cleaned_data.get('is_tutor')
if not is_tutor:
raise forms.ValidationError('Validation error.')
def save(self,commit=True):
rel=super(EditTutoredCoursesForm,self).save(commit=False)
rel.is_tutor=self.cleaned_data['is_tutor']
if commit:
rel.save()
return rel
# views.py
def edit_tutored_courses(request):
user = request.user
if request.method == 'POST':
form = EditTutoredCoursesForm(request.POST)
if form.is_valid():
user.courses.set(form.cleaned_data['courses'])
user = form.save(commit=True)
messages.success(request, 'Success!')
return redirect(reverse('view_profile'))
else:
form = EditTutoredCoursesForm()
context = {
'form' : form,
}
return render(request, 'edit_tutored_courses.html', context)
And here the page where the user selects/unselects the courses they wish to tutor/not tutor.
# edit_tutored_courses.html
<table style="width:50%">
<tr>
<th>Course Name</th>
</tr>
<form method="POST" action="">
{% csrf_token %}
{% for is_tutor in form %}
{% for course in is_tutor %}
<tr>
<td>{{ course }}</td>
<td>{{ user }}</td>
</tr>
{% endfor %}
{% endfor %}
</table>
<input type="submit" value="Save Changes"/>
</form>
I can display the courses on my page but I don't know how to make changes to the database. I want the checkboxes to mean that once I click "submit" the table TutorTeachesCourses populates with that user with the checked courses, and if I uncheck the boxes it means it deletes the existing one. (That means I also need to make the page automatically check the boxes that exists int he database. How do I do all of this?

foriegn key object not iterable in template

I have basic models for a section, subsection and clause. 1 section can hold multiple subsections. Each subsection can hold multiple clauses. The models look like:
**models.py**
class Clause(models.Model):
number = models.CharField(max_length=8, unique=True)
requirements = models.TextField(max_length=2000, unique=False, blank=True, null=True)
documentation = models.TextField(max_length=2000, unique=False, blank=True, null=True)
class Subsection(models.Model):
number = models.CharField(max_length=5, unique=True)
name = models.CharField(max_length=150, unique=False)
descriptor = models.TextField(max_length=2000, unique=False, blank=True, null=True)
clause = models.ForeignKey(Clause, on_delete=models.DO_NOTHING, related_name="clause")
class Section(models.Model):
number = models.CharField(max_length=2, unique=True)
name = models.CharField(max_length=150, unique=False)
descriptor = models.TextField(max_length=2000, unique=False, blank=True, null=True)
subsection = models.ForeignKey(Subsection, on_delete=models.DO_NOTHING, related_name="subsection")
basic view function to call the desired section:
**views.py**
def main(request):
form = MainSearchForm()
user = request.user
sections = []
show_results = True
if 'query' in request.GET:
show_results = True
query = request.GET['query'].strip()
if len(query) <= 2:
sections = Section.objects.filter(number__iexact=query)
if sections:
records = sections
tpl = "display_console.html"
context = {'user': user, 'records': records, 'form': form}
return render(request, tpl, context)
else:
tpl = "main.html"
context = {'user': user, 'form': form}
return render(request, tpl, context)
unfortunately, I can't get my template to return my subsection data. The following returns a 'Subsection' object is not iterable error:
**template**
<table class="section_tb">
{% if records %}
{% for record in records %}
<tr>
<td>{{ record.number }}</td><td>{{ record.name }}</td>
</tr>
{% for item in record.subsection %}
<tr>
<td>{{ item.number }}</td><td>{{ item.name }}</td>
</tr>
<tr>
<td colspan=2>{{ item.descriptor }}</td>
</tr>
{% endfor %}
</table>
{% endfor %}
{% else %}
{% endif %}
substituting:
{% for item in record.subsection.all %}
for:
{% for item in record.subsection %}
removes the error message, but doesn't return any data. Is there something obvious I'm doing wrong?
This is because Section can have only one Subsection.
So you can access the subsection with just {{record.subsection}} so no forloop needed here.
As a tip remember when you usea one to many, the one is where the foreign key is defined.
The model that store the foreign key will always store only one foreign key.
If you want to access the many foreign keys from the other side use the model_name_in_lowercase_set or define a related name in models.ForeignKey(..., related_name="something") then you can call something_set

Reverse for Model with Slug in URL not working

I have a parts.html page that references the model Part, the page I am having issue with is the Part List Generic Model view. The purpose of it is to list all of the parts on a page and show the category next to it. Each part has a foreignkey "category". I am trying to create a Slug URL from the Part list view to the Category detail page, but I receive this error when I go to the partlistview page. I can access the Category page with portal/category/category where the second category at the end is a category in the database.
Note: The entire python files below are to scale, I only pasted in relevant information, as it would be too much info.
django.urls.exceptions.NoReverseMatch: Reverse for 'category-detail' with arguments '('',)' and keyword arguments '{}' not found. 1 pattern(s) tried: ['portal/category/(?P<slug>[-\\w]+)/$']
Views.py
class PartDetailView(LoginRequiredMixin, generic.DetailView):
model = Part
template_name = 'portal/part.html' # Option - Specify your own template name/location
class PartListView(LoginRequiredMixin, generic.ListView):
model = Part
#queryset = Part.objects.filter(is_active=True) #.prefetch_related('user') #hos
paginate_by = 100
https://simpleisbetterthancomplex.com/tutorial/2017/03/13/how-to-create-infinite-scroll-with-django.html
template_name = 'portal/parts.html' # Option - Specify your own template name/location
context_object_name = 'part_list'
#def get_queryset(self):
#return Category.objects.all()
def get_context_data(self, **kwargs):
context = super(PartListView, self).get_context_data(**kwargs)
context['category'] = Category.objects.all()
return context
class CategoryDetailView(LoginRequiredMixin, generic.DetailView):
model = Category
template_name = 'portal/category.html' # Option - Specify your own template name/location
slug_field = 'category'
slug_url_kwarg = 'category'
Models.py
#python_2_unicode_compatible
class Category(BaseModel):
"""
Model representing a part type (wiper, wheel, brake).
"""
id = models.BigAutoField(primary_key=True)
category = models.CharField(max_length=120, help_text=_("Category to organize parts into (wheel, wiperblade, brake)"))
slug = models.SlugField(editable=False, unique=True, db_index=True)
def __str__(self):
return '%s' % (self.category)
def get_absolute_url(self):
return reverse('portal:category-detail', kwargs={'slug': self.slug}) # str(self.trailer_number) kwargs={'slug': self.slug} instead of args=[self.slug]??
def save(self, *args, **kwargs):
self.slug = slugify(self.category)
super(Category, self).save(*args, **kwargs)
class Meta:
db_table = 'category'
verbose_name = _('category')
verbose_name_plural = _('categories')
ordering = ['category']
#python_2_unicode_compatible
class Part(BaseModel):
id = models.BigAutoField(primary_key=True)
name = models.CharField(max_length=120, help_text=_("The unique name or part number to identify this particular item"))
category = models.ForeignKey(Category, on_delete=models.PROTECT, help_text='Category to organize parts into (wheel, wiperblade, brake)', related_name='part', null=True, blank=True)
brand = models.CharField(max_length=80, blank=True, help_text=_("The name of the manufacturer that originaly built this part"), null=True)
minimum_inventory_quantity = models.PositiveSmallIntegerField(default=0, help_text=_("The minimum inventory quantity of this part before more need to be ordered"))
def get_absolute_url(self):
return reverse('portal:part-detail', args=[str(self.id)])
def __str__(self):
return '%s - %s' % (self.name, self.brand)
class Meta:
unique_together = ("name", "brand",) #NOTE: Each SKU + Carrier should also be unique together #unique_together = (("name", "manufacturer"), ("sku", "Carrier"))
ordering = ["name", "brand",]
Urls.py
from django.conf.urls import url
from .views import PartDetailView, CategoryDetailView, PartListView, PartInstanceDetailView, PartVariantDetailView
urlpatterns = [
url(r'^parts/$', PartListView.as_view(), name='parts'),
url(r'^parts/(?P<pk>\d+)/$', PartDetailView.as_view(), name='part-detail'),
url(r'^category/(?P<slug>[-\w]+)/$', CategoryDetailView.as_view(), name='category-detail'),
]
parts.html
<div class="table-responsive">
<table class="table table-hover table-bordered table-striped">
<thead>
<tr>
<th>Category</th>
<th>Name</th>
<th>Brand</th>
<th>Model Number</th>
<th>Variants</th>
<th>Stock</th>
<th>Locations</th>
</tr>
</thead>
<tbody>
{% for part in part_list %}
<tr>
<td><strong>{{ part.category.category }}</strong></td>
<td><a href="{% url 'portal:part-detail' part.pk %}">{{ part.name }}</td>
<td>{{ part.brand }}</td>
<td>{{ part.part_variant.model_number }}</td>
<td>{{ part.count_all }}</td>
<td>{{ part.count_all }}</td>
<td>{{ part.section.zone }}</td>
</tr>
{% empty %}
{% if request.GET.q %}
<tr>
<td colspan="7" class="text-center bg-warning">No trailers found.</td>
</tr>
{% else %}
<tr>
<td colspan="7" class="text-center bg-warning">There are no trailers in the system.</td>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
</div>
I'm not entirely sure but I think your urls.py need an app_name = portal before the urls list.
Read up more in the docs.
Your url pattern is expecting a keyword argument, but the url template tag is passing the category slug as an unnamed argument.
Just do this {% url "portal:category-detail" slug=category.slug %},
because in your url pattern you named your capture group "slug".
Also, make sure category.slug is actually returning something.