I want to search based on distance from inputted US zipcode.
First, I know I need a search form:
class SearchForm(forms.Form):
zipcode = forms.CharField(max_length=5)
Then I pass those options to next view where I filter based on inputted parameters. This is where it gets tricky for me.. I have searched around a lot and it seems there are many solutions to this. I have used this post as a reference would give me something like this:
def display_map(request, zipcode):
objects_near_zip = Thing.objects.filter(location__distance_lte=(Point([zipcode]), D(mi=5)))
But I need to turn the zipcode into a point. How would I do this? Is there a better solution that you have used? Thanks for your ideas!
EDIT:
I found this discussion, but the implementation is a little hard for me to understand. I create a Zipcode model, that makes sense.
But Im not sure how or where to load the zipcodes like he says in the post:
lm = LayerMapping(Zipcode, 'tl_2008_us_zcta5.shp',
{ 'code' : 'ZCTA5CE',
'mpoly' : 'MULTIPOLYGON',
})
lm.save()
Where do I place this code? The shp file is quite large and took a long time even on my desktop, so Im not sure this is the best solution.
Related
I have two models, one with ForeignKey I'm trying to match. In order to do so, I'm looking up second model by a specific number and a date. The problem is it has two dates and I have to make decision on which date to choose. Under some circumstances it is set to NULL, in some it is not. If it is I have to get the second date field. I have something like this:
class MyModel1(models.Model):
model2_key = models.ForeignKey(MyModel2)
model1_date=...
model1_number=...
second model:
class MyModel2(models.Model):
model2_date1=...
model2_date2=...
model2_number=...
Now, how to make the choice? I have looked up documentation regarding F expressions, Q expressions, When expressions, Select and I'm a little bit confused. How can I wrtie a function that returns searched MyModel2 object? I have something like this, but it won't work.
def _find_model2(searched_date, searched_number):
searched_model2=MyModel2.objects.get(Q(model2_number=searched_number),
Q(When(model2_date1__e='NULL', then=model2_date2) |
Q(When(model2_date1__ne='NULL', then=model2_date1))=searched_date))
I am quite new to django, so any help will be appreciated.
I have made a workaround this issue, I don't think it's mostefficient and elegant one, but it works. Should anyone have a better solution please post it.
First, all objects whose corresponding dates match are called:
from_query = list(MyModel2.objects.filter(Q(model2_date1__range=
(datetime_min, datetime_max)) | Q(model2_date2__range=(datetime_min, datetime_max)),
model2_number=searched_number))
Then I iterate over found objects:
to_return = []
for item in from_query:
if item.model2_date1:
to_return.append(item)
elif datetime_min <= item.model2_date2 <= datetime_max:
to_return.append(item)
EDIT: I've come up with a solution. Assuring that model2_date1__isnull=True is enough. The solution now looks like this:
from_query = list(MyModel2.objects.get((Q(model2_date1__range=(datetime_min, datetime_max)) |
Q(Q(model2_date2__range=(datetime_min, datetime_max)),
Q(model2_date1__isnull=True)),
model2_number=searched_number))
I've got django 1.8.5 and Python 3.4.3, and trying to create a subquery that constrains my main data set - but the subquery itself (I think) needs a join in it. Or maybe there is a better way to do it.
Here's a trimmed down set of models:
class Lot(models.Model):
lot_id = models.CharField(max_length=200, unique=True)
class Lot_Country(models.Model):
lot = models.ForeignKey(Lot)
country = CountryField()
class Discrete(models.Model):
discrete_id = models.CharField(max_length=200, unique=True)
master_id = models.ForeignKey(Inventory_Master)
location = models.ForeignKey(Location)
lot = models.ForeignKey(Lot)
I am filtering on various attributes of Discrete (which is discrete supply) and I want to go "up" through Lot, over the Lot_Country, meaning "I only want to get rows from Discrete if the Lot associated with that row has an entry in Lot_Country for my appropriate country (let's say US.)
I've tried something like this:
oklots=list(Lot_Country.objects.filter(country='US'))
But, first of all that gives me the str back, which I don't really want (and changed it to be lot_id, but that's a hack.)
What's the best way to constrain Discrete through Lot and over to Lot_Country? In SQL I would just join in the subquery (or even in the main query - maybe that's what I need? I guess I don't know how to join up to a parent then down into that parent's other child...)
Thanks in advance for your help.
I'm not sure what you mean by "it gives me the str back"... Lot_Country.objects.filter(country='US') will return a queryset. Of course if you print it in your console, you will see a string.
I also think your models need refactoring. The way you have currently defined it, you can associate multiple Lot_Countrys with one Lot, and a country can only be associated with one lot.
If I understand your general model correctly that isn't what you want - you want to associate multiple Lots with one Lot_Country. To do that you need to reverse your foreign key relationship (i.e., put it inside the Lot).
Then, for fetching all the Discrete lots that are in a given country, you would do:
discretes_in_us = Discrete.objects.filter(lot__lot_country__country='US')
Which will give you a queryset of all Discretes whose Lot is in the US.
Im reading over an itunes library file. I scraped the artist names and songs and put them in parallel lists, one containing artist names and another containing artist songs. I would like to do this by using only lists
artist_choice = input("Enter artist name: ")
artist_names = [Logic, Kanye West, Lowkey, Logic, Logic]
artist_songs = [Underpressure, Stronger, Soundtrack to the struggle, Ballin, Im the man]
Say the user inputs the artist name Logic, how would i loop through the parallel list and print out every song associated with the artist Logic? if the user entered Logic the output should be:
Underpressure
Ballin
Im the man
This is sudo code for how to do it, I actually don't know much python.
results = [];
for (i=0;i<artist_names.length();i++): 1
if artist_names[i] == artist_choice:
results.push(artist_songs[i])
but as #Carcigenicate said, there are better ways of going about this. If you are going to be making many searches on these lists you may want to first loop through and group the data into a hash table or what #Carcigenicate suggests.
#RPGillespie 's link explains how to combine them into a hash table, this is a much better way of searching.
Rich beat me to it, but I'll post a more pythonic example:
def getSongs(listOfArtists,listOfSongs,artistToLookup):
songs = []
for artist,song in zip(listOfArtists,listOfSongs):
if (artist == artistToLookup):
songs.append(song)
return songs
Note using zip lets you iterate both lists at once fairly cleanly (without the need to subscript).
I'm trying to get the ten most commented posts in my django app, but I'm unable to do it because I can't think a proper way.
I'm currently using the django comments framework, and I've seen a possibility of doing this with aggregate or annotate , but I can figure out how.
The thing would be:
Get all the posts
Calculate the number of comments per post (I have a comment_count method for that)
Order the posts from most commented to less
Get the first 10 (for example)
Is there any "simple" or "pythonic" way to do this? I'm a bit lost since the comments framework is only accesible via template tags, and not directly from the code (unless you want to modify it)
Any help is appreciated
You're right that you need to use the annotation and aggregation features. What you need to do is group by and get a count of the object_pk of the Comment model:
from django.contrib.comments.models import Comment
from django.db.models import Count
o_list = Comment.objects.values('object_pk').annotate(ocount=Count('object_pk'))
This will assign something like the following to o_list:
[{'object_pk': '123', 'ocount': 56},
{'object_pk': '321', 'ocount': 47},
...etc...]
You could then sort the list and slice the top 10:
top_ten_objects = sorted(o_list, key=lambda k: k['ocount'])[:10]
You can then use the values in object_pk to retrieve the objects that the comments are attached to.
Annotate is going to be the preferred way, partially because it will reduce db queries and it's basically a one-liner. While your theoretical loop would work, I bet your comment_count method relies on querying comments for a given post, which would be 1 query per post that you loop over- nasty!
posts_by_score = Comment.objects.filter(is_public=True).values('object_pk').annotate(
score=Count('id')).order_by('-score')
post_ids = [int(obj['object_pk']) for obj in posts_by_score]
top_posts = Post.objects.in_bulk(post_ids)
This code is shameless adapted from Django-Blog-Zinnia (no affiliation)
I have this query:
checkins = CheckinAct.objects.filter(time__range=[start, end], location=checkin.location)
Which works great for telling me how many checkins have happened in my date range for a specific location. But I want know how many checkins were done by unique users. So I tried this:
checkins = CheckinAct.objects.filter(time__range=[start, end], location=checkin.location).values('user').distinct()
But that doesn't work, I get back an empty Array. Any ideas why?
Here is my CheckinAct model:
class CheckinAct(models.Model):
user = models.ForeignKey(User)
location = models.ForeignKey(Location)
time = models.DateTimeField()
----Update------
So now I have updated my query to look like this:
checkins = CheckinAct.objects.values('user').\
filter(time__range=[start, end], location=checkin.location).\
annotate(dcount=Count('user'))
But I'm still getting multiple objects back that have the same user, like so:
[{'user': 15521L}, {'user': 15521L}, {'user': 15521L}, {'user': 15521L}, {'user': 15521L}]
---- Update 2------
Here is something else I tried, but I'm still getting lots of identical user objects back when I log the checkins object.
checkins = CheckinAct.objects.filter(
time__range=[start, end],
location=checkin.location,
).annotate(dcount=Count('user')).values('user', 'dcount')
logger.info("checkins!!! : " + str(checkins))
Logs the following:
checkins!!! : [{'user': 15521L}, {'user': 15521L}, {'user': 15521L}]
Notice how there are 3 instances of the same user object. Is this working correctly or not? Is there a difference way to read out what comes back in the dict object? I just need to know how many unique users check into that specific location during the time range.
The answer is actually right in the Django docs. Unfortunately, very little attention is drawn to the importance of the particular part you need; so it's understandably missed. (Read down a little to the part dealing with Items.)
For your use-case, the following should give you exactly what you want:
checkins = CheckinAct.objects.filter(time__range=[start,end], location=checkin.location).\
values('user').annotate(checkin_count=Count('pk')).order_by()
UPDATE
Based on your comment, I think the issue of what you wanted to achieve has been confused all along. What the query above gives you is a list of the number of times each user checked in at a location, without duplicate users in said list. It now seems what you really wanted was the number of unique users that checked in at one particular location. To get that, use the following (which is much simpler anyways):
User.objects.filter(checkinat__location=location).distinct().count()
UPDATE for non-rel support
checkin_users = [(c.user.pk, c.user) for c in CheckinAct.objects.filter(location=location)]
unique_checkins = len(dict(checkin_users))
This works off the principle that dicts have unique keys. So when you convert the list of tuples to a dict, you end up with a list of unique users. But, this will generate 1*N queries, where N is the total amount of checkins (one query each time the user attribute is used. Normally, I'd do something like .select_related('user'), but that too requires a JOIN, which is apparently out. JOINs not being supported seems like a huge downside to non-rel, if true, but if that's the case this is going to be your only option.
You don't want DISTINCT. You actually want Django to do something that will end up giving you a GROUP BY clause. You are also correct that your final solution is to combine annotate() and values(), as discussed in the Django documentation.
What you want to do to get your results is to use annotate first, and then values, such as:
CheckinAct.objects.filter(
time__range=[start, end],
location=checkin.location,
).annotate(dcount=Count('user').values('user', 'dcount')
The Django docs at the link I gave you above show a similarly constructed query (minus the filter aspect, which I added for your case in the proper location), and note that this will "now yield one unique result for each [checkin act]; however, only the [user] and the [dcount] annotation will be returned in the output data". (I edited the sentence to fit your case, but the principle is the same).
Hope that helps!
checkins = CheckinAct.objects.values('user').\
filter(time__range=[start, end], location=checkin.location).\
annotate(dcount=Count('user'))
If I am not mistaken, wouldn't the value you want be in the input as "dcount"? As a result, isn't that just being discarded when you decide to output the user value alone?
Can you tell me what happens when you try this?
checkins = CheckinAct.objects.values('user').\
filter(time__range=[start, end], location=checkin.location).\
annotate(Count('user')).order_by()
(The last order_by is to clear any built-in ordering that you may already have at the model level - not sure if you have anything like that, but doesn't hurt to ask...)