Django display multiple uploaded files - django

I am trying to display multiple uploaded file URLs but I'm not sure how to do it. I am a form that the users can use to upload multiple files that are working perfectly but now I want to be able to display these files. For instance, a company can have more than one file.
class InternationalCompany(models.Model):
International_company_Name = models.CharField(max_length=50)
International_company_Id = models.CharField(max_length=50)
options = (
('Yes', 'Yes'),
('No', 'No'),
)
Does_it_have_a_Financial_Dealers_License = models.CharField(max_length=20, choices=options, null=True)
Register_Office = models.TextField(max_length=500, null=True)
Beneficial_owner = models.CharField(max_length=100, null=True)
Beneficial_owner_id = models.FileField(upload_to='passport/pdf/',null=True)
expire_date = models.DateField(null=True)
BO_Phone_number = models.IntegerField(null=True)
BO_Email_Address = models.EmailField(null=True)
BO_Residential_Address = models.TextField(max_length=200, null=True)
def __str__(self):
return self.International_company_Name
class SupportDocuments(models.Model):
Supporting_Documents = models.FileField(upload_to='support_doc/pdf/', null=True)
internationalcompany = models.ForeignKey(InternationalCompany, on_delete=models.CASCADE)
def __str__(self):
return self.Supporting_Documents.url
I try something like this but it only displayed one url of the file instead of the multiple urls for the files that are associate with that company.
{%for company in doc%}
<tr>
<td></td>
<td>{{company.internationalcompany.Beneficial_owner}}</td>
<td>{{company.Supporting_Documents.url}}</td>
</tr>
{%endfor%}
I have also try out this but it doesn't display anything.
{%for company in doc.Supporting_Documents.all%}
{{company.url}}
{%endfor%}
def supporting_doc(request, company_id):
doc = SupportDocuments.objects.filter(id=company_id)
return render(request, 'supporting_doc.html', locals())

First of all, it might be better to use context rather than locals() as discussed here
Second, the way you get the doc queryset is wrong. id=company_id The id of SupportingDocuments is different from company_id. What you really need to do is internationalcompany.id=company_id.
so views.py:
def supporting_doc(request, company_id):
documents = SupportDocuments.objects.filter(internationalcompany.id=company_id)
context = { "documents": documents}
return render(request, 'supporting_doc.html', context)
in template:
{% for doc in documents %}
{{ doc.internationalcompany.Beneficial_owner}}
{{ doc.Supporting_Documents }}
{% endfor %}
On a side note, it may be better to use all lowercases in fields. This way, it is easy to distinguish fields and models.

Related

Django can't display data from two models

