I'm using python 3.4.5 with Diango 2.0.2
I have 2 tables with a foreign key. For some reasons, I need to use 2 tables to store these data.
I want to generate a table which contain the following information.
program.name , program.program_id , program.filter(user=request.user.id).status(if exist, if not exist, keep it NULL)
models.py
class Program(models.Model):
name = models.CharField(max_length=128, null=True, blank=True, default=None)
program_id = models.AutoField(primary_key=True)
class ProgramInfo(models.Model):
pid = models.ForeignKey(Program, on_delete=models.CASCADE, null=True)
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
status = models.CharField(max_length=10, default=1003)
views.py
def program_list(request):
program = Program.objects.all()
return render(request, 'panel/program_list.html', {'program': program})
template
{% for prog in program %}
<tr>
<td> {{ prog.name }} </td>
<td> {{ prog.program_id }} </td>
<td> {{ "program's status of existing user" }} </td>
</tr>
{% endfor %}
How to generate a table which contain the following information?
program.name , program.program_id , program.filter(user=request.user.id).status
I have 2 solutions,
(1) generate a table and pass it to template
(2) send the program table to template, and use something like program.filter(user=request.user.id).status in "td"
But I don't know how to do it for these 2 solutions.
The table should be like this
NameA, 123, yes
NameB, 234,
NameC, 345, no
NameD, 456,
NameE, 567, no
ProgramInfo has a ForeignKey field pointing to a Program instance
pid = models.ForeignKey(Program, on_delete=models.CASCADE, null=True)
Thus, you can have multiple ProgramInfo instances linked to a single Program instance. To retrieve that list, simply use:
program_instance = Program.objects.get(id=123)
# gives you the list of ProgramInfo instances:
programinfo_list = program_instance.programinfo_set
You can find more information about Many to One relationships and Related objects in Django doc. FYI, instance.programinfo_set is a RelatedManager (a child class of the more generic Manager). Thus, it provides an interface to lookup instances contained in this relationship.
If you need to have only 1 to 1 relationship between your models, use a OneToOne field instead:
pid = models.OneToOneField(Program, on_delete=models.CASCADE, null=True)
Related
I have two models that look like;
class Body(models.Model):
body_id = models.AutoField(primary_key=True)
is_adult = models.BooleanField(default=False)
body = models.TextField()
add_user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
add_date = models.DateTimeField()
edit_user = models.CharField(max_length=25, blank=True, null=True)
edit_date = models.DateTimeField(blank=True, null=True)
category = models.ForeignKey(Category, models.CASCADE)
class Meta:
managed = True
db_table = 'jdb_body'
class BodyTag(models.Model):
body_tag_id = models.AutoField(primary_key=True)
body = models.ForeignKey('Body', models.CASCADE)
tag = models.ForeignKey('Tag', models.CASCADE, db_column='tag')
class Meta:
managed = True
db_table = 'jdb_body_tag'
def __str__(self):
return self.tag
I have a view that looks like;
def index(request):
latest_body_list = Body.objects.all().order_by('-body_id')
context = {
'latest_body_list': latest_body_list
}
return render(request, 'index.html', context)
That view gives me a list Body records no problem. I am trying to display Body records with their corresponding BodyTag records. What am I doing wrong?
You neeed a ManyToManyField in your class Body
tags = models.ManyToManyField('Tag')
To access
body = Body.objects.get(body_id=1)
tags = body.tags.all()
EDIT
My previous answer was incorrect because I did not see the more complex relationship. The problem is this: You have many BodyTag objects to one Body object, but you also have many BodyTag objects to one Tag object. So as shown in the image, BodyTag's BT4 and BT5 belong to Body's BODY1 and BODY2. That's why #chipchap31 is talking of a ManyToMany relationship.
If this is not the relationship you want, and from your comments I do not think that you want a ManyToMany field, then the BodyTag model should be either changed, or perhaps discarded. Perhaps relate Body to Tag directly using the ForeignKey, and then have a field in the Tag model that distinguishes it with the type of tag it is, so one type would be body, and you can use a choices field to show all the different types of Tags.
Previous answer (Incorrect)
If you mean displaying these in your template, then all you have to do is follow the ForeignKey relationship backwards. This is shown in the documentaion for the views, but it would look pretty much the same in the template. Something like:
{% for body in latest_body_list %}
{{ body }}
{% for tag in body.tag_set.all %}
{{ tag }}
{% endfor %}
{% endfor %}
The -set is what tells django to look backward in the ForeignKey relationship.
A perhaps better way, also shown in the documentation would be to define a related_name in your ForeignKey:
class BodyTag(models.Model):
body_tag_id = models.AutoField(primary_key=True)
body = models.ForeignKey('Body', models.CASCADE, related_name='tags')
tag = models.ForeignKey('Tag', models.CASCADE, db_column='tag')
Then your template could be written a little better:
{% for body in latest_body_list %}
{{ body }}
{% for tag in body.tags.all %}
{{ tag }}
{% endfor %}
{% endfor %}
I built a website with Python Django and part of it displays lines of already input data with the primary key next to it. Now I have separate user data by using a foreign key field in each one of my models and the specific user's data is only shown to that logged in user except that all the data regardless of the user is saved in one spot with the model shown in the admin interface(because I'm using foreign keys to separate data). My problem is that I need to display the primary key of just the logged-in user. Take this, for example, if User1 adds 1 line of data to their page then User2 adds 1 line of data on their page which will appear separate from one another, then User1 uploads another line of data, Then I user traditional primary key to number the data lines of User1 the numbers will be 1 and three instead of keeping them in numerical order of 1 and 2 and disregarding User2's data in the counting of the data. It's as if I need a separate primary key for each user. Sorry this is really hard to explain. I have found a temporary solution of using {{ forloop.revcounter }} to count in a for loop instead of using the primary key but the problem with this is that when data is deleted all the numbers above it go down one because this tag just counts how many times the for loop has looped. I have found no information of the internet about this and how to solve it beyond this. I might just be looking in the wrong places but I need help. Thanks!
EDIT:
models.py
class Sheet_Extinguisher(models.Model):
user = models.ForeignKey(User, default=True, related_name="Extinguisher", on_delete=models.PROTECT)
floor = models.CharField(max_length=5, choices=FLOOR_LEVEL_FE, blank=True, null=True, verbose_name='Floor / Level')
area_room = models.CharField(max_length=35, blank=True, null=True, verbose_name='Area / Room')
building_address = models.CharField(max_length=46, choices=BUILDING_ADDRESS, blank=True, null=True, verbose_name='Building and Address')
type = MultiSelectField(choices=TYPE_FE, blank=True, null=True, verbose_name='Type')
size = models.CharField(max_length=3, choices=SIZE_FE, blank=True, null=True, verbose_name='Size')
hydrostatic_date = models.DateField(blank=True, null=True, verbose_name='Last Hydrostatic Test')
mass_notes = models.CharField(max_length=20, blank=True, null=True, verbose_name='Mass Fire Tech Notes')
notes = models.TextField(max_length=500, blank=True, null=True, verbose_name="Inspector's note")
class Meta:
ordering = ['building_address']
def __str__(self):
return self.building_address or 'None'
def get_absolute_url(self):
return reverse('list_extinguisher')
HTML (with pk):
{% if filter.qs %}
{% for post in filter.qs %}
<tr>
<td><div class="item1" style="text-align: center;">{{ post.pk }}</div></td>
{% endfor %}
{% endif %}
HTML (just with forloop counter):
{% if filter.qs %}
{% for post in filter.qs %}
<tr>
<td><div class="item1" style="text-align: center;">{{ forloop.revcounter }}</div></td>
{% endfor %}
{% endif %}
Hellooo,
I am trying to add a feature to my admin where I can download order details from a PDF file, which has gone successful so far except that Order.Model is not completely appearing.
so I have 3 models: Item, OrderItem and Order. The Order has a Many-to-Many relationship with OrderItem and the OrderItem has a Foreign Key with Item.
In the template I am trying to loop between the Order.Items which is items = models.ManyToManyField(OrderItem) but it is not rendering any data.
Here is the models.py
class Item(models.Model):
title = models.CharField(max_length=100)
price = models.FloatField()
class OrderItem(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
ordered = models.BooleanField(default=False)
item = models.ForeignKey(Item, on_delete=models.CASCADE)
quantity = models.IntegerField(default=1)
variation = models.ManyToManyField(Variation)
class Order(models.Model):
items = models.ManyToManyField(OrderItem)
Here is the views.py
#staff_member_required
def admin_order_pdf(request, order_id):
order = get_object_or_404(Order, id=order_id)
html = render_to_string('pdf.html', {'order': order})
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'filename="order_{}.pdf"'.format(Order.id)
weasyprint.HTML(string=html).write_pdf(response)
return response
here is the url.py
path('admin/order/(<order_id>\d+)/pdf/', views.admin_order_pdf, name='admin_order_pdf')
Here is the pdf.html template which is only showing as highlighted
Ordered on: {{order.ordered_date}} <----------Showing
{% for order_item in order.items.all %}
{{ order_item.item.title }} <----------Not Showing
{% endfor %}
I even tried removing the forloop but still nothing happened
Ordered on: {{order.ordered_date}} <----------Showing
{{ order_item.item.title }} <----------Not Showing
I think I dont have enough information to answer, but from what I see here, you are only passing an order from the view (single order) and not a queryset or any other iterable to the template. Am I missing the queryset or iterable?
If you want to access other objects related to the Order (such as OrderItem) you are missing it in the template. From you models I can see that Order has a relationship with OrderItem and not Items. Items are the one you try to access in the view. (Do you even have an Items model?)
Removing the loop wont work, as there is no order_item variable available in the template.
You are using manytomany field with OrderItem. Hence in order to reach OrderItem, you will have to go via a through model which is created under the hood. You are accessing the through mode when writing order.items.all() instead of your OrderItem model. For further information see django docs here: https://docs.djangoproject.com/en/3.1/topics/db/examples/many_to_many/
Assuming you intention here is to create a manytomany relation between Order and Item models. Then here is how you should create your ManyToMany
class Item(models.Model):
title = models.CharField(max_length=100)
price = models.FloatField()
class OrderItem(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
ordered = models.BooleanField(default=False)
item = models.ForeignKey(Item, on_delete=models.CASCADE)
quantity = models.IntegerField(default=1)
variation = models.ManyToManyField(Variation)
class Order(models.Model):
items = models.ManyToManyField(Item, through='OrderItem')
This will resolve your problem.
#a-k First of all {{order.ordered_date}} this is not valid. Your Order model doesn't have any field or method ordered_date according to what you've shown here.
Ordered on: {{order.ordered_date}} # This is wrong and invalid
{% for order_item in order.items.all %}
{{ order_item.item.title }} # This is valid, use this method to render other fields
{% endfor %}
When you convert your above html code, it will generate pdf like this. item_1 here is the title of item. {{order.ordered_date}} didn't worked instead {{ order_item.item.title }} worked and it was renderd in the pdf.
The second snippet which is shared by you is invalid and will not show any dynamic data. It will just render Ordered on:
Ordered on: {{order.ordered_date}} <----------Invalid
{{ order_item.item.title }} <----------Invalid
I hope this resolves your queries.
I've read in the docs and stackoverflow but i cant figure out why my foreign key following isnt working, django just says that there is no such attribute as vote_story_set.all().
I have a table named story and one named vote_story and the story table has several foreign keys like a foreign to vote_story to get the number of votes for a news story.
According to the docs and the detailed answer here: *_set attributes on Django Models i created an object like this:
all_stories = Story.objects.all()
votes = all_stories.vote_story_set.all()
but this doesnt work since django says that there is no such attribute as "vote_story_set". The database table for story has the 'votes' attribute as a foreign key to the table Votes_story. From the examples ive seen this should be working so i dont understand why it doesnt. There is no foreign keys in the Votes_story table, just a primay key and the attribute 'votes' containing the number of votes.
Update:
Models and template is shown below for Story and Vote_story as well as the relevant view.
Models:
class Story(models.Model):
story_id = models.IntegerField(primary_key=True)
date_added = models.DateTimeField(auto_now_add=True)
date_modified = models.DateTimeField(auto_now=True)
title = models.CharField(max_length=150)
description = models.CharField(blank=True, null=True, max_length=2000)
story_text = models.TextField()
picture = models.ImageField(blank=True, null=True, upload_to="story/images")
storyAccessLevelID = models.ForeignKey(StoryAccessLevel)
categoryID = models.ForeignKey(Category)
votes = models.ForeignKey(Vote_story, blank=True, null=True)
comments = models.ForeignKey(Comment, blank=True, null=True)
def __unicode__(self):
return self.title
class Vote_story(models.Model):
votes = models.IntegerField()
def __unicode__(self):
return self.votes
In the file Vote_story is defined above Story so it can find it.
In Vote_story i let django create the primary key automatically unlike Story.
There is currently one vote for one of the stories added.
Template code (the relevant portion):
<table class="table table-hover">
<thead>
<tr>
<th>Title</th>
<th>Description</th>
<th>Date added</th>
<th>Votes</th>
<th>Comments</th>
</tr>
</thead>
<tbody>
{% for story in all_stories %}
<tr>
<td>{{ story.title }}</td>
<td>{{ story.description }}</td>
<td>{{ story.date_added }}</td>
<td>{{ story.votes }}</td>
<td>{{ story.comments }}</td>
</tr>
{% endfor %}
</tbody>
</table>
The view is like this:
def list_all_stories(request):
""" Show all stories """
all_stories = Story.objects.all()
return render(request, "base/story/all_stories.html", {'all_stories': all_stories})
all_stories is a queryset, not an instance. vote_story_set is an attribute on each instance within the queryset, not the queryset itself.
Plus, you seem to be confused about the direction of relations. If your ForeignKey goes from Vote to VoteStory, you don't need the reverse relation, you need the forward one, which is just whatever you called the field. Again, though, this is an attribute of each instance, not the queryset.
So I have a model called Car with a foreign key of a Manufacturer model. I also have a CarCharacterisitcs model with a foreign key of Car.
This is what the code looks like:
class Car(models.Model):
idcar = models.AutoField(primary_key=True)
manufacturer = models.ForeignKey(Manufacturer, null=True, blank=True, on_delete=models.SET_NULL)
name = models.CharField(max_length=765)
class Manufacturer(models.Model):
idmanufacturer = models.AutoField(primary_key=True)
name = models.CharField(max_length=765)
class CarCharacteristics(models.Model):
idcar_characteristics = models.AutoField(primary_key=True)
car = models.ForeignKey(Car, on_delete=models.PROTECT)
I am making a page that lets you add CarCharacteristics.
This is my form and view:
class CarCharacteristicsForm(ModelForm):
class Meta:
model = CarCharacterisitics
def add_car_characteristics(request):
if request.method == 'POST':
car_char_form = CarCharacterisiticsForm(request.POST)
if car_char.is_valid(:
car_char_form.save()
return HttpResponseRedirect('/cars/car-characterisitcs')
else:
car_char_form = CarCharacterisiticsForm()
return render(request, 'car_characteristics/add_car_characteristics.html',{'car_char_form': car_char_form,})
In my html page, I have this:
<h1>Car Characteristics</h1>
<form action="." method="POST">
{% csrf_token %}
<table id="characteristics_table">
<tr>
<td>
<table id="car_characterisitcs_table">
<td>{{ char_char_form.as_table }}</td>
</table>
</td>
</tr>
</table>
<p><input type="submit" value="Submit"></p>
</form>
When this form is displayed, I have a drop down select field with all my possible Car models. What I want is to have two select fields. I want the first to let you be able to select the Manufacturer and then the second to display all the possible Cars that have that manufacturer. Then when you submit the form, it assigns the Car you selected to the Foreign Key of the CarCharacterisitcs model.
If you go look at Advance Auto Parts, when you click "Your Vehicle", that is what I want to have. How do I do that?
You need to use AJAX to fetch the data for a selected manufacturer and populate the car field accordingly. This needs to be done inside the view code and return the car fetched data in to the template and use the template language to populate the field.