Django: Adding additional properties to Model Class Object - python

This is using Google App Engine. I am not sure if this is applicable to just normal Django development or if Google App Engine will play a part. If it does, would you let me know so I can update the description of this problem.
class MessageModel(db.Model):
to_user_id = db.IntegerProperty()
to_user = db.StringProperty(multiline=False)
message = db.StringProperty(multiline=False)
date_created = db.DateTimeProperty(auto_now_add=True)
Now when I do a query a get a list of "MessageModel" and send it to the template.html to bind against, I would like to include a few more properties such as the "since_date_created" to output how long ago since the last output, potentially play around with the message property and add other parameters that will help with the layout such as "highlight" , "background-color" etc...
The only way I thought of is to loop through the initial Query Object and create a new list where I would add the property values and then append it back to a list.
for msg in messagesSQL:
msg.lalaland = "test"
msg.since_created_time = 321932
msglist.append(msg)
Then instead of passing the template.html messagesSQL, I will now pass it msglist.

You should still be able to send it messagesSQL to the template after you've added elements to it via the for loop. Python allows that sort of thing.
Something else that might make sense in some cases would be to give your MessageModel methods. For instance, if you have a
def since_date_created(self):
'''Compute the time since creation time based on self.date_created.'''
Then (assuming you have "messagesSQL" in the template), you can use the function as
{% for msg in messagesSQL %}
{{ msg.since_date_created }}
{% endfor %}
Basically, you can call any method in the model as long as you it needs no arguments passed to it.

You can obtain that by defining methods in the model
like
class MessageModel(db.Model):
# Definition
def since_date_created(self):
# ...
Now in the template, you can use it like
Time since created {{ message.since_date_created }}

Related

Why is the get_absolute_url() defined in the models.py?

I am trying to redo my app views with a Class Based Views(CBV) and stumbled across this function get_absolute_url() being defined in the models.py, generic editing views
I have created models and have never used this function before. Is this specific to CBVs?
It's not specific to CBV, you can use it anywhere in your application. It makes it much easier to get the url for a model instance without having to mess around with url resolving. Also it is much easier to get the definitive url for your object in a template when you can call get_absolute_url on the object itself. For example, if you are looping through a list of objects:
{% for post in blog_posts %}
read post
{% endfor %}
That said, there's nothing stopping you using the method in your view either:
post = BlogPost.objects.get(...)
url = post.get_absolute_url()
There's also is nothing at all special about the method though. You can write your own get_foo_url() if you like instead. For example, I wrote a blog post about a get_admin_url, a method to allow you to get the Django admin url to an object:
class Book(models.Model):
...
def get_admin_url(self):
content_type = ContentType \
.objects \
.get_for_model(self.__class__)
return reverse("admin:%s_%s_change" % (
content_type.app_label,
content_type.model),
args=(self.id,))
# {{ book.get_admin_url }}

Extend Model's Queryset with additional attributes

I have simple Django model with some internet sessions (Radius logs). And want to show it in my template.
models.py:
class Radacct(models.Model):
radacctid = models.BigIntegerField(primary_key=True)
username = models.CharField(max_length=253)
nasipaddress = models.IPAddressField()
class Meta:
db_table = u'radacct'
view.py:
def ajax_radius_sessions(request, username):
radius_sessions = Radacct.objects.filter(username=username).order_by('-radacctid')
template.html:
{% for session in radius_sessions %}
{{ session.username }}, {{ session.nasipaddress }}</br>
{% endfor %}
In my template, I need to show the hostname based on user's ip-address (nasipaddress) as well.
Method 1:
Creation of Model's method.
I do not want to calculate Hostname as Model's method, because it will be triggered for every record, but the number of session for particular user can be very big — in this case it will cause huge amount of DNS-checks. 1000 sessions = 1000 DNS checks?..
Method 2a:
View level.
I was trying to this on View level, to check only unique IPs and get the "local" dictionary with IP-Hostname pairs:
#servers={'192.168.100.1':'alpha', '192.168.100.2':'beta', '192.168.100.3':'gamma'}
But I can not access this dictionary in the template, using the key as variable:
#Wrong!
{{ servers[session.nasipaddress] }}
Method 2b:
View level. Adding new attribute to the Queryset instance.
Maybe I can add a new attribute to my Radacct Model which is not connected with database. And fill it by hostname, in my View?
What is the proper way to calculate some "attribute" and then access it in the Template in Queryset {% for %} loop?
Again: it seems I can not do this as Model's method, so I think I should extend my database results with custom ones.
P.S. Sorry for a really looong post. This is my very first try on Stackoverflow. Thank you!
Model "method". Create a separate class that is responsible for looking up DNS entries and caching them, and refer to an instance of this class in a descriptor on the model.

Properly Defining Relationships in Django DB