I am trying to display data from two different models. The two models have a one-to-many relationship but I am not sure why it is not displaying the data from the MembersPresent model. Here are my models
and view
class fly_minute(models.Model):
mode = (
('Email', 'Email'),
('Zoom', 'Zoom'),
('Alternative', 'Alternative'),
)
mode_of_meeting = models.CharField(max_length=100, choices=mode, blank=False, )
date = models.DateField()
Time = models.TimeField()
minute_prepared_by = models.CharField(max_length=25)
location = models.CharField(max_length=25)
authorize_by = models.CharField(max_length=25)
item = models.TextField()
owner = models.CharField(max_length=25)
def __str__(self):
return self.mode_of_meeting
class MembersPresent(models.Model):
flyminute = models.ForeignKey(fly_minute, on_delete=models.CASCADE)
name = models.CharField(max_length=25)
status = models.CharField(max_length=25)
email = models.EmailField(max_length=25)
phone = models.IntegerField()
def __str__(self):
return self.name
#login_required(login_url='login_page')
def MinutesReport(request, minute_id):
report = fly_minute.objects.filter(id=minute_id)
return render(request, 'minute_report.html', locals())
{%for rpt in report%}
<tbody>
<tr class="table-active">
<td>{{rpt.flyminute.name}}</td>
<td>{{rpt.flyminute.status}}</td>
<td>{{rpt.flyminute.email}}</td>
<td>{{rpt.flyminute.phone}}</td>
</tbody>
{%endfor%}
You need to use 'prefetch_related()'
Returns a QuerySet that will automatically retrieve, in a single batch, related objects for each of the specified lookups.
This has a similar purpose to select_related, in that both are designed to stop the deluge of database queries that is caused by accessing related objects, but the strategy is quite different.
models.py
class MembersPresent(models.Model):
flyminute = models.ForeignKey(
fly_minute,
related_name='memberspresent_set', # this will be the default name, incase of need of change provide a new one
on_delete=models.CASCADE
)
...
views.py
#login_required(login_url='login_page')
def MinutesReport(request, minute_id):
report = fly_minute.objects.filter(id=minute_id).prefetch_related('memberpresent_set')
return render(request, 'minute_report.html', locals())
For further control, you can use Prefetch along with prefetch_related()
Note:
locals() returns a dict of all the locally defined variables in the current scope and this may result in exposing sensitive info. Instead of that create a custom dict and return it.
...
context = {
'report': report,
...
}
return render(request, 'minute_report.html', context)
You are referencing and querying in the opposite way. Your fly_minute model doesn't contain MembersPresent model as the Foreign Key. You are filtering the fly_minute model and trying to access MembersPresent model. So, you should change your fly_minute to in this way:
class fly_minute(models.Model):
mode = (
('Email', 'Email'),
('Zoom', 'Zoom'),
('Alternative', 'Alternative'),
)
mode_of_meeting = models.CharField(max_length=100, choices=mode, blank=False, )
date = models.DateField()
Time = models.TimeField()
minute_prepared_by = models.CharField(max_length=25)
location = models.CharField(max_length=25)
authorize_by = models.CharField(max_length=25)
item = models.TextField()
owner = models.CharField(max_length=25)
member = models.ForeignKey(MembersPresent, on_delete=models.CASCADE)#add this line and remove fly_minute in MembersPresent model
def __str__(self):
return self.mode_of_meeting
Then in template file change it to in this way:
{%for rpt in report%}
<tbody>
<tr class="table-active">
<td>{{rpt.member.name}}</td>
<td>{{rpt.member.status}}</td>
<td>{{rpt.member.email}}</td>
<td>{{rpt.member.phone}}</td>
</tbody>
{%endfor%}
I guess it works
Thanks, I ended up using fetch-related and had to make adjustments to my template.
<tr>
<th>Name</th>
<th>Status</th>
<th>Email</th>
<th>Phone</th>
</tr>
</thead>
{%for rpt in report%}
{%for rpts in rpt.memberspresent_set.all%}
<tbody>
<tr class="table-active">
<td>{{rpts.name}}</td>
<td>{{rpts.status}}</td>
<td>{{rpts.email}}</td>
<td>{{rpts.phone}}</td>
</tbody>
{%endfor%}
{%endfor%}

Template not showing context variable

I created an app called marketing app which customizes messages to be written on top of home page. My problem is that these messages are not showing when everything configured and I don't know why is that might be the template because {{ marketing_message.message }} is only not showing
This is the model:
class MarketingMessage(models.Model):
message = models.CharField(max_length=120)
active = models.BooleanField(default=False)
featured = models.BooleanField(default=False)
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
updated = models.DateTimeField(auto_now_add=False, auto_now=True)
start_date = models.DateTimeField(
auto_now_add=False, auto_now=False, null=True, blank=True)
end = models.DateTimeField(
auto_now_add=False, auto_now=False, null=True, blank=True)
def __str__(self):
return str(self.message[:12])
This is the view:
from marketing.models import MarketingMessage
class HomeView(ListView):
model = Item
paginate_by = 10
template_name = "home.html"
def get_context_data(self, **kwargs):
context = super(HomeView, self).get_context_data(**kwargs)
context['marketing_message'] = MarketingMessage.objects.all()
return context
This is the template:
{% if marketing_message %}
<div id="top-alert"class="alert alert-light" style="padding-top:85px; margin-bottom:-24px;">
×
<div class="container" style="text-align:center">
<strong> Marketing Message ! : </strong> {{ marketing_message.message}}
</div>
</div>
{% endif %}
marketing_message is a QuerySet, not a model instance.
You probably only want the most recent "active" message.
context['marketing_message'] = MarketingMessage.objects.filter(active=True).latest('timestamp')
Or the most recently updated:
context['marketing_message'] = MarketingMessage.objects.filter(active=True).latest('updated')
However latest() will fail if there is no object, which is likely not what you want, but you can do this:
try:
context['marketing_message'] = MarketingMessage.objects.filter(active=True).latest('updated')
except MarketingMessage.DoesNotExist:
context['marketing_message'] = None
Looking at your data, though, it seems incorrect. You have a start and end dates, but also active. You can imply if something is active if it falls within the start and end dates.
Also, since you have this, it seems like you could have multiple messages at once, in which case you should drop the .latest() and iterate over the ones within the start and end dates.

