I want to concatenate a string to get a product link in one of my django datatable columns.
I want a result like this:
https://www.aliexpress.com/item/1005003324927716.html
The product id is stored in my mongodb database.
This is what I tried to write in my datatable.html but i get an empty column:
{% for product in products %}
<tr>
<td>
{% with "https://www.aliexpress.com/item/"|add:{{product.productId}}|add:".html" as template %}
{% endwith %}
</td>
</tr>
{% endfor %}
Then to make it as an href link as this syntax :
<td> Click here</td>
views.py :
def datatable_view(request):
client = MongoClient("mongodb://localhost:27017/")
db = client["aliexpress"]
col = db["listproducts"]
products = col.find()
context = {'products' : products}
return render(request,'datatable.html', context)
models.py :
class Datatable(models.Model):
Title = models.CharField('Title',max_length=500),
Price = models.DecimalField('Price',decimal_places = 3, max_digits = 10000),
Currency = models.CharField('Currency',max_length=500),
Stars = models.DecimalField('Stars',decimal_places = 3 , max_digits = 10000),
Orders = models.PositiveIntegerField('Orders',max_length=500),
Shipcost = models.CharField('Shipcost',max_length=500),
Supplier = models.CharField('Supplier',max_length=500),
Productlinks = models.CharField('Productlinks',max_length=700)
I am pretty new in using django and I will be so grateful if you help me in this isuue.
Thank you !
Make it simple, add a property in your Product model
class Product(models.Model):
...
#property
def link(self):
return 'https://www.aliexpress.com/item/' + str(self.productId) + '.html'
<td> Click here</td>
UPDATE
You can make it even more simpe by doing this :
<td>Click here</td>
Related
How to display only some columns of Django model in a HTML template?
And also: how do I perform a function on one of the records? (amount)?
Right now I'm displaying a whole table of model like that:
my models.py
class Tabela(models.Model):
block_id = models.CharField(max_length=64)
timestamp = models.DateTimeField()
type = models.CharField(max_length=32)
link = models.CharField(max_length=64)
link_as_account = models.CharField(max_length=100)
account = models.CharField(max_length=100)
amount = models.CharField(max_length=64)
def __str__(self):
return self.block_id
My views.py
def search_results(request):
model = Tabela
query_addresse = request.GET.get('addressee', None)
query_hash = request.GET.get('hash', None)
if not query_hash and not query_addresse and request.method == 'GET':
return render(request, 'nanosite/index.html', {})
if query_hash and request.method == 'GET':
if query_addresse:
result = Tabela.objects.filter(account=query_addresse, block_id=query_hash)
else:
result = Tabela.objects.filter(block_id=query_hash)
field_names = [f.name for f in model._meta.get_fields()]
data = [[getattr(ins, name) for name in field_names]
for ins in result]
elif query_addresse and request.method == 'GET':
result = Tabela.objects.filter(account=query_addresse)
field_names = [f.name for f in model._meta.get_fields()]
data = [[getattr(ins, name) for name in field_names]
for ins in result]
return render(request, 'nanosite/index.html', {'field_names': field_names, 'data': data})
My index.html
<div id="bottomhalf" class="table-responsive">
<table class="table table-sm table-dark table-hover">
<thead class="thead-light">
{% for head in field_names %}
<th scope="col">{{ head }}</th>
{% endfor %}
</thead>
<tbody>
{% for row in data %}
<tr scope="row">
{% for cell in row %}
<td>{{ cell }}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
What I'd like to do is display only block_id, timestamp, account and amount in html. I've tried different approaches like using only the result part of views without field_names and data, but of course it didn't work.
My other question is, how can I modify the field amount and perform an operation on it to be displayed in template like amound divided by certain digit with a $ sign before it (for example if amount=1488 to be divided by 124 and displayed as '$12')?
Pass the queryset qs selecting the objects to display to the template and iterate over it to generate your table:
{% for obj in qs %}
<tr>
<td> {{obj.block_id}} </td>
<!-- etc ... -->
</tr>
{% endfor %}
Now, if you also want to pass a variable specifying the names of the fields of the object to tabulate, and in what order, you find out that the Django template engine is by design (!) incapable of doing that. You can either do what you are doing, and generate a list-of-rows in Python which you pass to the Template, or you need a Django custom template tag such as
#register.filter
def attr( obj, name):
return getattr( obj, name, '')
and then you can run an inner loop in your template
<tr>
{% for name in selected_field_names %}
<td> {{obj|attr:name}} </td>
{% endfor %}
</tr>
The answer to the second question, is to define a property on your model to return the field suitably transmogrified:
class Tabela(models.Model):
...
#property
def funny_amount(self):
val = self.amount/12.0
return f'$ {val:.2f}'
and refer to {{obj.funny_amount}} in your template
I've got a History ListView in which I'd like to let my Users filter the Historyitems based on which User they picked in the ModelChoiceFields I'm providing them
My History View looks like this:
class HistoryItems(ListView):
model = HistoryItem
template_name = 'history/history_table.html'
context_object_name = 'history_items'
def get_context_data(self, **kwargs):
user_id = kwargs.get('user_id')
query = {}
if user_id:
user = get_object_or_404(User, pk=user_id)
query['changed_by'] = user
else:
user = None
history_items = HistoryItem.objects.filter(**query).select_related('changed_by',
'content_type')
return {
'filter_history_form': HistoryFilterForm(user_id=user_id),
'history_items': history_items,
}
It returns me the correct History items in a big table (see html below). And then I've got this form:
class HistoryFilterForm(forms.Form):
normal_user = forms.ModelChoiceField(User.objects.filter(special=None), label="Normal Users", empty_label="All normal users")
special_user = forms.ModelChoiceField(User.objects.exclude(special=None), label="Special User", empty_label="All special users")
def __init__(self, *args, **kwargs):
user_id = kwargs.pop('user_id')
super(HistoryFilterForm, self).__init__(*args, **kwargs)
self.fields['normal_user'].initial = user_id
self.fields['special_user'].initial = user_id
self.helper = FormHelper()
self.helper.label_class = 'sr-only'
self.helper.add_layout(Layout(
Row(
Div('normal_user', css_class='col-sm-3'),
Div('special_user', css_class='col-sm-3'),
)
))
This form simply creates two ModelChoiceFields of the same User object, just that one field shows all "normal" users and the other all "special users"
My Urls looks lime this:
urls = [
path('', views.HistoryItems.as_view(), name='history_index'),
path('u=<int:pk>', views.HistoryItems.as_view(), name='history_index'),
]
I figured that I would need to refresh my page all the time when I'm searching for the history items of another user, which I'm doing with JavaScript (see HTML below). I'm also setting the id of the user in the url as an extra parameter.
And finally my HTML:
{% block extra_js %}
{{ block.super }}
<script type="application/javascript">
$(function(){
var historyUrlBase = '/history/';
var getParams = function(){
return {
'normalUserId': $('#id_normal_user').val(),
'specialUserId': $('#id_special_user').val()
}
};
var getNormalUrl = function(){
var params = getParams();
return historyUrlBase + 'u=' + params.normalUserId;
};
$('#id_normal_user').change(function(){
window.location.href = getNormalUrl();
});
var getSpecialUrl = function(){
var params = getParams();
return historyUrlBase + 'u=' + params.specialUserId;
};
$('#id_special_user').change(function(){
window.location.href = getSpecialUrl();
});
});
</script>
{% endblock %}
{% block main %}
{% crispy filter_history_form %}
<table class="table table-bordered table-responsive-sm">
<thead class="thead-light">
<tr>
<th>Changed at</th>
<th>Object</th>
<th>Action</th>
<th>Changed by</th>
<th>Difference</th>
</tr>
</thead>
<tbody>
{% for history_item in history_items %}
<tr>
<td>
{{ history_item.changed_at|date:"d.m.Y h:i:s" }}
</td>
<td>
{{ history_item.object }}
</td>
<td>
{% if history_item.action == 'custom' %}
{{ history_item.description }}
{% else %}
{{ history_item.get_action_display }}
{% endif %}
</td>
<td>
{{ history_item.changed_by }}
</td>
<td>
{{ history_item.difference|default:'' }}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
My main problem right now is that in my View the kwargs I am receiving are always an empty dict with which ofc nothing works.
But I don't know how I can receive the ID from the users I'm picking, my form always shows the correct users in the two ModelChoiceFields, but how can I get the ID's from those users to use them in my view?
The users themselves only distinguish by the special field they have, but they share the same model.
I'm using Django 2.2 and Python 3.7 btw, so maybe if there is an even easier way someone knows, that would also be welcome!
I hope someone knows a good solution or can tell me what I'm doing wrong. Thanks in regard! :)
Short Answer
The kwargs dictionary in get_context_data contains any key word arguments defined in your urls.
urls = [
path('', views.HistoryItems.as_view(), name='history_index'),
path('u=<int:pk>', views.HistoryItems.as_view(), name='history_index'),
]
Your first url has no key word arguments defined. Your second url has one key word argument, pk (i.e. not user_id). So your code should actually be
user_id = kwargs.get('pk')
Long Answer
The way you've set up your form isn't typically how you would handle filtering of data. What you want to do is to submit your form using a GET request.
https://docs.djangoproject.com/en/dev/topics/forms/#get-and-post
Which will produce a url with query string parameters that looks something like
/history/?normal_user=1&special_user=1
You can then access these query string parameters in your view via the GET dictionary from the request object.
def get_context_data(self, **kwargs):
normal_user = self.request.GET.get('normal_user')
special_user = self.request.GET.get('special_user')
# filter your history with normal_user/special_user
And finally, delete your second url as this is no longer necessary.
I tried getting the list of objects from the current logged users. There something missing in the codes.
I wrote a class-based view as well as function-based views.
Class-based views give an error like 1 positional argument but two were given.
And in function-based view it giving only first item instead looping through it.
I want to show the pass investments inventory record of each investor.
Thank you!
views.py (Function-Based Views)
def InvestmentListView(request):
investors = Investment.objects.all(id=request.user.id)
args = {'investors':investors}
return render(request, 'investors/myinvest.html', args)
This only retrieving an only first item.
views.py (class-Based viewa)
class InvestmentListView(ListView):
model = Investment
template_name = 'investors/myinvest.html'
context_object_name = 'total_invested_by_user'
def get_queryset(self):
return Investment.objects.filter(investor=self.request.user.id)
This CBV gives an error like 1 positional argument, but 2 were given.
myinvest.html
<div class="container">
{% if user.is_authenticated %}
<h2>Investor Name: {{ request.user }}</h2>
<table>
<tr>
<th>Amount Invested</th>
<th>Date</th>
<th>Rate Of Interest</th>
<th>Return</th>
<th>Profit</th>
</tr>
<tr>
{% for invest in investors %}
<th>{{ invest.amount }}</th>
<th>{{ invest.timestamp }}</th>
<th>{{ invest.rate }}</th>
<th>None</th>
<th>None</th>
{% endfor %}
</tr>
</table>
{% endif %}
Here, models.py
class Investor(models.Model):
name = models.CharField(max_length=99)
user = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.name
class Investment(models.Model):
amount = models.FloatField(blank=False)
rate = models.FloatField(blank=False)
timestamp = models.DateField(default=datetime.now)
investor = models.ForeignKey(Investor, on_delete=models.CASCADE)
def __str__(self):
return str(self.investor)
You are filtering the Investment id with your user id which is not correct. This should work:
investors = Investment.objects.filter(investor__user=request.user)
I really need help...i ve been asking a lot of times for help and looked on google and i haven't found anything....
I want when the I click on the Table name i want to get the ID and number and obtain the details about the that table.
table_base.html
{% extends 'base.html' %}
{% block content %}
<br>
<div class="container">
<div class="jumbotron">
<h1> {{ table_name }} List</h1>
{% if list_tables %}
<table>
<thead>
<th>Id</th>
<th>Name</th>
<th>Date</th>
</thead>
{% for list in list_tables %}
<tr>
<td><pre>{{ list.id }}</pre></td>
<td><pre><a class="btn-link" href="{% url 'tables:details' list.id %}">{{ list.name }}</a></pre></td>
<td> <pre>{{ list.date }}</pre></td>
</tr>
{% endfor %}
</table>
{% else %}
<p> No Records Found</p>
{% endif %}
</div>
</div>
{% endblock %}
views.py
def table_base(request):
table_name = Crawledtables._meta.db_table
list_tables = Crawledtables.objects.order_by('id')
return render(request, 'tables/table_base.html', {'table_name': table_name,
'list_tables': list_tables})
class AboutDetail(DetailView):
model = Crawledtables
pk_url_kwarg = 'table_id'
template_name = 'tables/table_list.html'
def __init__(self, **kwargs):
super(AboutDetail, self).__init__(**kwargs)
def get_object(self):
if 'table_id' not in self.kwargs:
return Crawledtables.objects.get(id=1)
else:
return Crawledtables.objects.get(id=self.kwargs['table_id'])
class Details(ListView):
model = AllTables
template_name = 'tables/table_list.html'
context_object_name = 'details'
paginate_by = 15
queryset = AllTables.objects.all()
tables/urls.py
urlpatterns = [
url(r'^$', views.table_base, name='tables'),
url(r'^(?P<table_id>\d+)$', views.AboutDetail.as_view(), name='id-details'),
url(r'^(?P<table_id>\d+)/details$', views.Details.as_view(), name='details'),]
Basically i want to get the value of the table_id and make a new function in views where i get the table info based on what table_id i have...
If i have table_id 2 i want to the data of table_name2...
if i have table_id 3 i want to the data of table_name3...and so on.
I want this data to list it on a new template that i will create.
Something like this for the views.py:
I will get the table_id = 2 and then i use table_id to get the table name that has that id. When i get the table name..i will put it in the models.py in db_table to get that specific table details.
def details(request, table_id):
tbl_name = Crawledtables.objects.get(id=table_id)
AllTables._meta.db_table = tbl_name
query = AllTables.objects.order_by('id')
tbl_query = {'t_details': query}
return render(request, 'tables/table_list.html', context=tbl_query)
Thank you in advance
UPDATE:
I almost figure it out...but i still missing 1 more thing.
views.py
class Details(ListView):
AllTables._meta.db_table = 'table_name_1'
# AllTables._meta.db_table = 'table_name_2'
# AllTables._meta.db_table = 'table_name_3'
model = AllTables
template_name = 'tables/table_list.html'
context_object_name = 'details'
paginate_by = 15
queryset = AllTables.objects.all()
I need to switch between those 3 tables based on the table_id that i get from
views.AboutDetail or the table_base.html when the user clicks on the table_name
Something like this:
class Details(ListView):
if AboutDetail.pk_url_kwarg == 1:
AllTables._meta.db_table = 'table_name_1'
if AboutDetail.pk_url_kwarg == 2:
AllTables._meta.db_table = 'table_name_2'
if AboutDetail.pk_url_kwarg == 3:
AllTables._meta.db_table = 'table_name_3'
else:
pass
class Product(models.Model):
name = models.CharField(max_length=50)
desc = models.CharField(max_length=50)
def __unicode__(self):
return self.name
class ProductModels(models.Model):
product = models.ForeignKey(Product)
name = models.CharField(max_length=50)
price = IntegerField(max_length=50)
def __unicode__(self):
return self.name
class Sold(model.Model)
product = models.ForeignKey(Product)
model_name = models.ForeignKey(ProductModels)
sold_date = models.DateField()
model_qty = models.IntegerField()
def __unicode__(self):
return self.sold_date
this is with reference to my previous question( that problem is solved)
what i am trying to find out is how many models have been sold from Jan to Dec for the particular product.
so far i have done this, i know it's little crude. but it would help he if it written correctly:
views.py
allmonths = ['jan' , ....., 'dec']
products = Products.objects.all()
for each_product in products :
models = ProductModels.objects.filter(product = each_product)
for each_model in models:
for months in allmonths :
att_name = str(each_model.model_name) + str(months)
print 'attname %s' % att_name
val = sold.objects.filter(product = each_product ,
model_name = each_model ,(sold_date =(allmonths.indesx(month) + 1))) .aggregate(qty=Sum('model_qty'))
val = temp(val['qty'])
setattr(each_product, att_name , val)
I am not sure if this correct or not , but this approach has worked earlier. i used getattribute template tag from here.
This is how my template looks like :
{% for record in products %}
<tr class="odd gradeX">
<td><span class="label label-warning">{{ record.name }}</span></td>
<td>
<table class="table table-striped table-bordered table-hover" id="pipelineTbl">
{% for model in record.ProductModels_set.all %}
<tr class="odd gradeX">
<td>
<span class="label label-success">{{ model }}</span>
</td>
</tr>
{% endfor %}
</table>
</td>
{% for months in allmonths %}
<td>
<table class="table table-striped table-bordered table-hover" id="pipelineTbl3">
{% for model in record.ProductModels_set.all %}
{% with model|add:months as val %}
<tr>
<td>{{ record|getattribute:val }}</td>
</tr>
{% endwith %}
{% endfor %}
</table>
</td>
{% endfor %}
</tr>
{% endfor %}
You can make the following query:
product = some_product()
year = 2013
product_sells = Sold.objects.filter(product=product, sold_date__year=year)
If you want to know how many individual sells do this:
product_sells.count()
If you want to sum the product sold quantities:
from django.db.models import Sum
product_sells.Sum('model_qty')
In general avoid iterating over Products.objects.all(), as it's really expensive on database and memory.