Issues with foreign key relationship - python

I have defined a relationship between two models of different app using foreign key and data is inserted into Db accurately with foreign key instance, but I want to fetch that data using Django ORM but I didn't get it, I have googled this issue and also checked stack-overflow questions but still my issues are not solved.
#models.py
class teamInfo(models.Model):
ownerID = models.IntegerField()
teamName = models.CharField(max_length=50)
def __unicode__(self):
return unicode(self.id)
class gameWorld(models.Model):
team = models.ForeignKey(teamInfo)
w = models.IntegerField(null=True)
l = models.IntegerField(null=True)
def __unicode__(self):
return unicode(self.id)
I have tried a few things in my views but nothing worked for me. Here is the latest thing I have tried in my views:
def teamStandings(request,template=None,context=None):
getAllTeamStat = gameWorld.objects.all()
for i in getAllTeamStat.teaminfo_set.select_related() :
raise Exception(i.teaminfo.teamName)
I simply want a Django ORM query which fetches data from both models so I can display the team name in templates

See here and try that:
class TeamStandingsView(ListView):
model = gameWorld
template = # Some template path here!
context_object_name = "games"
in template:
{% for game in games %}
{{ game.team.teamName }}
{% endfor %}

edit: this should work:
def teamStandings(request,template=None,context=None):
getAllTeamStat=gameWorld.objects.all()
for team in getAllTeamStat:
for teaminfo in team.teaminfo_set.all():
print teaminfo.teamName

Related

Can't display foreign key related object in Django DetailView

I've got a booking class which is related to Customer and Barber models. I can display all bookings using the detail view, however, can't figure out how to display a booking/bookings that a specific barber has. Basically, I want to get a booking or multiple bookings of a barber based on the ID given to the url.
Here is my model:
customer_id = models.ForeignKey(User, on_delete = models.CASCADE,)
barber_id = models.ForeignKey(Barber, on_delete = models.CASCADE)
timeslot = models.DateTimeField('appointment')
def __str__(self):
return f"{self.customer_id} {self.barber_id} {self.timeslot}"
def get_absolute_url(self):
return reverse("model_detail", kwargs={"pk": self.pk})
My view:
class GetBarberBooking(DetailView):
model = Booking
template_name = "barber_booking.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['barber'] = Booking.objects.filter(
id=self.kwargs.get('<str:pk'))
return context
My url path:
path('barber-booking/<str:pk>/', views.GetBarberBooking.as_view(), name='barber-booking'),
You can remove this piece of code:
context['barber'] = Booking.objects.filter(
id=self.kwargs.get('<str:pk'))
And in template just use:
{{ object.barber_id }}
And show all the booking for barber:
{{ object.barber_id.booking_set.all }}
It will show all the the barber. This works because of FK relation between Booking and Barber model. More information can be found in Django documentation. For reverse relation (Many to one), please check this documentation.
FYI, you do not need to create a field name suffix with _id, because Django creates that automatically for you.
Also, if you want to query a Barber, then you should use Barber as the model in the DetailView. Then you can use a similar query mentioned above:
# view
class GetBarberBooking(DetailView):
model = Barber
# template
{{ object.booking_set.all }}

Django how to add query results foreign key model to queryset