How to query in Django with best efficiency?

I recently found that too much SQL query optimization issue. django-debug-tool reported hundreds of similar and duplicate queries. So, I'm trying to figure out the best efficiency of Django ORM to avoid unnecessary Queryset evaluation.
As you see the below Store model, a Store model has many Foreign key and ManyToManyFields. Due to that structure, there are many code snippets doing the blow on HTML template files such as store.image_set.all or store.top_keywords.all. Everything starts with store. In each store detail page, I simply pass a cached store object with prefetch_related or select_related. Is this a bad approach? Should I cache and prefetch_related or select_related each Foreign key or ManyToManyField separately on views.py?
HTML templates
{% for img in store.image_set.all %}
{{ img }}
{% endfor %}
{% for top_keyword in store.top_keywords.all %}
{{ top_keyword }}
{% endfor %}
{% for sub_keyword in store.sub_keywords.all %}
{{ sub_keyword }}
{% endfor %}
views.py
class StoreDetailView(View):
def get(self, request, *args, **kwargs):
cache_name_store = 'store-{0}'.format(store_domainKey)
store = cache.get(cache_name_store, None)
if not store:
# query = get_object_or_404(Store, domainKey=store_domainKey)
query = Store.objects.all().prefetch_related('image_set').get(domainKey=store_domainKey)
cache.set(cache_name_store, query)
store = cache.get(cache_name_store)
context = {
'store': store,
}
return render(request, template, context)
models.py
class Store(TimeStampedModel):
categories = models.ManyToManyField(Category, blank=True)
price_range = models.ManyToManyField(Price, blank=True)
businessName = models.CharField(unique=True, max_length=40,
verbose_name='Business Name')
origin = models.ForeignKey(Origin, null=True, on_delete=models.CASCADE, blank=True)
ship_to = models.ManyToManyField(ShipTo, blank=True)
top_keywords = models.ManyToManyField(Keyword, blank=True, related_name='store_top_keywords')
sub_keywords = models.ManyToManyField(SubKeyword, blank=True, related_name='store_sub_keywords')
sponsored_stores = models.ManyToManyField(
'self', through='Sponsorship', symmetrical=False, related_name='sponsored_store_of_store')
similar_stores = models.ManyToManyField(
'self', through='Similarity', symmetrical=False, related_name='similar_store_of_store')
shortDesc = models.TextField(blank=True, verbose_name='Short Description')
longDesc = models.TextField(blank=True, verbose_name='Long Description')
returnPol = models.TextField(verbose_name='Return Policy', blank=True)
returnUrl = models.CharField(max_length=255, null=True, blank=True, verbose_name='Return Policy URL')
likes = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True, editable=False)
created_by = models.ForeignKey(settings.AUTH_USER_MODEL, editable=False, on_delete=models.CASCADE,
related_name='stores_of_created_by', null=True, blank=True)
updated_by = models.ForeignKey(settings.AUTH_USER_MODEL, editable=False, on_delete=models.CASCADE,
related_name='stores_of_updated_by', null=True, blank=True)
I really wouldn't advise custom caching/performance optimisation, unless it's a very last resort. Django has great docs on querysets and optimisation - if you follow those, it should be rare for you to experience major performance issues that require custom workarounds.
I think the issue here is that you're printing your objects in a template and hence calling their str() method. There's nothing wrong with this, but I'd check what variables you're using in your str() methods. I suspect you're referencing other models? I.e. the str() method in your image model (or whatever) is doing something like image.field.other_field. In this case, your query should look like:
queryset = Store.objects.prefetch_related('image_set__field')
Your final queryset may look like:
queryset = Store.objects.prefetch_related('image_set__field1', 'image_set__field2', 'top_keywords__field3', ...)
Note that you can still pass this into get_object_or_404 like so:
get_object_or_404(queryset, pk=<your_stores_id>)
Hope this helps.

