I created a model named MenuItems which will allow for me to enter all of the items that a restaurant has on their menu, later I will use these on the front end. I also created a model name MenuGrouping so that on the front end, I can have Bootstrap tabs show the group_title and under each, show the items in that group. What field should I add in the MenuItems model to associate it to a group? I attempted to use group = models.ForeignKey(MenuGrouping) but then I run into the issue of showing each item in the specific group.
Models.py:
class MenuItems(models.Model):
menu_item_title = models.CharField(max_length=256)
menu_item_description = models.TextField()
menu_item_price = models.DecimalField(max_digits=4, decimal_places=2)
customer_favorite = models.BooleanField(default=False)
is_on_menu = models.BooleanField(default=True)
class Meta:
ordering = ('menu_item_title', )
class MenuGrouping(models.Model):
group_title = models.CharField(max_length=256)
Is there a relationship that I can add in the MenuGrouping model that I can associate multiple MenuItems?
Thank you in advance!
If I understand you correctly that you are trying to make groups like drink, food, desert and ... then here it is:
Each item can be only in one group (I mean soda is a drink and it can't be food too and etc). So what you need to do here is to add a field to MenuItems model.
your MenuItems should be like this:
class MenuItems(models.Model):
menu_item_title = models.CharField(max_length=256)
menu_item_description = models.TextField()
menu_item_price = models.DecimalField(max_digits=4, decimal_places=2)
customer_favorite = models.BooleanField(default=False)
is_on_menu = models.BooleanField(default=True)
group = models.ForeignKey(MenuGrouping)
Now to use this in your template first get the groups in view and send them to template and then:
{% for group in groups %)
# add your tabs or just print the group name. or how ever you want.
Group {{ group.group_title }}:
# and now you can list the items in this group here
{% for item in group.menuitems_set.all %}
Title is: {{ item.menu_item_title }}
Price is: {{ item.menu_item_price }}
...
{% endfor %}
{% endfor %}
If you need all items to be listed somewhere else out of groups or any other way just send the items to the template too.
Here is the Many to One relationship documentation :
Many-to-one relationships
Also you can add a m2m relation to MenuGrouping and add items to each group but then one item can be in multiple groups and for a restaurant menu I can't see how that might happen.
Related
Let's say I have the following django models:
class House(Model):
author = ForeignKey(settings.AUTH_USER_MODEL, on_delete=CASCADE)
title = CharField(max_length=200, default='')
text = TextField(default='')
rooms = IntegerField(null=True)
class Room(Model):
author = ForeignKey(settings.AUTH_USER_MODEL, on_delete=CASCADE)
title = CharField(max_length=200, default='')
text = TextField(default='')
house = CharField(max_length=200, default='')
furniture = IntegerField(null=True)
class Furniture(model):
author = ForeignKey(settings.AUTH_USER_MODEL, on_delete=CASCADE)
title = CharField(max_length=200, default='')
text = TextField(default='')
room = CharField(max_length=200, default='')
And I want to generate the following table in a template:
Room
In house
Amount of furniture
Living Room
Summer house
5
Kitchen
Summer house
8
Bedroom
Summer house
2
Bathroom
Main house
3
Where the column "Amount of furniture" counts the instances of the "furniture" model where the field "room" is equal to that of the entry in the column "room" for that row.
I'm trying to figure out how to do this, and I've landed on a few different ways - ranked from most ideal/pythonic to least ideal/pythonic.
Building some sort of mechanism into the model. This would be perfect, but I can't seem to find any obvious way to do it.
Adding a function that generates a dictionary in the view in views.py. Would be easy to build (gather names of "room", make a for loop doing a filter query for each room on the model "furniture", add a counter variable, and build a dictionary) but not very flexible or pythonic.
Using a third party module like datatables. Feels like overkill - but may be a better long term solution?
Setting up some real shenaningans in the template language. Since you can't declare variables in the template, i imagine this would be a spider web of nested loops, conditionals, and custom template tags.
Which approach should I go for here?
You should work a ForeignKey [Django-doc] to link models. This is part of database normalization [wiki] to prevent data duplication and making databases more manageable:
class House(Model):
author = ForeignKey(settings.AUTH_USER_MODEL, on_delete=CASCADE)
title = CharField(max_length=200, default='')
text = TextField(default='')
class Room(Model):
author = ForeignKey(settings.AUTH_USER_MODEL, on_delete=CASCADE)
title = CharField(max_length=200, default='')
text = TextField(default='')
house = ForeignKey(House, on_delete=CASCADE)
class Furniture(model):
author = ForeignKey(settings.AUTH_USER_MODEL, on_delete=CASCADE)
title = CharField(max_length=200, default='')
text = TextField(default='')
room = ForeignKey(Room, on_delete=CASCADE)
there is also no need to store the number of Rooms or Furniture: you can determine that when necessary. In your view you can query the Room model with:
from app_name.models import Room
from django.db.models import Count
def some_view(request):
rooms = Room.objects.select_related('house').annotate(
num_furniture=Count('furniture')
)
return render(request, 'app_name/some_template.html', {'rooms': rooms})
here we thus annotate the Rooms with the number of related Funiture with Count('furniture'). The database will simply count the number of Furnitures per Room: this is more robust since it does not require logic when creating, updating, removing a Furniture, Room, etc.
and in the template, you then can render the table with:
<table>
<thead>
<tr><th>Room</th><th>In house</th><th>Amount of furniture</th></tr>
</thead>
<tbody>
{% for room in rooms %}
<tr><td>{{ room.title }}</td><td>{{ room.house.title }}</td><td>{{ room.num_furniture }}</td></tr>
{% endfor %}
</tbody>
</table>
I need to retrieve distinct value from query set and display it on a div.
Here is my model.py:
class Persons(models.Model):
id = models.IntegerField(primary_key=True)
firstname = models.CharField(max_length=100)
lastname = models.CharField(max_length=100)
address = models.CharField(max_length=100)
dob = models.CharField(max_length=100)
salary = models.IntegerField
doj = models.DateField()
class Meta:
db_table = "test"
Here is my view.py:
def calender(request):
distinctyears = Persons.objects.all().values('doj').distinct()
year = {
"Items": distinctyears
}
return render(request, "home.html", year)
Here is my html :
<div>
{% for item in Items %}
<div class="numbers">{{ item.doj }}</div>
{% endfor %}
</div>
My code is not working. Any help will be highly appreciated.
Thank You!
You need to add .distinct([*fields]) at the end of your query.
Here's the difference. For a normal distinct() call, the database compares each field in each row when determining which rows are distinct. For a distinct() call with specified field names, the database will only compare the specified field names.
As stated all fields in a record are checked. Mostly likely in your case you are getting records with different field values (more likely a case if you are queries multiple tables ManyToMany or ForeignKey relations).
I am using two related models in my Django application. The objects so created in the models are being displayed using the listview class. In the child model I can create multiple rows based on some key date. When I try to display values from both the models (linked with an FK field), all the child objects for the respective FK fields are displayed (wherever more than one records are there).
Is there a way that I may use select distinct to filter out duplicate rows. I have tried:
myModel.objects.distinct().order_by('id')
but still getting all the child rows for the parent id.
In my template I am using:
{% for obj in object_list %}
{{ obj.<field1> }} <!-- field1: Parent model field -->
{% for item in obj.<child_model>_set.all %}
{{ item.<field2> }} <!-- field2: Child model field -->
{% endfor %}
{% endfor %}
My question is:
How do I filter out duplicate rows before the data is displayed?
The backend is sqlite3 on Django 2.0.6 / Python 3.6
Edit
This is how the current list is being generated:
The first column is pk of parent model record and the next column is for child records' pk.
What I am trying to get is:
Option 1: Get only the last (date wise) record for the combination of parent/child rec numbers (i.e. for parent record number 32, only the combination 32|156 should be displayed, and those with values for child records 149 and 148 should not be displayed).
OR
Option 2: Get all combination of records grouped by ParentModel pk field and ChildModel pk field to be shown separately in successive rows (as you can see, the multiple values for a parent record (wherever existing), is being shown in the same row, successive columns).
PS. I am sorry things are getting quite dense here.
Edit 2
This is the class view I am using for displaying data:
class myRateListView(ListView):
template_name = "rate_list.html"
context_object_name = 'ratelists'
model = ParentModel
def get_context_data(self, **kwargs):
context = super(myRateListView, self).get_context_data(**kwargs)
context.update({
'rate_item_list': ChildModel.objects.order_by('field3'),
})
return context
def get_queryset(self):
return ParentModel.objects.values('field1', 'childmodel__field2').distinct()
Here I am getting error :
Cannot resolve keyword 'childmodel' into field. Choices are....
I think my class view is wrong??
Edit 3
Models and view details:
models.py
class TptRateDoc(models.Model):
tpt_rate_doc_number = models.IntegerField(null=True, blank=True.....)
loc_from = models.ForeignKey(Location, related_name='locn_from', on_delete=.......)
loc_to = models.ForeignKey(Location, related_name='locn_to', on_delete=.......)
create_date = models.DateField(default=timezone.now,...)
class TptRateItems(models.Model):
tpt_doc_header = models.ForeignKey(TptRateDoc, on_delete=...)
tpt_rate_item_num = models.CharField(max_length=3, default=10,...)
tpt_rate_valid_from_date = models.DateField(null=True, verbose_name='From date')
tpt_rate_valid_to_date = models.DateField(null=True, verbose_name='To date')
tpt_rate = models.DecimalField(max_digits=7, decimal_places=2, null=True, blank=True,...)
views.py
class TptRateListView(ListView):
template_name = "tpt_rate_list.html"
context_object_name = 'tptrates'
model = TptRateDoc
def get_context_data(self, **kwargs):
context = super(TptRateListView, self).get_context_data(**kwargs)
context.update({
'tpt_rate_item_list': TptRateItems.objects.order_by('tpt_rate_valid_to_date'), # .distinct()
})
return context
def get_queryset(self):
# return TptRateDoc.objects.order_by('loc_from')
return TptRateDoc.objects.values('tpt_rate_doc_number', 'tptrateitems__tpt_rate_item_num').distinct()
Note: The commented out parts are what I had tried earlier.
did you try to catch the returned queryset of distinct filter to a new queryset? I mean like this:(* according docs, distinct will come after order_by())
queryset = myModel.objects.order_by('id').distinct()
and then pass this updated queryset to template.
return render(request, "html_file.html", { "objects": queryset})
On PostgreSQL only, you can pass positional arguments (*fields) in order to specify the names of fields to which the DISTINCT should apply. This translates to a SELECT DISTINCT ON SQL query. Here’s the difference. For a normal distinct() call, the database compares each field in each row when determining which rows are distinct. For a distinct() call with specified field names, the database will only compare the specified field names.
You have not stated when you consider objects to be "distinct". If you do somthing like
queryset = MyModel.objects.distinct()
your queryset will contain all the MyModel instances. Why? Because each instance will have a different id (or pk) even if all other fields are identical. So for distinct() to work you need to specifify the fields to consider, i.e. you need to use values(). So in order to get a queryset containing the distinct values of field2 in your ChildModel you would need to do something like
queryset = ChildModel.objects.values('field2').distinct()
So if I understand you correctly you want to display all "field1" values and associated "field2" values where "field2" values should be unique. What I would recomend is a 2 step approach.
First in your view create a queryset containing distinct combinations of field1 and field2, e.g.:
queryset = ParentModel.objects.values('field1', 'childmodel__field2').distinct()
and then pass this queryset to your template
return render(request, 'parent_child.html', {'objects': queryset})
Then, in order to do the hierachical rendering, you can use the {% regroup %} template tag as described in the docs:
{% regroup objects by field1 as obj_list %}
<ul>
{% for obj in obj_list %}
<li>
{{ obj.grouper }}
<ul>
{% for child in obj.list %}
<li>
{{ child.childmodel__field2 }}
</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
As OP has not posted his models these are the models used for this answer
class ParentModel(models.Model):
field1 = models.CharField(max_length=100)
class ChildModel(models.Model):
parentmodel = models.ForeignKey(ParentModel, on_delete=models.CASCADE)
field2 = models.CharField(max_length=100)
field3 = models.IntegerField()
I have a todo website that allows users to put a remind in a certain list, such as work, school, groceries, etc. However, I'm a bit lost on how to get the list name and their items to display.
Models.py:
class RemindList(models.Model):
parent_user = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
title = models.CharField(max_length=50)
class Reminder(models.Model):
remind_types = [('Regular', 'Regular'), ('Long Term', 'Long Term')]
title = models.CharField(max_length=100)
description = models.TextField()
remind_time = models.DateTimeField(blank=True)
parent_user = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
parent_list = models.ForeignKey(RemindList, on_delete=models.CASCADE, null=True)
type_of_remind = models.CharField(max_length=12, choices=remind_types, default='Regular')
complete = models.BooleanField(default=False)
Views.py:
#login_required(login_url='/login')
def home(request):
user = get_object_or_404(User, username=request.user.username)
context = {
'events': ToDoItem.objects.filter(parent_user=user),
'reminders': Reminder.objects.filter(parent_user=user, type_of_remind='Regular'),
'long_term_reminders': Reminder.objects.filter(parent_user=user, type_of_remind='Long Term'),
'remind_list_items': RemindList.objects.filter(parent_user=user),
}
return render(request, 'main/home.html', context)
I can pass through the list names, and I planned to just loop through them and add Reminder.objects.filter(parent_user=user, type_of_remind='Regular', parent_list=list_name) to context. However, theres no way to loop through them on the html side (can't do for loop because there are other context types), and you can't filter them on the html side (correct me if I'm wrong). Is there another way to do this?
Ok, it took me a few readings, but if what I understand is correct you want to be able to iterate over the ReminderList objects and also list out the Reminder items under each one.
My suggestion would be to add a method to ReminderList that returns the items in that list, you could then do something like this in your template
{% for list in reminder_lists %}
... List header stuff goes here ...
{% for item in list.get_reminder_items %}
... Print the item ...
{% endfor %}
{% endfor %}
(The Django templating language can be a little interesting in that object.identifier can map to either an attribute or an object method - this can be useful for cases like these).
I have a model called Address and it has about 7 different fields. The corresponding form for this model is completely optional and the user may fill in either all 7 fields or just 1 field or none of the fields. There are no required fields here.
Now, if the user has filled only the city and country field, how would I in my class method fetch only those fields and then display it properly in the template?
This is the closest I've come to achieving what I want:
class Address(models.Model):
address_name = models.CharField(...)
line1 = models.CharField(...)
line2 = models.CharField(...)
line3 = models.CharField(...)
city = models.CharField(...)
state = models.CharField(...)
zipcode = models.CharField(...)
country = models.CharField(...)
def get_fields(self):
values = []
for field in Address._meta.fields:
if field.name in ('line1', 'line2', 'line3', 'city', 'state',
'postcode', 'country'):
if field.value_to_string(self):
values.append(field.value_to_string(self))
return values
In my template:
{% for field in address.get_fields %}
{{field}}{% if not forloop.last %}, {% else %}.{% endif %}
{% endfor %}
Now this achieves almost what I want, but in one of the test cases, if only one field has been filled out (for ex: only country was filled), it prints:
, US.
How do I make it say only US instead. Basically, the address format I want is:
{{line1}}, {{line2}}, {{line3}}, {{state}} - {{zipcode}}, {{country}}.
Is this kind of formatting possible at all with the way my model currently is? I even tried using {% if %} before each variable, but, then again, the commas don't sit well. What are my options here?