How can I get the Author model objects into a queryset through the foreign key of B model? I would like to use the Author objects in my template.
#Models.py
class Book(models.Model):
name = models.CharField(max_length=5)
class Author(models.Model):
# lots of fields
class B(models.Model):
author = models.ForeignKey(Author)
book = models.ForeignKey(Book)
selected_book = "ABC"
book = Book.objects.get(name=selected_book)
original_queryset = B.objects.filter(name=book)
for i in original_queryset:
print(i.author) # returns what i want
queryset = # get all i.author objects somehow
return render(request,"template.html", {"queryset": queryset}
Remove the for loop. then add the following line after the original_queryset = B.objects.filter(name=book) line->
queryset = original_queryset.author
If this doesn't work then let me know. I hope I can help you.
You can rename your B model's author field to authors, that makes your code more meaningful because ForeignKey field can store many data. In your code, you have made your B model's author field as a ForeignKey field, which means books can have multiple authors. You can see the django documentation of ForeignKey reference.
If you change as I told you then don't forget to run migration(python manage.py makemigrations and python manage.py migrate command in your cmd) and change the line queryset = original_queryset.author to queryset = original_queryset.authors
Another approach
You can pass the original_queryset in the context of the template,(i.e: {'queryset':original_queryset }) then in your template.html, you can add tages like this:
{% for book in queryset %}
<ul>
{% for author in book.author %}
<li>author.name</li>
....
{% endfor %}
</ul>
{% endfor %}
By doing these, you can place your books and authors in your template nicely. If it still shows error, message me, I hope I can help you.

How to use objects.filter(user=request.user) in Django templates?

I used PurchaseInfo.objects.filter(user=request.user).values() and want to show the result in templates. But, I get this error message:
FieldError at /auth/purchaseHistory/
Cannot resolve keyword 'user' into field. Choices are: id, product_name, product_price, purchase_addr, purchase_date, purchase_id, purchase_id_id, purchase_name, purchase_phone
purchaseinfo/models.py
class PurchaseInfo(models.Model):
purchase_id = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
purchase_name = models.CharField(max_length=30)
purchase_addr = models.CharField(max_length=100)
purchase_phone = models.CharField(max_length=15)
...and so on
customlogin/views.py
from purchaseinfo.models import PurchaseInfo
def purchaseHistory(request):
history = PurchaseInfo.objects.filter(user=request.user).values()
return render(request,'customlogin/purchaseHistory.html',{'history':history})
purchaseHistory.html
{% for i in history %}
<tr>
<td>{{i.purchase_id}}</td>
<td>{{i.purchase_name}}</td>
<td>{{i.purchase_addr}}</td>
<td>{{i.purchase_phone}}</td>
<td>{{i.product_name}}</td>
<td>{{i.product_price}}</td>
<td>{{i.purchase_date}}</td>
</tr>
{% endfor %}
How can I solve this problem?
Update your views to this:
history = PurchaseInfo.objects.filter(purchase_id=request.user).values()
In your model the foreign key relation to User model is purchase_id but in views you are trying to filter by user. You need to filter by purchase_id.
Most of time the error messages explain the problem pretty well, try to understand what it's saying and attempt to fix it on your own. Debugging is a nice skill to have.

How can I properly use related_name in django models to get back the class name?

I have an application called "school" inside one of my django projects.
Below is the code of models.py
from django.db import models
class Student(models.Model):
name = models.CharField(max_length=255)
birthday = models.DateField(blank=True)
class Class(models.Model):
name = models.CharField(max_length=255)
student = models.ForeignKey(Student,related_name='classes',null=True)
def __str__(self):
return self.name
And now, views.py:
from django.shortcuts import render
from .models import *
def test(request):
obj2 = Student.objects.get(name='john')
return render(request,'test/list.html', {'obj2':obj2} )
And finally, my template looks like this:
{% block content %}
<h2>
{{ obj2.classes }}
</h2>
{% endblock %}
In my template, I am using obj2.classes (i.e., responseobject.related_name). I want it to print the class name.
However when I access the site at http://127.0.0.1:8000/shop/ ,
it gives me this output:
shop.Class.None
How will I get the output as only "Class", that is the class name?
Would obj2._meta.get_field('classes').related_model.__name__ do the job? This will work on your view only, not on the template.
def test(request):
obj2 = Student.objects.get(name='john')
classes_name = obj2._meta.get_field('classes').related_model.__name__
return render(request, 'test/list.html',
{'obj2':obj2, 'classes_name': classes_name})
Using this method, you avoid to use obj2.classes, which hits the database to retrieve the object.
You can also get the verbose_name with obj2._meta.get_field('classes').related_model._meta.verbose_name.

Django - logic behind displaying relational tables in template

I have multiple related tables defined in my Django models:
# first models.py
from django.db import models
class Character(models.Model):
first_field = models.DateTimeField()
second_field = models.TextField()
# second models.py
from django.db import models
class Op(models.Model):
fk_character = models.ForeignKey('Character')
some_field = models.DateTimeField()
other_field = models.TextField()
class Participant(models.Model):
fk_op = models.ForeignKey('Op')
fk_character = models.ForeignKey('Character')
some_other_field = models.IntegerField(default=0)
For now, I'm sending this data from a view to template in a way like this:
# views.py
from django.shortcuts import render_to_response
from django.template import RequestContext
from second.models import MainModel
def home(request):
data = Op.objects.filter(some_field__isnull=True).order_by('-date')
rc = RequestContext(request, {'data':data})
return render_to_response('index.html', rc)
In this way I do have all the Op related data I need in my index.html template, but I'm struggling with logic to display this data in my template in a specific way. For example:
display a list of all Ops,
for each list item, check if Character is also a Participant in current Op item,
if it isn't, display some button, if it is than don't display the button
I know that template shouldn't handle any programming logic, but I'm also not sure what would be the best approach to solve this. Should I do all the logic in my view and construct a new object and send that object to my view or is there an easy way to solve this in template with current object I'm sending?
Update your model:
class Op(models.Model):
fk_character = models.ForeignKey('Character')
some_field = models.DateTimeField()
other_field = models.TextField()
def check_if_participant(self):
return bool(self.participant_set.all())
Display list of all Ops:
{% for op in data %}
{{op.some_field}}
{% if op.check_if_participant %}Yes - Character is participant {% endif %}
{% endfor %}

Categories