So I'd like to think what I'm doing is fairly common. I'm attempting to display a result set using Django. I have looked online for a while and here is what I've come up with:
models.py{
from django.db import models
from django.conf import settings
class SalesRep(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL)
class Sales(models.Model):
seller = models.ForeignKey(SalesRep)
sold_on = models.DateField("Sold On")
}
sales_view.py{
from salesteam.models import SalesRep, Sales
from django.views.generic import ListView
class SellerHome(List View):
model = SalesRep
template_name = 'production/sales.html'
#property
def rep_sales(self):
return Sales.objects.filter(SalesRep=self)
}
sales.html{
<div id="total-sales">
{% for sale in SellerHome.rep_sales%}
<li>{{ sale.id }}</li>
{% empty %}
<li>You don't currently have any sales</li>
{% endfor %}
</div>
}
For the sake of completeness I even tried writing just the property out as Sales.objects.all() but still no luck. Thanks for taking a look as I'm fairly new to HTML, Django, and Python. Any help on what I'm doing wrong would be much appreciated. Let me know if you have any questions :)
I'm not sure what tutorial you've followed, but there is a lot of errors in your code... I'm assuming you would like to display all Sales for the logged in user?
In this scenario, I would change the model slightly to add a related_name to Sales foreign key to SalesRep:
class SalesRep(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL)
class Sales(models.Model):
seller = models.ForeignKey(SalesRep, related_name='sales')
sold_on = models.DateField('Sold On')
Documentation: https://docs.djangoproject.com/en/1.7/ref/models/fields/#django.db.models.ForeignKey.related_name
And I would change the views to use DetailView:
from django.views.generic import DetailView
class SellerDetailView(DetailView):
model = SalesRep
template_name = 'production/sales.html'
context_object_name = 'seller'
def get_object(self):
return self.request.user
Docs on DetailView — https://docs.djangoproject.com/en/1.7/ref/class-based-views/generic-display/#detailview
<div id="total-sales">
<ul>
{% for sale in seller.sales.all %}
<li>{{ sale.id }}</li>
{% empty %}
<li>You don't currently have any sales</li>
{% endfor %}
</ul>
</div>
First, I'd recommend avoiding class based views, at least as you are learning Django, since they are not really necessary and needlessly complicated for what you are doing.
Anyway, to answer your question using class-based views, your problem is in your template and your view. You'll want to put your rep_sales logic in a get_queryset, set the model to be Sales, not SalesRep, and then reference object_list in the template. More info.
However, I'd instead recommend writing a normal, function-based Django view. Something like this might get you started:
def view_all_sales(request):
my_sales_rep = SalesRep.objects.get(request.user)
all_my_sales = Sales.objects.filter(seller=my_sales_rep)
return render(request, "production/sales.html", {
"sales": all_my_sales
})
Related
Given the models
class TaskGroup(models.Model):
name = models.CharField(max_length=256)
class Task(models.Model):
name = models.CharField(max_length=256)
group = models.ForeignKey(TaskGroup, on_delete=models.CASCADE)
completed = models.BooleanField(default=False)
completed_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True)
and the list view
class TaskGroupListView(ListView):
model = TaskGroup
I'd like to display the list of task groups with corresponding tasks. The catch is - I only want to show the tasks that have not been completed or have been completed by the user, or if the user as the attribute user.type == "ADMIN" set show all groups and all tasks.
Right now I have a template that looks like:
{% for taskgroup in object_list %}
<h1>{{ taskgroup.name }}</h1>
<ul>
{% for task in taskgroup.task_set.all %}
<li>{{ task.name }}</li>
{% endfor %}
</ul>
{% endfor %}
I know that I can modify the queryset of a list view by overriding get_queryset like:
def get_queryset(self):
if self.request.user == "ADMIN":
return TaskGroup.objects.all()
else:
...
but I'm not sure how to go about filtering the Task relations on the TaskGroups in the else clause.
I've thought about creating a manager subclass for Task that can filter based on .completed and .completed_by that I can use in the template but that seems against the philosophy of Django - I'd like to keep all the logic in the view (this may be way off the mark so please correct me, its been a while since I've touched django/read two scoops of django).
Is there some idiomatic way to do this? Should I discard ListView entirely and write some custom logic? any guidance here is helpful. Thanks.
You can use prefetch_related with a Prefetch that uses a custom filtered queryset like this:
from django.db.models import Prefetch, Q
def get_queryset(self):
if self.request.user.is_admin:
return TaskGroup.objects.all()
return TaskGroup.objects.prefetch_related(
Prefetch(
'task_set',
queryset=Task.objects.filter(Q(completed=False) | Q(completed_by=self.request.user))
)
)
This will get all the TaskGroups with the related Taskss (in task_set) filtered by those that are not yet completed or are completed by the current user.
I am not able to use the Django model object in Django templates. I want to iterate using the model user in the template and then play with the ActivityPeriod(model) of that user. Please check my code for the clarity:
Here is my code:
views.py
from .models import User,ActivityPeriod
def call_response(request):
user = User.objects.all()
return render(request, "Test/list.html", {"users":user ,"activityperiod":ActivityPeriod})
Test/list.html
{% for user in users %}
'real_name': {{ user.real_name}}},
'activity_periods': {% with activity=activityperiod.objects.get(id =user) %}
{{ activity.start_time }}
{% endwith %}
{% endfor %}
But i am getting an error:
Could not parse the remainder: '(id' from 'activityperiod.objects.get(id'
What is the correct way? Can anyone please share it with me.
Django template don't understand the filter action of Model. This part shoud be in view.
activity=activityperiod.objects.get(id =user)
You should prepare your data and manipulate them before sending to template (a dictionary may help you). And remember that result of action "User.objects.all()" is a list.
views.py
def call_response(request):
user = User.objects.filter(user=request.user)
activityperiod = activityperiod.objects.get(user=user)
context={'user':user,'activityperiod':activityperiod}
return render(request, "Test/list.html",context})
Test/list.html
'real_name': {{ user.real_name}}
'activity_periods':{{ activityperiod.start_time }}
Your question suggests that you think you can a function in the templates like a normal function (ie activityperiod.objects.get(...)).
You can't, the templating system is not made like this (for security reasons amongst others).
You should do something like, in your models:
def call_response(request):
# ! first() not "all()" (if > 1 user, you'll have problem)!
user = User.objects.first()
activityperiod = activityperiod.objects.get(user=user)
return render(request, "Test/list.html",
{"users":user ,"activityperiod":activityperiod})
new try of dev here.
Im trying to make a project and I alredy having some issues that i dont know why dont work... I put my code and explain it...
url.py
app_name = 'opotest'
urlpatterns = [
url(r'^$', views.indexView, name='index'),
url(r'^inicio/$', views.ListaView.as_view(), name='inicio'),
url(r'^test/(?P<tipo>.+)/$', views.TestList.as_view(), name='test'),
url(r'^test/(?P<tipo>.+)/run/$',
views.TestDetail.as_view(), name='run'), # this one
View.py
class TestDetail(generic.DetailView):
model = Pregunta
context_object_name = 'lista'
def get_queryset(self):
return Pregunta.objects.all()
HTML template
{% for test in lista %}
<br/>
<p>Pregunta: {{ pregunta.textopregunta }}</p>
{% endfor %}
Models.py
class Pregunta(models.Model):
id = models.AutoField(primary_key=True)
textopregunta = models.CharField('Texto pregunta', max_length=1000)
test = models.ForeignKey(Test, on_delete=models.CASCADE)
def __str__(self):
return self.textopregunta
This code should bring me some 'pregunta' that i have alredy created but it doesnt work... can you please tell me what im doing wrong? the for bring me Pregunta: the textopregunta do not appears...
Thanks everyone
D...
Should be
{% for test in lista %}
<br/>
<p>Pregunta: {{ test.textopregunta }}</p>
{% endfor %}
will work,
but anyway, if you want to use Pregunta.objects.all() , you must use ListView, not DetailView. Like this
class TestList(generic.ListView):
model = Pregunta
context_object_name = 'lista'
{% for test in lista %}
<br/>
<p>Pregunta: {{ test.textopregunta }}</p>
{% endfor %}
UPDATE
If you want to list all your model objects, please use ListView.
1. Change your view to ListView
class TestList(generic.ListView):
model = Pregunta
context_object_name = 'lista'
Then you can use objects and lista both in tempalte.
2. Change your url
You don't need tipo in url, if it's listview.
urlpatterns = [
url(r'^$', views.indexView, name='index'),
url(r'^inicio/$', views.ListaView.as_view(), name='inicio'),
url(r'^test/(?P<tipo>.+)/$', views.TestList.as_view(), name='test'),
url(r'^test/run/$',
views.TestList.as_view(), name='run'), # this one
3. use objects or lista in templates.
Because you define lista in context_object_name : it means your objects list will be used with lista in template. (you can use objects cause django ListView automatically make context for you)
{% for test in lista %}
<br/>
<p>Pregunta: {{ test.textopregunta }}</p>
{% endfor %}
UPDATE for DetailView
1. Change urls with pk
Above all, you have to understand about View - Template and urls.
In your urls - you should pass params what you want to use to grep your one specific object. It should be unique, so just use pk(id). (Or you can make your own unique slug)
url(r'^test/run/$',
views.TestList.as_view(), name='run'), # this one
# this is DetailView
url(r'^test/(?P<pk>\d+)/$',
views.TestDetail.as_view(), name='run'), # this one
Then your url will be.. test/1/ , test/2/.
2. change views
Actually, django CBV supports many functions (method) so you don't have to handle more but it's hard to understand.
class TestDetail(generic.DetailView):
model = Pregunta
context_object_name = 'lista'
You're confusing when you don't know about DetailView.
In DetailView, (as you can see here-ccbv.co.kr ) it has get_object() method. If any url_kwargs defined in your view, it use pk for basic. So it will find like Pregunta.objects.get(id=self.kwargs.get(pk)) that takes from your urls.py.
Then you can use your object in template, using lista or object.
<br/>
<p>Pregunta: {{ lista.textopregunta }}</p>
You DONT have to forloop all objects (actually CANT) because DetailView basically find your object from your kwargs (in this situation, pk).
I highly recommend reading django docs (CBV) and seeing ccbv.co.kr for understanding CBV, or trying to use FBV in django.
try to override the get_context_data() method, as below then change your template also,
class TestDetail(generic.DetailView):
model = Pregunta
context_object_name = 'lista'
def get_queryset(self):
return Pregunta.objects.all()
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['sample'] = self.get_queryset()
return context
Try to change your template as below,
{% for test in sample %}
<br/>
<p>Pregunta: {{ test.textopregunta }}</p>
{% endfor %}
By default Generic.DetailView looks for pk in the url parameters which is used to search data from your database. In your case you are using tipo as url parameters. So, you need to override the default inside your view. Your code should be something like this:
class TestDetail(generic.DetailView):
model = Pregunta
context_object_name = 'lista'
pk_url_kwarg = 'tipo'
def get_queryset(self):
return Pregunta.objects.all()
Now it will
look for tipo in your url and take the parameters to search from your database. More on Generic views can be found on this link: https://ccbv.co.uk/projects/Django/1.10/django.views.generic.detail/DetailView/
Following from my question Django sharing one model between two others which explored the best way to generically manage two similar models and their dependencies. I've now come to the next part - the views.
After a bit of tweaking around I've come to the following generic listview to represent the objects.
Is this coherent? Should the urls manage the models like this?
I believe if I refine their logic I can just subclass this itemlist and add additional logic in the future so it should be future-proofed.
A class that
urls.py excerpt
urlpatterns = [
url(r'^item/(?P<model>\w+)/$',views.ItemList.as_view(),name='generic'),
url(r'^item/(?P<model>\w+)/(?P<pk>\d+)$',views.ItemList.as_view(),name='generic'),
]
views.py excerpt
class ItemList(ListView):
context_object_name = 'itemlist'
template_name = 'food/item.html'
model = None
def get_queryset(self):
model = apps.get_model('food',self.kwargs.get('model'))
if self.kwargs.get('pk'):
print ('pk provided')
return model.objects.filter(pk=self.kwargs.get('pk'))
else:
print ('all')
return model.objects.all()
food/item.html excerpt (using registered filter to get class name for object)
{% block content %}
{% for item in itemlist %}
...
{% for review in item.reviews.all %}
{% endfor %}
...
<span class="glyphicon glyphicon-plus"> Add Review </span>
{% endblock %}
Also - can I carry this attitude into my forms (again assuming that when I add a review it'll generically link back to whatever object it came from?) or is that where I should start breaking them up?
I asked in past time about how generate an url with similar caracterist starting from an ID you said me that is better use slugs to do that. On this time I wanna generate dinamics urls with slugs. My objective is obtain this result:
I have five products that I named cards in models.py (Ysera, Neltharion, Nozdormu, Alexstrasza, Malygos). I need the respective url of each of the products:
localhost:8000/card/ysera
localhost:8000/card/neltharion
localhost:8000/card/nozdormu ... etc.
I try to generate these urls but i dont know if I made a good applying of commands, either I don't know how I can specify the id card like the main name of the card (ysera, neltharion...). I was trying to follow an answer posted here in this community a little blind and this is my "reconfiguration":
Here my views.py:
from django.shortcuts import render_to_response
from django.template import RequestContext
from dracoin.apps.synopticup.models import card
from dracoin.apps.home.forms import ContactForm,LoginForm
from django.core.mail import EmailMultiAlternatives
from django.contrib.auth import login,logout,authenticate
from django.http import HttpResponseRedirect
def shop(request):
tarj = card.objects.filter(status=True)
ctx = {'tarjetas':tarj}
return render_to_response('home/shop.html',ctx,context_instance=RequestContext(request))
def singleCard(request, slug, id):
try:
tarj = card.objects.get(slug=slug, id=id_tarj)
except ObjectDoesNotExist:
tarj = get_object_or_404(card, id=id_tarj)
return render_to_response('home/singleCard.html',ctx,context_instance=RequestContext(request))
My urls.py (I have an urls.py by app and the main urls.py):
url(r'^card/(?P<slug>[-\w]+)/(?P<id_tarj>\d+)/$','dracoin.apps.home.views.singleCard',name='vista_single_card'),
My models.py:
class card(models.Model):
nombre = models.CharField(max_length=100)
descripcion = models.TextField(max_length=300)
status = models.BooleanField(default=True)
def __unicode__(self):
return self.nombre
My common template for all cards:
{% extends 'base.html' %}
{% block title %} Tarjeta {{card.nombre}} {% endblock %}
{% block content %}
<h1>{{ card.nombre }}</h1><br>
<p> {{ card.descripcion }}</p>
{% endblock %}
I don't know if my slug building in views.py was find, I'm convinced that the urls.py is bad but i don't know how build it?
please excuse me if I edit my own question to prolong it, Recently I'm trying to learn django by my side and I have many gaps in my learning
apologizeme in advance my extensive question and if I overlook something.
Thanks!!
This line:
tarj = card.objects.get(slug=slug, id=id_tarj)
tries to load a card object where the id field is set to is id_tarj and the slug field is set to slug. Your model does not have a field named slug. You will need to add one.
A good candidate for it would be a SlugField - https://docs.djangoproject.com/en/dev/ref/models/fields/#slugfield
You will need to make sure that your slug field contains a proper value in each case.