I have the following model setup:
class Model1(models.Model):
val1 = models.CharField(max_length=25, blank=True)
val2 = models.CharField(max_length=25, blank=True)
user = models.ForeignKey('users.User', on_delete=models.PROTECT, related_name='model1')
class Model2(models.Model):
val3 = models.BinaryField()
model1_link = models.ForeignKey(Case, on_delete=models.CASCADE, related_name='model2')
class Model3(models.Model):
id = models.BigAutoField(primary_key=True)
model2_link = models.ForeignKey(Model2, on_delete=models.CASCADE, related_name='model3')
class Model4(models.Model):
id = models.BigAutoField(primary_key=True)
model3_link = models.ForeignKey(Model3, on_delete=models.CASCADE, related_name='model4', null=True, default=None)
pred = models.CharField(max_length=50)
In my HTML template, I have a section where I iterate over entries from Model1 (e.g. val1), and would like to be able for each value, to include field 'pred' from Model4. Models 1-4 are daisy-chained through their FK`s at the moment. Yes, I know I could just include FK in Model4 linking it to Model1, but from logical point of view, I do not prefer this option at the moment.
Anyway, expression like this does not get the job done on my end:
...
{% for entry in model1_entries %}
...
{% if user.is_superuser and entry.model2.model3.model4.count > 0 %}
something here
{% endif %}
...
{% endfor %}
I figure the problem has something to do with the fact that call model1.model2 returns a set of all model2's related to model1, but I dunno how I can pick one in this expression and run with it through the rest of models before reaching #4.
Any ideas?
I'd add a method to your Model1 something like:
class Model1(models.Model):
val1 = models.CharField(max_length=25, blank=True)
val2 = models.CharField(max_length=25, blank=True)
user = models.ForeignKey('users.User', on_delete=models.PROTECT, related_name='model1')
def get_model4_count(self):
count = 0
for m2 in Model2.objects.filter(model1_link=self):
for m3 in Model3.objects.filter(model2_link=m2):
count += Model4.objects.filter(model3_link=m3).count()
return count
your template says count, so this uses, count, but you can update to whatever you want.
At least that would allow you to write a test/debug that your method is returning the correct data, and allow you to easily use it in your template.
...
{% for entry in model1_entries %}
...
{% if user.is_superuser and entry.get_model4_count > 0 %}
something here
{% endif %}
...
{% endfor %}
Related
i wrote a code about music and used Many-To-Many-Field() as genre but when i try to show genres it just shows : Genre['a number']
template:
{% extends 'pages/base.html' %}
{% block content %}
<form>
{% if mdata.image %}
<img src="mdata.image.url" height="500" width="500">
{% endif %}
{% for field in form %}
<p>{{ field.label }} : {{ field.value}}</p>
}
{% endfor %}
</form>
edit
{% endblock %}
models is here:(i didnt know which one u need so pasted both of them)
from django.db import models
from django.contrib.auth.models import User
class Genre(models.Model):
name = models.CharField(unique=True,max_length=20)
def __str__(self):
return self.name.title()
class Mdata(models.Model):
name = models.CharField(max_length=100)
artist = models.CharField(max_length=150)
album = models.CharField(max_length=100)
nation = models.CharField(max_length=100)
duration = models.DecimalField(max_digits=4,decimal_places=2)
released_in = models.DecimalField(max_digits=4,decimal_places=0)
uploaded_at = models.DateTimeField(auto_now_add=True)
image = models.ImageField(upload_to='images/',blank=True,null=True)
audio = models.FileField(upload_to='audios/',null=True,blank=True)
genre = models.ManyToManyField(Genre)
uploader = models.ForeignKey(User,on_delete=models.CASCADE)
def __str__(self):
return self.name.title()+" by "+self.artist.title()
forms.py:(its just a simple form im using)
[![class MdataForm(ModelForm):
class Meta:
model = Mdata
fields =\[
'name',
'artist',
'album',
'genre',
'nation',
'duration',
'released_in',
'image',
'audio',
]
and here the render :dunno if this is enough
[1]: https://i.stack.imgur.com/T5eK2.png
This could be that you don't have a __str__ method on your Genre model. Add a __str__ method and return the genre name. That would be something like:
def __str__(self):
return self.name
self.name here being the field on your genre model used to specify the name. In the sample image below, I set the custom user to return the username by default, that way anywhere I call a user it will automatically show the name of the genre.
class CustomUser(AbstractUser):
id = models.UUIDField(primary_key=True, editable=False, default=uuid4)
email = models.EmailField(_("email address"), unique=True, null=True)
phone_number = PhoneNumberField(unique=True, null=True)
username = models.CharField(max_length=100, unique=True, null=True)
password = models.CharField(_("password"), max_length=128, null=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
verbose_name = "User"
verbose_name_plural = "Users"
def __str__(self):
return self.username
I want to filter a queryset that depends on another queryset that already depends on another queryset
My models.py
class Escola(models.Model):
id = models.AutoField(db_column='ID', primary_key=True)
nome = models.CharField(db_column='Nome', max_length=255, blank=True, null=True)
class Inscrio(models.Model):
id = models.AutoField(db_column='ID', primary_key=True)
escolaid = models.ForeignKey(Escola, models.DO_NOTHING, db_column='EscolaID', blank=True, null=True)
class Utilizador(AbstractBaseUser)
id = models.AutoField(db_column='ID', primary_key=True)
inscriçãoid = models.ForeignKey(Inscrio, models.DO_NOTHING, db_column='InscriçãoID', blank=True, null=True)
My views.py
def view_forms(request):
return render(request,
"main/view_forms.html",
{"escolas": Escola.objects.all(),
})
I am doing
{% for escola in escolas %}
{% for inscrio in escola.inscrio_set.all %}
{% for utilizador in inscrio.utilizador_set.all %}
<tr>
<td><center>{{inscrio.id}}</center></td>
<td><center>{{escola.nome}}</center></td>
<td><center>{{utilizador.id}}</center></td>
{% endfor %}
{% endfor %}
{% endfor %}
I am currently trying to get the Inscrio data from Escola.
But when I try to get the Utlizador data from the Inscrio I get nothing.
How can I do this?
Thanks in advance
Escola.objects.all method is not executed and is passed into the template as a method.
To fix this, add Parentheses to the end. Escola.objects.all()
If you are extending AbstractBaseUser then you should provide USERNAME_FIELD.
Here Utlizador doesn't save any record due to this error so correct as below
class Utilizador(AbstractBaseUser):
id = models.AutoField(db_column='ID', primary_key=True)
inscriçãoid = models.ForeignKey(Inscrio, models.DO_NOTHING, db_column='InscriçãoID', blank=True, null=True)
username = None
email = models.EmailField('email address', unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
Im new in python-django and i really need some help. This is my first question here. I´ve searched a lot on similar questions here but didnt find my needs. I am working on a restaurant website, developing in python and django and im facing very difficulties to make the restaurant menu. This data of the menu stays in a mysql db.
I searched for select_related and prefetch related a lot, i imagine one of these will help, but its not working.
So, i have 2 tables, category_menu and menu. I have to list all categories and all the items of these categories.
I have 2 models, category_menu and menu:
class category_menu(models.Model):
name_category = models.CharField(max_length=50, null=False)
class Meta:
default_related_name = 'categories'
def __str__(self):
return self.name_category
def get_absolute_url(self):
return reverse('category_menu_edit', kwargs={'pk': self.pk})
class menu(models.Model):
item = models.CharField(max_length=50, null=False)
description = models.CharField(max_length=300, null=True)
price = models.DecimalField(max_digits=10, decimal_places=2)
category = models.ForeignKey(category_menu,related_name='categories', null=True, on_delete=models.CASCADE)
class Meta:
default_related_name = 'menus'
def __str__(self):
return self.item
def get_absolute_url(self):
return reverse('menu_edit', kwargs={'pk': self.pk})
Im my views, i have the following:
query = category_menu.objects.prefetch_related('categories').all().distinct
datamenu = {'object_list': query}
return render(request, template_name, datamenu)
In my html, just the categories are listing, but the relationed items of the menu are not.
Could you help me?
You have used "categories" in both category.Meta.default_related_name and in menu.category.related_name. That could be causing some problems.
Try removing related_name='categories' from menu.category so that it looks like this:
category = models.ForeignKey(category_menu, null=True, on_delete=models.CASCADE)
Fix the indentation of your menu model. Meta, __str__() and get_absolute_url() should all be indented the same as they are on the category_menu model, e.g.:
class menu(models.Model):
item = models.CharField(max_length=50, null=False)
description = models.CharField(max_length=300, null=True)
price = models.DecimalField(max_digits=10, decimal_places=2)
category = models.ForeignKey(category_menu, null=True, on_delete=models.CASCADE)
# These have been indented
class Meta:
default_related_name = 'menus'
def __str__(self):
return self.item
def get_absolute_url(self):
return reverse('menu_edit', kwargs={'pk': self.pk})
Migrate the database, then attempt getting your queryset without prefetch:
query = category_menu.objects.all()
In your template, you can use nested for tags to list the categories and menu items within each category. Something like this:
{% for category in object_list %}
<h2>{{ category }} ({{ category.menus.count }})</h2>
{% for item in category.menus.all %}
<div>
<h3>{{ item }}</h3>
<p>{{ item.description }}</p>
<div>${{ item.price }}</div>
</div>
{% endfor %}
{% endfor %}
If it works, try prefetching using the default_related_name on your menu model:
query = category_menu.objects.prefetch_related('menus').all()
I am not focusing on the answer here, but it may be a step to solution at least.
on menu model, could you please change the field:
category = models.ForeignKey(category_menu, related_name='categories', null=True,
to this one:
category = models.ForeignKey(category_menu, related_name='menus', null=True)
I have a simple model (kit) connected by another model(client_id) with a foreign key, and also by a ManyToMany field. I have a form view for the kit model, in which user can create new kits, by selecting a few products, and then choosing which client it is made for. Problem is, the fields are being displayed correctly, but with only ID displayed, instead of their names. User does not know what is he selecting as he does not know the ID of all products or clients. How should I approach this ? I searched on SO but found nothing useful.
Code
models.py
# Parent model connected with both models
class Kit(models.Model):
kit_name = models.CharField(max_length=255, default=0)
kit_info = models.CharField(max_length=255, default=0)
components_per_kit = models.IntegerField(default=0)
product_id = models.ManyToManyField(Product, related_name='kit_product')
quantity_per_kit = models.IntegerField(default=0)
kit_client = models.ForeignKey(Client, on_delete=models.CASCADE, related_name='kit_owner')
# connected by foreign key
class Client(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
client_company = models.CharField(max_length=255, default=0)
client_name = models.CharField(max_length=255, default=0)
# connected by many to many field
class Product(models.Model):
product_id = models.IntegerField(default=0)
product_name = models.CharField(max_length=255, default=0)
product_short_code = models.CharField(max_length=255, default=0)
product_description = models.CharField(max_length=255, default=0)
template:
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<h2 class="mb-3">Add a new Kit</h2>
<div class="row">
<div class="col-md-6 col-sm-8 col-12">
<form method="post" novalidate>
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="btn btn-success">Save</button>
Nevermind
</form>
</div>
</div>
{% endblock %}
Current output
A fairly simple way to do this would be adding string representation to your models. For example in your product model add:
class Product(models.Model):
product_id = models.IntegerField(default=0)
product_name = models.CharField(max_length=255, default=0)
product_short_code = models.CharField(max_length=255, default=0)
product_description = models.CharField(max_length=255, default=0)
def __str__(self):
return self.product_name
Also, if you can use any of the model's fields in there, so for example if you want both id and name you can do something like:
def __str__(self):
return '{}: {}'.format(self.id, self.product_name)
Use __str__.
I asked for your code just in case you have some strange setup, but this is probably the easiest way for you to do it.
Change your Product model to this
class Product(models.Model):
product_id = models.IntegerField(default=0)
product_name = models.CharField(max_length=255, default=0)
product_short_code = models.CharField(max_length=255, default=0)
product_description = models.CharField(max_length=255, default=0)
def __str__(self):
return self.product_name
That will replace the Project Object (1) with whatever is in the product_name charfield.
EDIT: See below for a good comment about Python 2.
I have the following Models in Django.
from django.db import models
#Show DB Table Model
class Shows(models.Model):
show_key = models.CharField(primary_key=True, max_length=7)
show_date = models.DateField(blank=True, null=True)
show_venue = models.CharField(max_length=50, blank=True, null=True)
show_city = models.CharField(max_length=50, blank=True, null=True)
show_state = models.CharField(max_length=3, blank=True, null=True)
show_country = models.CharField(max_length=3, blank=True, null=True)
class Meta:
managed = False
db_table = 'shows'
#Songs DB Table Model
class Songs(models.Model):
song_key = models.CharField(primary_key=True, max_length=8)
show_key = models.ForeignKey('Shows', models.DO_NOTHING, db_column='show_key', blank=True, null=True)
song_name = models.CharField(max_length=100, blank=True, null=True)
song_set = models.CharField(max_length=20, blank=True, null=True)
song_track = models.IntegerField(blank=True, null=True)
song_encore = models.IntegerField(blank=True, null=True)
song_segue = models.CharField(max_length=1, blank=True, null=True)
song_notes = models.CharField(max_length=100, blank=True, null=True)
song_cover = models.CharField(max_length=50, blank=True, null=True)
song_with_guest = models.CharField(max_length=50, blank=True, null=True)
class Meta:
managed = False
db_table = 'songs'
I am trying make a query that will find all objects meeting a certain criteria, ie:
Shows.objects.filter(show_date__year=2000)
This above query would return multiple objects.
I need to take it a step further and pull all of the information from the Songs table/model relating to the filtered Show objects. The models are related in the sense that the "show_key" is a primary key / foreign key relationship and is one to many.
I also need to package all of the found data up into a usable form that I can iterate through and send to a jinja2 template.
For example:
{% for item in query_results %}
<ul>
<li>item.show_date</li>
<li>item.show_venue</li>
<li>item.show_city</li>
<li>item.show_state</li>
<li>item.show_country</li>
</ul>
<ul>
{% for song in item %}
<li>song.song_name</li>
<li>song.song_set</li>
<li>song.song_track</li>
<li>song.song_encore</li>
<li>song.song_segue</li>
<li>song.song_notes</li>
</ul>
{% endfor %}
Thanks in advance. Brent
Seems like what you're trying to do is follow a FK relationship backwards.
This is what it should look like in the template:
{% for show in query_results %}
<ul>
<li>show.show_date</li>
<li>show.show_venue</li>
<li>show.show_city</li>
<li>show.show_state</li>
<li>show.show_country</li>
</ul>
<ul>
{% for song in show.entry_set.all %}
<li>song.song_name</li>
<li>song.song_set</li>
<li>song.song_track</li>
<li>song.song_encore</li>
<li>song.song_segue</li>
<li>song.song_notes</li>
</ul>
{% endfor %}
This will actually force jango to issue one SQL query for every show. If you have too many it can be a pain. To avoid this you can tell Django to select related songs data when it queries for the shows. This can save you a lot of SQL queries.
Shows.objects.select_related(Songs).filter(show_date__year=2000)
I finally figured it out!
First I queried the Shows model/table and saved the results to query_results:
query_results = Shows.objects.filter(show_date__year=2018)
Then in my Jinja Template
{% for show in query_results %}
<ul>
<li>{{show.show_date}}</li>
<li>{{show.show_venue}}</li>
<li>{{show.show_city}}</li>
<li>{{show.show_state}}</li>
<li>{{show.show_country}}</li>
</ul>
<ul>
{% for song in show.songs_set.all %} #This is the key, calling the related "shows_set.all" This grabs the related objects from the Songs table/model
<li>{{song.song_name}}</li>
<li>{{song.song_set}}</li>
<li>{{song.song_track}}</li>
<li>{{song.song_encore}}</li>
<li>{{song.song_segue}}</li>
<li>{{song.song_notes}}</li>
{% endfor %}
</ul>
{% endfor %}