I'm working on a fitness game web app. The idea is that each week has a certain number of tasks that a person must complete before the next week is revealed. Here is my models.py schema for the app so far:
from django.db import models
from django.contrib.auth.models import User
class WeekOne(models.Model):
squats = models.PositiveIntegerField()
lunges = models.PositiveIntegerField()
skipStairs = models.BooleanField()
stairDaysCount = models.PositiveSmallIntegerField()
# Set to true if (squats == 1000), (lunges == 250),
# (skipStairs is True), and (stairDaysCount == 3)
weekOneComplete = models.BooleanField()
class UserProfile(models.Model):
user = models.OneToOneField(User)
weekOne = models.ForeignKey(WeekOne)
I'm lost on a few points. First of all, obviously I want each user to be able to track their own progress and not have any other users be able to see it. Is making weekOne a ForeignKey the best way to do this? If so, how does accessing each user's data work once this relationship is defined? For example, if I wanted to create an addSquats function, would I do something like this:
user = UserProfile()
user.squats += 5
or would I have to do some other magic to get to the squats field?
Second, every time a user makes a change to their progress (i.e., adds a squat or lunge), I want to check if all of the fields have met a certain a benchmark. If they have, I want to set weekOneComplete to true. Each addition will be triggered by some javascript when a user clicks a button -- but where would I put the function that checks/updates the database?
First of all, obviously I want each user to be able to track their own progress and not have any other users be able to see it.
In the template, you can do like this
User: {{ user.username }}
squats: {{ user.userprofile.squats }}
lunges: {{ user.userprofile.lunges }}
Skip Stairs:
{% if user.userprofile.skipStairs %}
Yes
{% else %}
No
{% endif %}
Stair: {{ user.userprofile.stairDaysCount }}}
Week Completed:
{% if user.userprofile.weekOneComplete %}
Yes
{% else %}
In-Progress
{% endif %}
How does accessing each user's data work once this relationship is defined? For example, if I wanted to create an addSquats function.
To access user data,
user = UserProfile(user=request.user)
user.weekOne.squats += 5
user.weekOne.save()
user.save()
Second, every time a user makes a change to their progress (i.e., adds a squat or lunge), I want to check if all of the fields have met a certain a benchmark. If they have, I want to set weekOneComplete to true.
Under your UserProfile model, create check updates function.
class UserProfile(models.Model):
user = models.OneToOneField(User)
weekOne = models.ForeignKey(WeekOne)
def check_updates(self):
check = WeekOne.object.get(id=self.weekOne)
if check.skipStairs and \
check.squats == 1000 and \
check.lunges == 250 and \
check.stairDaysCount == 3:
check.weekOneComplete = True
check.save()
So every time you update the data for that user, just call the method like this:
user = UserProfile.objects.get(user=request.user)
user.check_updates()
To access field of week one you need to do:
user.weekOne.squats += 5
user.weekOne.save()
Actually, it is better to use the F function and do (or similar):
user.weekOne.squats = F('squates') + 5
In general, it is better to do all checkings also in the server side and not to rely on the client (JS or whatever). E.g You expose a url and check for all the POST params that they are integers (e.g. converted to ints)
To your second question: one possible (and simple) way of doing this, since you say you're using javascript, is through an ajax call.
It should point to a url which, itself, points to a view that'll handle the data you're sending in the request. Something along the lines of (say you're using a POST request):
def add(request):
if not request.is_ajax():
raise ...
excercise, amount = request.POST['excercise'], request.POST['amount']
user = request.user
# a model method that'll add to whatever activity
# the user did and update the "week one complete" field
user.did_activity(excercise, amount)
if user.weekOne.weekOneComplete:
return HttpResponse(json.dumps(some_return_data), mimetype="application/json")
return HttpResponse(json.dumps(other_return_data), mimetype="application/json")
This is more to the side of pseudocode, so you get the idea. You'd still need to write the ajax call on the JS side, the model method that'll add to the correct excercise and validate the benchmark, and save the user to the database. For example:
def did_activity(self, excercise, amount):
if excercise == 'squats':
self.weekOne.squats += amount
...
if self.hit_benchmark():
self.weekOne.weekOneComplete = True
self.save()
Also, this example assumes the user is authenticated.
Good luck.

Django Haystack - Show results without needing a search query?

I would like to display all results which match selected facets even though a search query has not been inserted. Similar to how some shop applications work e.g. Amazon
e.g. Show all products which are "blue" and between $10-$100.
Haystack does not return any values if a search query is not specified.
Any ideas how I can get around it?
Thanks!
If anyone is still looking, there's a simple solution suggested in haystack code:
https://github.com/toastdriven/django-haystack/blob/master/haystack/forms.py#L34
class SearchForm(forms.Form):
def no_query_found(self):
"""
Determines the behavior when no query was found.
By default, no results are returned (``EmptySearchQuerySet``).
Should you want to show all results, override this method in your
own ``SearchForm`` subclass and do ``return self.searchqueryset.all()``.
"""
return EmptySearchQuerySet()
Why No Results?
I imagine you're using a search template similar to the one in the haystack getting started documentation. This view doesn't display anything if there is no query:
{% if query %}
{# Display the results #}
{% else %}
{# Show some example queries to run, maybe query syntax, something else? #}
{% endif %}
The second problem is that the default search form's search() method doesn't actually search for anything unless there's a query.
Getting Results
To get around this, I'm using a custom search form. Here's an abbreviated sample:
class CustomSearchForm(SearchForm):
...
def search(self):
# First, store the SearchQuerySet received from other processing.
sqs = super(CustomSearchForm, self).search()
if not self.is_valid():
return sqs
filts = []
# Check to see if a start_date was chosen.
if self.cleaned_data['start_date']:
filts.append(SQ(created_date__gte=self.cleaned_data['start_date']))
# Check to see if an end_date was chosen.
if self.cleaned_data['end_date']:
filts.append(SQ(created_date__lte=self.cleaned_data['end_date']))
# Etc., for any other things you add
# If we started without a query, we'd have no search
# results (which is fine, normally). However, if we
# had no query but we DID have other parameters, then
# we'd like to filter starting from everything rather
# than nothing (i.e., q='' and tags='bear' should
# return everything with a tag 'bear'.)
if len(filts) > 0 and not self.cleaned_data['q']:
sqs = SearchQuerySet().order_by('-created_date')
# Apply the filters
for filt in filts:
sqs = sqs.filter(filt)
return sqs
Also, don't forget to change the view:
{% if query or page.object_list %}
{# Display the results #}
{% else %}
{# Show some example queries to run, maybe query syntax, something else? #}
{% endif %}
Actually, the view code is a little hackish. It doesn't distinguish query-less searches with no results from search with no parameters.
Cheers!
Look at SearchQuerySet.
This should be possible if color and price has been defined in your SearchIndex:
sqs = SearchQuerySet().filter(color="blue", price__range=(10,100))
You can limit the query to certain models by adding models(Model) to the SearchQuerySet. So if you want to limit your query to the model Item use:
sqs = SearchQuerySet().filter(color="blue", price__range=(10,100)).models(Item)
Following form display all the result if not query string is present. Now you can add custom filters.
from your_app.forms import NonEmptySearchForm
url(r'^your_url$',
SearchView(template='search.html',searchqueryset=sqs,form_class=NonEmptySearchForm), name='haystack_search'),
forms.py
#Overridding because the default sqs is always none if no query string is present
class NonEmptySearchForm(SearchForm):
def search(self):
if not self.is_valid():
return self.no_query_found()
sqs = self.searchqueryset.auto_query(self.cleaned_data['q'])
if self.load_all:
sqs = sqs.load_all()
return sqs
Stumpy Joe Pete's answer is pretty spot on, but as he mentioned, the template if query or page.object_list check is a little hacked. A better way of solving this would be to create your own SearchForm which would still find something if q is empty - will not repost that - AND to customize the SearchView with something like:
class MySearchView(SearchView):
def get_query(self):
query = []
if self.form.is_valid():
for field in self.form:
if field.name in self.form.cleaned_data and self.form.cleaned_data[field.name]:
query.append(field.name+'='+str(self.form.cleaned_data[field.name]))
return ' AND '.join(query)
In most cases, you won't even be using the query value, so you could just as well do a quick check if any of the fields is set and return True or something like that.. or of course you can modify the output any way you want (I'm not even 100% sure my solution would work for all field types, but you get the idea).

how to extend django views/templates in a forward looking way

i'm looking for a way to extend a django template/view.
my first implementation consists of two models (clients/models.py):
class Client(models.Model):
...
class Address(models.Model):
client = models.ForeignKey(Client)
...
and its fairly simple template (clients/detail.html) :
{{client.name}}
Address: {{client.address.street}}, {{client.address.zipcode}} {{client.address.city}}
as my application grows, a new app was born: 'invoices'.
it is again very simple (invoices/models.py):
class Invoice(models.Model):
client = models.ForeignKey(clients.models.Client)
...
now my clients details-view needs to display invoices, so i create and override clients/detail.html in my 'invoices' app.
good for now.
later on i created a third app 'quotes'.
again my clients details-view needs to display quotes.
if i create clients/detail.html in my 'clients' i will loose the ability to display invoices.
because the 'invoices' and 'quotes' app are indipendent.
my first idea was to create something like a SubView-class
which 'invoices' and 'quotes' can extend and then register their implementation somewhere.
a template should look like this:
{{client.name}}
Address: {{client.address.street}}, {{client.address.zipcode}} {{client.address.city}}
{% for view in views %}
<h1>{{view.title}}</h1>
{{view.get_html}}
{% endfor %}
is this a good way to go and should i use a admin.site-like implementation for registering my sub-views?
In Django one url in urls.py should ideally use one view, just to keep things simple.
I would therefore adopt the approach of putting all the required context in your one view for this screen (I think you already have this via foreign keys in your model). Then, rather than doing what you call "SubView-class" I would go for the Django template include tag.
Example:
{% for invoice in client.invoices %}
{% include "invoice-detail.html" with invoice=invoice %}
{% endfor %}
This renders each invoice's detail for all the invoices of the client. Notice how this is in line with the DRY principle.

Categories

Resources