I have two models
class Document(models.Model):
name = models.CharField(max_length=250, blank=True)
class Approval(models.Model):
document = models.ForeignKey(Document)
user = models.ForeignKey(User, related_name='approval user')
status = models.IntegerField(choices=APPROVELS, default=1, help_text="Approved")
i want to list all document with current login user approval status, when a user approve/Abstain/Not Approved a document i am recording in Approval table otherwise there is no record about current user approval status in Approval table
Please help me with the view and template.
On view:
userApprovals = Approval.objects.filter( user = request.user )
or
userApprovals = request.user.approval_user_set.all()
forYourApproval = Document.objects.exclude( pk__in = [ a.document.pk for a in userApprovals ] )
and don't forget to include userApprovals on render_to_response:
return render_to_response(
"yourPage.html",
{
"userApprovals": userApprovals,
"forYourApproval": forYourApproval,
},
context_instance=RequestContext(request))
On template:
{% for approval in userApprovals %}
{{ approval.document.name }} status {{ approval.get_status_display }}
{% endfor %}
{% for document in forYourApproval %}
{{ document.name }} waiting for your approval.
{% endfor %}
Note: change related name to 'approval_user'.
It's not clear whether your requirements allow any user to approve a document, but I'm inferring that this is the case based on your models. If a Document can only be approved by a specific user, or set of users, or if a document is approved by multiple users, you will need to make some substantial changes to your model design.
If not, I would write a view like this:
from django.db.models import Q
def approval_view(request):
documents = Document.objects.filter(
Q(approval__id__isnull=True) | Q(approval__user=request.user))
return render_to_response(template_name, {'documents': documents})
This will return a context with documents that have no Approval record in the approval table OR who have been approved by request.user.
You will likely need some additional code to display the appropriate information for each document in documents. For example, a custom template filter that displays a document status ("For your Approval" or "Approved" or whatever) might be necessary. An example template fragment:
{% for document in documents %}
<li>{{ document.name }} - {{ document|approval_status }}</li>
{% endfor %}
As I said at the beginning, your requirements are not clear. Is every user to be given an opportunity to approve a document? Or do all documents get a single opportunity to be approved by any user? There is a big difference and this code reflects the latter assumption.
If every user is to be given an opportunity to approve a document and you need to display the current user's approval decision, then the above code will work with slight modification. I would probably modify the view to display all documents in some order:
documents = Document.objects.all()
And then use a custom template filter as above to display the approval status for the current user (passing in the user as an argument):
<li>{{ document.name }} - {{ document|approval_status:request.user }}</li>
Related
I have a website that has some services that has to be subscribed individually. The user has to subscribe the services he wants to avail. Now there are three plans for subscription monthly, quaterly and half-yearly. The user has to choose one of them individually for each service he is opting for.
For example, I have three services civil, tax, criminal. Now a user can choose to subscribe Civil for 1 month and Criminal for 6 month hence these will expire too individually. Based on the services he has choosen he will get menus once he logs in. Below is the approach I took to make the models.
models.py
SUB_CHOICES = (
('monthly', 'monthly'),
('quaterly', 'quaterly'),
('hf', 'half_yearly'),
('anually', 'anually'),
)
class ServiceProduct(models.Model):
title = models.CharField(max_length=50, null = True)
code = models.IntegerField(null=True, unique= True)
price = models.DecimalField(max_digits=10,decimal_places=2,null=True)
def __str__(self):
return self.title
class UserSubscription(models.Model):
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
service_choosen = models.ForeignKey(ServiceProduct, on_delete=models.CASCADE, null=True)
is_active = models.BooleanField(default= False)
subscribed_on = models.DateTimeField(null=True)
expiring_on = models.DateTimeField(null=True)
Here i connected the usermembership model to customuser with foreign key to make multiple subscription for the same user having is_active class that shall toggle based on the subscription dates and expiring dates. The ServiceProduct models stores the name, prices etc of the service that would be required during checkout
But now as I said the user will get menus after login based on what services is active in subscription I am unable to do this in the template.
I passed the value from my views as
views.py
subuser = request.user
sub = UserSubscription.objects.filter(user = subuser)
return render(request, 'testpage.html', {'subuser': subuser, 'sub': sub})
But in html i cannot write somthing like
{% for cust in sub %}
{% if cust.service_choosen.civil.is_active %}
do something...
{% endif %}
{% endfor %}
I am sure that I am unable to make the correct models .Therefore please suggest me what will be the right approach to create models that would make this type of subscription method possible.
Desired result:
If the user chooses civil for a month and criminal for 6 months then Civil should be active for him for a month and Criminal should be active for him for 6 months
I believe that is_active would be better as model method. Like this:
def is_active(self):
return timezone.now() <= self.expiring_on
because it will "update" itself automatically if the subsrciption time will pass.
Share more views.py and I will tell you, how to pass context to html.
in views.py I would first filter UserSubscription to select only active subscriptions
subuser = request.user
sub = UserSubscription.objects.filter(user = subuser, is_active = True)
return render(request, 'testpage.html', {'subuser': subuser, 'sub': sub})
In this way you can simplify your template:
{% for cust in sub %}
{% if cust.service_choosen.title == 'civil' %}
do something with Civil...
{% elif cust.service_choosen.title == 'tax' %}
do something with Tax...
{% elif cust.service_choosen.title == 'criminal' %}
do something with Criminal...
{% endif %}
{% endfor %}
or using code instead of title (suppose codes 1=Civil, 2=Tax and so on):
{% for cust in sub %}
{% if cust.service_choosen.code == 1 %}
do something with Civil...
{% elif cust.service_choosen.code == 2 %}
do something with Tax...
{% elif cust.service_choosen.code == 3 %}
do something with Criminal...
{% endif %}
{% endfor %}
Depending on the output you need, you could also try to generalize (example)
{% for cust in sub %}
<a href='#'>Service {{ cust.service_choosen.title }}</a>
{% endfor %}
Also consider that calculating is_active on the fly like suggested by NixonSparrow answer is a best practice
I'm building a tool, that gets user timeline tweets and their responses and I need to find out how to store those conversations in a database to render them afterwards in a template.
To get a conversation, I use a while loop, that gets 'in_reply_to_status_id' of a tweet, then retrieves the status object of this reply by the id, finds its 'in_reply_to_status_id' etc till the whole conversation gets retrieved.
This is the code I use:
conversation = []
while True:
response = api.get_status(id=tweet_id, tweet_mode='extended')._json
if response['in_reply_to_status_id'] == None:
break
else:
message_dict = {}
message_dict['author'] = response['user']['screen_name']
message_dict['text'] = response['full_text']
message_dict['created_at'] = response['created_at']
message_dict['author_profile_url'] = response['user']['profile_image_url']
conversation.append(message_dict)
tweet_id = response['in_reply_to_status_id']
if len(conversation) == 0:
return None
return reversed(conversation)
In my models.py I have a Tweet model and I need to find out how to make a model that stores the whole conversation/dialogue/thread retrieved by the script above. Also, it should be possible to render the conversation as a simple chat dialogue afterward.
My first thought was to add "replies" field to my Tweet model and store the conversation as a JSON but this doesn't look like the right solution to me.
I don't know all the fields that you get or want to store, but for what I saw at your code this should work (set the max_length at what it should do, I don't know):
Tweet(models.Model):
author = models.Charfield(max_length=50)
text = models.Charfield(max_length=500)
author_profile_url = models.URLField(null=True, blank=True)
reply_to = models.ForeignKey(Tweet, on_delete=models.CASCADE, related_name='replies')
creation_date = models.DateTimeField()
To print all the conversation you will need to iterate the FK looking for all the related objects and order them by creation_date.
If what you want is to show only one conversation you should send through the view the initial object of the conversation and then you could do something like:
{{ tweet.author }}
{{ tweet.text }}
{{ tweet.creation_date }}
{% if tweet.reply_to_set.count > 0 %}
{% with replies=tweet.reply_to_set.all %}
{% for reply in replies %}
{{ reply.author }}
{{ reply.text }}
{{ reply.creation_date }}
replies to this message: {{ reply.reply_to_set.count }}
{% endfor %}
{% endwith %}
{% endif %}
This will show first the tweet information, then check if there are replies and if there are show you the information of each one. Inside that reply I added the replies to this message in which you can let the people know if that reply have other replies. Just in case you want to do infinite reply system (like twitter). But then there you could add a link to this same template in which the object is that reply, so that will be the main tweet and then the replies will be shown.
So I am working on a small Django project, which for the moment doesn't require optimization. But to prepare for the future, I'd like to know a bit more about the three approaches.
For instances, as part of the models, I have User and UserProfile, Transaction.
class User(models.Model):
name = ...
email = ...
class UserProfile(models.Model):
user = models.ForeignKey(User, related_name='profile')
photo = models.URLField(...)
...
class Transaction(models.Model):
giver = models.ForeignKey(User, related_name="transactions_as_giver")
receiver = models.ForeignKey(User, related_name='transactions_as_receiver')
...
I frequently need to do something like "return transactions that the request.user is giver or receiver", or "return the profile photo of a user". I have several choices, for instance to get a list of pending transactions and photos of both parties, I can do it at views.py level:
1.
#views.py
transactions = Transaction.objects.filter(Q(giver=request.user)|Q(receiver=request.user))
for transaction in transactions:
giver_photo = transactions.giver.profile.all()[0].photo
# or first query UserProfile by
# giver_profile = UserProfile.objects.get(user=transaction.giver),
# then giver_photo = giver_profile.photo
#
# Then same thing for receiver_photo
transaction['giver_photo'] = giver_photo
...
Or I can do it more on template level:
# some template
<!-- First receive transactions from views.py without photo data -->
{% for t in transactions %}
{{t.giver.profile.all.0.photo}}, ...
{% endfor %}
Or I can move some or even all of the above stuffs into filters.py
# some template
{{ for t in request.user|pending_transactions }}
{{ t.giver|photo }} {{ t.receiver|photo }}
{{ endfor }}
where photo and pending_transactions are roughly the same code in original views.py but moved to a filter.
So I wonder is there a best practice/guide line on how to choose which approach?
From Django documentation, lower level is faster, and therefore 2. 3. should be slower than 1; but how about comparing the 2. and 3.?
In getting a user photo, which of the two should be recommended, transactions.giver.profile.all()[0].photo OR profile = UserProfile.objects.get(...) --> photo = profile.photo?
Move this logic into models and managers. Views and templates must be as short as possible.
class User(models.Model):
...
def transactions(self):
return Transaction.objects.filter(Q(giver=self)|Q(receiver=self))
def photo(self):
return self.profile.all().first().photo
So the template will be:
{% for t in request.user.transactions %}
{{ t.giver.photo }} {{ t.receiver.photo }}
{% endfor %}
My experience says that business logic in model as much easier to test, support and reuse than in the views/templates.
I'm using Django 1.4 with Python 2.7 on Ubuntu 12.04.
I have a template that I want to fill with information regarding developers working on a project.
Each developer will have the following information to display:
type
title
first_name
last_name
skills
The trouble I'm running into is that each developer has many skills associated with them.
I've created the model like this:
class DevSkills(models.Model):
dev = models.ForeignKey(User)
skill = models.CharField(max_length = 200)
I'm trying to create a view that will populate the dictionary so that I can loop through each developer, display their info, then loop through each skill (to display them one at a time).
Here is the view:
def developers(request):
"""
.. function:: developers()
Provide the page that shows the developer credentials
:param request: Django Request object
"""
devs = User.objects.filter(is_staff = True)
dev_info = {}
for dev in devs:
dev_info.update(createDevDisplayDict(dev))
data = { 'user' : request.user }
data.update({ 'devs' : dev_info })
return render_to_response("developers.html", data)
I've designated the is_staff field from User to indicate the user is a developer.
I've created a simple utility that helps me populate the embedded dictionaries so I can loop through them:
def createDevDisplayDict(user):
"""
.. function:: createDevDisplayDict()
Create a dictionary for showcasing the developer
:param user: developer who we are working with
"""
userProfile = UserProfile.objects.get(user = user)
devSkills = DevSkills.objects.filter(dev = user)
dev_dict = {}
user_dict = { 'dev_type' : userProfile.dev_type,
'title' : userProfile.title,
'first_name' : user.first_name,
'last_name' : user.last_name,
}
dev_dict.update(user_dict)
skill_dict = {}
for skill in devSkills:
skill_dict.upate({ 'skill' : skill.skill })
dev_dict.update(skill_dict)
return dev_dict
My intention is to loop through each developer, create a "super" dictionary to contain each of their user_dict dictionaries (which are based on their User info) and add to that a dictionary for each of their skills. Then, back in the template I want to loop through the "super" dictionary in such a way that it will present them something like the following:
James Taylor
Project Lead
Software Developer
• Django
• Python
• JavaScript
• JQuery
Elizabeth Norton
Design Lead
Graphic Designer
• Edge
• Adobe Photoshop
• Adobe Illustrator
• CSS
Here is the template I'm trying to work with:
{% extends "base.html" %}
{% block content %}
<div>
<p>Our Developers</p>
</div>
{% for dev in devs %}
{{ dev.user_dict.first_name }} {{ dev.user_dict.last_name }}
{{ dev.user_dict.title }}
{{ dev.user_dict.dev_type }}
<ul>
{% for skill in dev.skill_dict %}
<li>skill.skill</li>
{% endfor %}
</ul>
{% endfor %}
{% endblock %}
When I see the page now it looks like this:
Our Developers
Yeah...nothing is getting populated. Any suggestions?
UPDATE 1:
I've modified my utility per iMom0's suggestion. I'm now using a list to contain each skill. Like so:
def createDevDisplayDict(user):
"""
.. function:: createDevDisplayDict()
Create a dictionary for showcasing the developer
:param user: developer who we are working with
"""
userProfile = UserProfile.objects.get(user = user)
devSkills = DevSkills.objects.filter(dev = user)
dev_dict = {}
user_dict = { 'dev_type' : userProfile.dev_type,
'title' : userProfile.title,
'first_name' : user.first_name,
'last_name' : user.last_name,
}
dev_dict.update(user_dict)
skills = []
for skill in devSkills:
skills.append(skill.skill)
skill_dict = {'skill' : skills}
dev_dict.update(skill_dict)
return dev_dict
I can see the value in doing this - in fact, it's much more intuitive and I think I was making it too hard the other way. But my template still shows up bare. :(
UPDATE 2:
I know I'm on the write path now. I put some logging in the view:
devs = User.objects.filter(is_staff = True, is_superuser = False)
dev_info = {}
for dev in devs:
dev_info.update(createDevDisplayDict(dev))
for key in dev_info:
for sub_key in dev_info[key]:
logfile.write('{0} = {1}\n'.format(sub_key, dev_info[key][sub_key]))
And the logfile displays:
skills = [u'Java', u'Perl', u'C++', u'Python', u'Django']
dev_type = Software Developer
first_name = Rico
last_name = Cordova
title = Owner
So, it has to be a way I'm calling it in the template, right?
UPDATE 3:
I had a realization that I was disconnecting the user_dict and their skills. So I modified the utility slightly to bring them into a single dictionary.
## Create a logging object
userProfile = UserProfile.objects.get(user = user)
devSkills = DevSkills.objects.filter(dev = user)
dev_dict = {}
user_dict = { 'dev_type' : userProfile.dev_type,
'title' : userProfile.title,
'first_name' : user.first_name,
'last_name' : user.last_name,
}
skills = []
for skill in devSkills:
skills.append(skill.skill)
user_dict.update({ 'skills' : skills })
dev_dict['user_dict'] = user_dict
return dev_dict
This is a much better solution, in my opinion. I'm still having trouble accessing the user_dict info in the template though. :(
You could be using Django's ORM features to make this a lot easier (and, we'll see, get better performance), it's a great feature!
Model code
class DevSkill(models.Model):
dev = models.ForeignKey(UserProfile, related_name = 'skill_set')
skill = models.CharField(max_length = 200)
We changed two things:
Using a UserProfile ForeignKey instead of user will simplify the rest of the code. Since you have a UserProfile <-> User mapping anyway, this is not going to be an issue.
We added a related_name attribute so that any UserProfile object now has a skill_set attribute which store it's list of DevSkills.
(Please note that related_name is not required, and Django will create a generic modelname_set attribute if you don't set it).
Also, DevSkill should be singular, the object is a single skill!
I also expect that you have the following for UserProfile, and created code assuming you did. You'll need to adapt if you don't.
class UserProfile(models.Model):
user = models.OneToOneField(User)
title = models.CharField(max_length = 40)
dev_type = # W/E you want
In the view:
devs = UserProfile.objects.all() # Or W/E queryset would fit.
# Pass context & all.
In the template:
{% extends "base.html" %}
{% block content %}
<div>
<p>Our Developers</p>
</div>
{% for dev in devs %}
{{ dev.user.first_name }} {{ dev.user.last_name }}
{{ dev.title }}
{{ dev.dev_type }}
<ul>
{% for skill in dev.skill_set.all %}
<li>skill.skill</li>
{% endfor %}
</ul>
{% endfor %}
{% endblock %}
Performance
Please be aware that this code (the one you're using now too, though) is going to absolutely kill performance. Indeed, we're doing several queries for each user (Hitting the database for their User and their DevSkills).
That's not a problem though, we can use the ORM's select_related and prefetch_related features to solve that issue:
devs = UserProfile.objects.select_related('user').prefetch_related('skill_set').all()
That way, we only do two queries, one for the UserProfile -> Userand one for the DevSkill's, for which the joining is done in Python, but you shouldn't care about that, Django does it for you.
Please be aware that prefetch_related is a Django 1.4 feature.
Footnote: the UserProfile stuff is going away in Django 1.5, check it out!
dict.update always overwrite the value of dict
In [2]: d = {'key': 'value'}
In [3]: d.update({'key': 'value1'})
In [4]: d
Out[4]: {'key': 'value1'}
Instead, you should use list and list.append.
And your template do not know what user_dict is, correct it,
dev_dict['user_dict'] = user_dict
This is a new concept for me - dict.items in a template. The following is exactly how I was able to display what I wanted.
{% extends "base.html" %}
{% block content %}
<div>
<p>Our Developers</p>
</div>
{% for key, value in devs.items %}
{{ value.first_name }} {{ value.last_name }} <br>
{{ value.title }} <br>
{{ value.dev_type }} <br>
<ul>
{% for skill in value.skills %}
<li>{{ skill }}</li>
{% endfor %}
</ul>
{% endfor %}
{% endblock %}
Here are my models:
class Activity(models.Model):
title = models.CharField(blank=False, max_length=100)
description = models.TextField(blank=False)
class UserActivityWork(models.Model):
activity = models.ForeignKey(Activity)
user = models.ForeignKey(User)
hours_worked = models.FloatField()
comment = models.TextField()
Example data would be, an Activity of "climbing Mt Everest" and each user would be able to input how long it took them and a comment.
Here's my question: How can I display a list of all the Activities, and if the user has entered data for that Activity, display the pertinent details next to the Activity?
So far, I have considered:
creating a dictionary of
UserActivityWork with a key of the Activity id and a value of the user's UserActivityWork. This would be fine with
me, but I have no idea of how to do
this in django's templating system (ie, how do you say: {{ user_work[activity.id] }})
creating an object that would hold
both the Activity and
UserActivityWork. I haven't done this
one, because I am hoping that django
has a better way to do this.
Any insight would be greatly appreciated!
Assuming you have 2 querysets accessable from within your template (say as activities and user_activities)
A naive way would be to iterate over each activity and then over each user activity.
{% for activity in activities %}
{{ activity.title }}
{% for user_activity in user_activities %}
{% ifequal user_activity.activity activity %}
Display userdata
{% endifequal %}
{% endfor %}
{% endfor %}
Dictionary lookups can be performed in templates by using a dot (.)
Technically, when the template system encounters a dot, it tries the following lookups, in this order:
Dictionary lookup
Attribute lookup
Method call
List-index lookup
Another option would be to create a custom template tag. You could loop over the activity list as before and then pass the activity and either the user_activity list or the user to the tag to perform the lookup and render the required data.
Thanks for the hint, Gerry. I found that writing a custom template tag as you suggested was the way to go.
Here are the gory details, in case anyone stumbles across this.
In the view method, I published a dictionary "user_activity_status" which contains a key of activity.id and value of UserActivityWork object for the logged in user's work on that activity
This is the the relevant section of the template. Basically this going to add a variable "map_value" with a value of
getattr(user_activity_status[activity.id], "comment")
Here's the template:
{% load *file-name-of-the-templatetag-file* %}
{% access_map_method user_activity_status activity.id comment %}
{% if map_value %}
{{ map_value }}
{% else %}
get working sucka!
{% endif %}
here is the section of the templatetag file (see Gerry's links for the details of how to set this up)
from django import template
register = template.Library()
#register.tag(name="access_map_method")
def do_access_map_method(parser, token):
try:
tag_name, dict_name , key_name, method_name = token.contents.split()
except ValueError:
msg = '%r tag requires three arguments' % token.contents[0]
raise template.TemplateSyntaxError(msg)
return MapNode(dict_name , key_name, method_name)
class MapNode(template.Node):
def __init__(self, dict_name, key_name, method_name):
self.dict_var = template.Variable(dict_name)
self.key_var = template.Variable(key_name)
self.method_name = method_name
def render(self, context):
try:
dict_obj = self.dict_var.resolve(context)
key_obj = self.key_var.resolve(context)
if key_obj in dict_obj.keys():
if self.method_name:
context['map_value'] = getattr(dict_obj[key_obj], self.method_name)
else:
context['map_value'] = dict_obj[key_obj]
else:
context['map_value'] = ''
except template.VariableDoesNotExist:
context['map_value'] = ''
return ''