Retrieve a user list from a manydomanyfield with information from an intermediate table

it's been a few hours since I tried to retrieve a list of users with the information of an intermediate table.
So I have a workspace model that is a manytomanyfield with users
There is also an intermediary table to differentiate the classic users and the workspace manager
I would like to display the list of users and add a small icon symbolizing the managers in the list.
But unfortunately it seems difficult for Django, to display both the list of users of the workspace with the information of the intermediate table.
In any case I look at the documentation of Django I have not managed to find how to do.
models.py
class Workspace(models.Model):
name = models.CharField(max_length=250, verbose_name="Nom du workspace")
members = models.ManyToManyField(User, through='Membership', verbose_name="Membres du workspace")
token = models.CharField(max_length=500) # token statique
join_token = models.CharField(max_length=500) # token dynamique
join_token_date = models.DateTimeField(auto_now_add=False, null=True, blank=True)
payday = models.DateField(max_length=10, verbose_name="Jour de paye", null=True, blank=True)
planning_image = ProcessedImageField(upload_to='planning',
null=True,
blank=True,
processors=[ResizeToFill(1299, 937)],
format='JPEG',
options={'quality': 100})
planning_thumbnail = ImageSpecField(source='planning_image',
processors=[ResizeToFill(280, 202)],
format='JPEG',
options={'quality': 100})
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('create-workspace')
class Membership(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
workspace = models.ForeignKey(Workspace, on_delete=models.CASCADE)
is_manager = models.BooleanField(default=False)
date_joined = models.DateTimeField(auto_now_add=True)
views.py
#login_required
def workspace_detail(request, token):
ins_workspace = get_object_or_404(Workspace, token=token)
list_members = ins_workspace.members.all()
for member in list_members:
if member == request.user:
current_user = Membership.objects.get(workspace=ins_workspace, user=request.user)
context = {
'name': ins_workspace.name,
'token': ins_workspace.token,
'list_members': list_members,
'payday': ins_workspace.payday,
'is_manager': current_user.is_manager,
}
return render(request, 'workspace/workspace_detail.html', context)
else:
return HttpResponseForbidden()
template.html
{% for item in list_members %}
{{ item.username }}
{% endfor %}
This is what I want:
template.html
{% for item in list_members %}
{% item.is_manager %}
{{ item.username }} (♔)
{% else %}
{{ item.username }}
{% endfor %}
You can do it like this:
Update Membership model with related name:
class Membership(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="membership")
workspace = models.ForeignKey(Workspace, on_delete=models.CASCADE)
is_manager = models.BooleanField(default=False)
date_joined = models.DateTimeField(auto_now_add=True)
Then you can update your view like following:
from django.db.models import F
#login_required
def workspace_detail(request, token):
ins_workspace = get_object_or_404(Workspace, token=token)
list_members = ins_workspace.members.all().annotate(is_manager=F('membership__is_manager'))
context = {
'name': ins_workspace.name,
'token': ins_workspace.token,
'list_members': list_members,
'payday': ins_workspace.payday,
'is_manager': request.user.membership.get(workspace=ins_workspace).is_manager,
}
return render(request, 'workspace/workspace_detail.html', context)
That should do the trick.
Here what I have done is that, I am using a reverse relation to get is_manager value from membership model. I am annotating that value in the queryset using F.

Combining, filtering models/views in a ManyToMany Django

I'm working on a comic book database and there are main covers and variant covers. I have a page that shows all the Main covers, but I'd like to combine the variant covers too, in order of the publication date. This is what part of my models look like:
class Image(models.Model):
CATEGORY_CHOICES = (
('Cover', 'Cover'),
('Scan', 'Scan'),
('Other', 'Other'),
)
title = models.CharField(max_length=128)
number = models.CharField(max_length=20, help_text="Do not include the '#'.")
image = models.ImageField(upload_to="images/")
category = models.CharField(max_length=10, choices=CATEGORY_CHOICES)
### The variant cover is determined by the category_choice 'Cover'. ###
contributor = models.ManyToManyField(Contributor, blank=True, null=True)
date_added = models.DateField(auto_now_add=True, auto_now=True)
def __unicode__(self):
return self.title
class Meta:
ordering = ['title']
class Issue(models.Model):
CATEGORY_CHOICES = (
('Major', 'Major'),
('Minor', 'Minor'),
('Cameo', 'Cameo'),
('Other', 'Other'),
)
title = models.ForeignKey(Title)
number = models.CharField(max_length=20, help_text="Do not include the '#'.")
pub_date = models.DateField(blank=True, null=True)
cover_image = models.ImageField(upload_to="covers/", blank=True, null=True)
### This would be where the main image goes. ^^^ ###
images = models.ManyToManyField(Image, related_name="images_inc", blank=True, null=True)
### This is where the variant covers go.^^^ ###
has_emma = models.BooleanField(help_text="Check if Emma appears on the cover.")
My views.py for the main cover page looks like this:
def covers(request):
sort_by = request.GET.get('sort', 'pub_date')
if sort_by not in ['-date_added', 'date_added', '-pub_date', 'pub_date']:
sort_by = '-date_added'
issues = Issue.objects.filter(has_emma=True).order_by(sort_by).select_related(depth=1)
return render_to_response('comics/covers.html', {'issues': issues}, context_instance=RequestContext(request))
But I would like to display the variant covers too and not just the cover_image. Is there a way to do this? Maybe with something image and then filtering the category (of the Image model by cover)?
I, of course, can do this:
def variants(request):
Issue.objects.filter(has_emma=True).order_by(sort_by).select_related(depth=1)
images = Image.objects.filter(category='Cover').order_by('id')
return render_to_response('comics/variants.html', {'images': images}, context_instance=RequestContext(request))
But that does not give me enough flexibility as def covers does, and I want them combined and sorted by pub_date, like def covers.
Edit
models.py:
class Image(models.Model):
CATEGORY_CHOICES = (
('Cover', 'Cover'),
('Scan', 'Scan'),
('Other', 'Other'),
)
title = models.CharField(max_length=128)
image = models.ImageField(upload_to="images/")
category = models.CharField(max_length=10, choices=CATEGORY_CHOICES)
date_added = models.DateField(auto_now_add=True, auto_now=True)
def __unicode__(self):
return self.title
class Meta:
ordering = ['title']
class Issue(models.Model):
title = models.ForeignKey(Title)
number = models.CharField(max_length=20)
######
has_emma = models.BooleanField(help_text="Check if cover appearance.")
cover_image = models.ImageField(upload_to="covers/", blank=True, null=True)
images = models.ManyToManyField(Image, related_name="images_inc", blank=True, null=True)
######
def get_images(self):
''' Returns a list of all cover images combined,
"main" cover image first.
'''
images = [self.cover_image]
for image in self.images.filter(category='Cover'):
images.append(image.image)
return images
views.py:
def covers(request):
sort_by = request.GET.get('sort', '-pub_date')
if sort_by not in ['-date_added', 'date_added', '-pub_date', 'pub_date']:
sort_by = '-date_added'
issues = Issue.objects.filter(has_emma=True).order_by(sort_by)
return render_to_response('template.html', {'issues': issues,}, context_instance=RequestContext(request))
template.html:
{% for issue in issues %}{% for image in issue.get_images %}{{ image.image }}{% endfor %}{% endfor %} - displays nothing, however, {% for issue in issues %} {% for image in issue.get_images %} {{ issue.cover_image }} {% endfor %} {% endfor %} will repeatedly display the cover_image of the Issue model if there are variant covers, which are categorized in the Image model.
What can I do to fix this, so that it shows everything correctly? And for the record again, I want it to display the {{ cover_image }} (from the Issue model) and the {{ image.image }} as defined by the Image model combined.
If I understand your problem correctly, one way to solve it would be adding a method to Issue class like this:
class Issue(models.Model):
# fields...
def get_images(self):
''' Returns a list of all cover images combined,
"main" cover image first.
'''
images = [self.cover_image]
for image in self.images.filter(category='Cover'):
images.append(image.image)
return images
Then, in your template, you can do, for example, {% for image in issue.get_images %}....
(If it's not exactly what you need—then, I think, it would be better if you provide some template code as an example of what you're trying to achieve.)