Django - Creating data with or without .create() - django

I'm following the official Django Tutorial and confused about this part:
Sometimes they create a model data without .create() like:
Poll(pub_date= timezone.now() )
and sometimes they use .create() like:
Poll.objects.create(pub_date= timezone.now() )
From what I run, both returns the same result. So is there any difference?
Thanks

The latter saves it in the table (performs an implicit .save()). The former does not.

Related

Django .get() raises DoesNotExist error without explicit '__exact' lookup

I've faced with issue, which I cannot neither understand nor 'google', while followed steps from "Practical Django Projects" book.
The example of view code below should return specific Entry object (I omitted unnecessary part), but it raises "DoesNotExist: Entry matching query does not exist" error:
...
return render_to_response('weblog/entry_detail.html',
{'entry':Entry.objects.get(pub_date__year=pub_date.year,
pub_date__month=pub_date.month,
pub_date__day=pub_date.day,
slug=slug)
(I confirmed that target object indeed exists, etc.)
When I replaced .get() with filter() method, it returned me queryset with my target object.
After some 'hitting-the-wall' sessions, I managed to make .get() call work when replaced
slug=slug
with
slug__exact=slug
I cannot get the difference between these two. Seems to me, Django's docs clearly state that in such case '__exact' is implied (Django 1.6, "Making queries")
I also cannot check the actual SQL query which Django ran in the .get() cases to compare with SQL query used with .filter() method (the result is either object, not queryset, or raised exception).
So, I actually have 2 workarounds (filter()[0] to get single object, or '__exact'), but I want to understand the weird behavior with .get() method.
My questions are:
Did I misunderstand documentation about '__exact' implication in my case?
If no, isn't my problem a Django/DB bug?
Is there a way to check the actual SQL query which Django has performed, when result of query is not a queryset object?
Thank you!
Note: I run Django 1.6.1 / Python 2.7.3 / MySQL 5.5.33
Update: I installed suggested django-debug-toolbar and was able to compare queries for .get() call with & w/o '__exact' lookup. The only difference that I see between these queries, is the order of 'AND' conditions, so still have no clue what's going on:
slug=slug:
SELECT weblog_entry.id, weblog_entry.title, weblog_entry.excerpt, weblog_entry.body, weblog_entry.pub_date, weblog_entry.excerpt_html, weblog_entry.body_html, weblog_entry.author_id, weblog_entry.slug, weblog_entry.status, weblog_entry.enable_comments, weblog_entry.featured FROM weblog_entry WHERE (EXTRACT(MONTH FROM CONVERT_TZ(weblog_entry.pub_date, 'UTC', 'UTC')) = 2 AND weblog_entry.pub_date BETWEEN '2014-01-01 00:00:00' and '2014-12-31 23:59:59' AND EXTRACT(DAY FROM CONVERT_TZ(weblog_entry.pub_date, 'UTC', 'UTC')) = 2 AND weblog_entry.slug = '3rd-entry' )
slug__exact=slug:
SELECT weblog_entry.id, weblog_entry.title, weblog_entry.excerpt, weblog_entry.body, weblog_entry.pub_date, weblog_entry.excerpt_html, weblog_entry.body_html, weblog_entry.author_id, weblog_entry.slug, weblog_entry.status, weblog_entry.enable_comments, weblog_entry.featured FROM weblog_entry WHERE (EXTRACT(MONTH FROM CONVERT_TZ(weblog_entry.pub_date, 'UTC', 'UTC')) = 2 AND weblog_entry.pub_date BETWEEN '2014-01-01 00:00:00' and '2014-12-31 23:59:59' AND weblog_entry.slug = '3rd-entry' AND EXTRACT(DAY FROM CONVERT_TZ(weblog_entry.pub_date, 'UTC', 'UTC')) = 2)
Note: I've tried to execute these queries manually from mysql console and they both selected target entry;
Update2: I've changed title to point on the problem more precisely.
Ok, let me speak for collective unconscious.
Did I misunderstand documentation about '__exact' implication in my case?
No, you got it right. Let me quote django doc:
As a convenience when no lookup type is provided (like in
Entry.objects.get(id=14)) the lookup type is assumed to be exact.
And since you observe something that contradicts requirements, answer to the next question is:
If no, isn't my problem a Django/DB bug?
Yes, it is a bug. Me and whole Django community will be grateful if you describe steps to reproduce and file an issue
Is there a way to check the actual SQL query which Django has
performed, when result of query is not a queryset object?
Looks you already got the answer :)

MongoEngine get_or_create Alternatives

I've been using the get_or_create method with MongoEngine in a Django app. Today, I noticed there were a few duplicate entries. I came across this in the MongoEngine API Reference for get_or_create:
This requires two separate operations and therefore a race condition exists. Because there are no transactions in mongoDB other approaches should be investigated, to ensure you don’t accidentally duplicate data when using this method. This is now scheduled to be removed before 1.0
Should I be using something like this?:
from models import Post
post = Post(name='hello')
try:
Posts.objects.get(name=post.name)
print "exists"
except:
post.save()
print "saved"
Will that solve my problem?
Is there a better way?
To perform an upsert use the following syntax:
Posts.objects(name="hello").update(set__X=Y, upsert=True)
That will add a post with the name "hello" and where X = Y if it doesn't already exist, otherwise it will update an existing post just setting X = Y.
If you need pass a dictionery, can do this:
post = Post.objects(name="hello").first() or Post(name="hello")
then you can update with something like this:
# data = dictionary_with_data
for field, value in data.items():
post[field] = value
post.save()

Django: How to use django.forms.ModelChoiceField with a Raw SQL query?

I'm trying to render a form with a combo that shows related entities. Therefore I'm using a ModelChoiceField.
This approach works well, until I needed to limit which entities to show. If I use a simple query expression it also works well, but things break if I use a raw SQL query.
So my code that works, sets the queryset to a filter expression.
class ReservationForm(forms.Form):
location_time_slot = ModelChoiceField(queryset=LocationTimeSlot.objects.all(), empty_label="Select your prefered time")
def __init__(self,*args,**kwargs):
city_id = kwargs.pop("city_id") # client is the parameter passed from views.py
super(ReservationForm, self).__init__(*args,**kwargs)
# TODO: move this to a manager
self.fields['location_time_slot'].queryset = LocationTimeSlot.objects.filter(city__id = city_id )
BUT, if I change that to a raw query I start having problems. Code that does not work:
class ReservationForm(forms.Form):
location_time_slot = ModelChoiceField(queryset=LocationTimeSlot.objects.all(), empty_label="Select your prefered time")
def __init__(self,*args,**kwargs):
city_id = kwargs.pop("city_id") # client is the parameter passed from views.py
super(ReservationForm, self).__init__(*args,**kwargs)
# TODO: move this to a manager
query = """SELECT ts.id, ts.datetime_to, ts.datetime_from, ts.available_reserves, l.name, l.'order'
FROM reservations_locationtimeslot AS ts
INNER JOIN reservations_location AS l ON l.id = ts.location_id
WHERE l.city_id = %s
AND ts.available_reserves > 0
AND ts.datetime_from > datetime() """
time_slots = LocationTimeSlot.objects.raw(query, [city_id])
self.fields['location_time_slot'].queryset = time_slots
The first error I get when trying to render the widget is: 'RawQuerySet' object has no attribute 'all'
I could solve that one thanks to one of the commets in enter link description here, by doing:
time_slots.all = time_slots.__iter__ # Dummy fix to allow default form rendering with raw SQL
But now I'm getting something similar when posting the form:
'RawQuerySet' object has no attribute 'get'
Is there a proper way to prepare a RawQuerySet to be used by ModelChoiceField?
Thanks!
Are you sure you actually need a raw query there? Just looking at that query, I can't see any reason you can't just do it with filter(location__city=city_id, available_reserves__gte=0, datetime_from__gt=datetime.datetime.now()).
Raw query sets are missing a number of methods that are defined on conventional query sets, so just dropping them in place isn't likely to work without writing your own definitions for all those methods.
I temporarily fixed the problem adding the missing methods.
The way I'm currently using the ModelChoiceField I only needed to add the all() and get() methods, but in different scenarios you might need to add some other methods as well. Also this is not a perfect solution because:
1) Defining the get method this way migth produce incorrect results. I think the get() method is used to validate that the selected option is within the options returned by all(). The way I temporarily implemented it only validates that the id exists in the table.
2) I guess the get method is less performant specified this way.
If anyone can think of a better solution, please let me know.
So my temporary solution:
class LocationTimeSlotManager(models.Manager):
def availableSlots(self, city_id):
query = """SELECT ts.id, ts.datetime_to, ts.datetime_from, ts.available_reserves, l.name, l.'order'
FROM reservations_locationtimeslot AS ts
.....
.....
MORE SQL """
time_slots = LocationTimeSlot.objects.raw(query, [city_id])
# Dummy fix to allow default form rendering with raw SQL
time_slots.all = time_slots.__iter__
time_slots.get = LocationTimeSlot.objects.get
return time_slots

Django get() query not working

this_category = Category.objects.get(name=cat_name)
gives error: get() takes exactly 2 non-keyword arguments (1 given)
I am using the appengine helper, so maybe that is causing problems. Category is my model. Category.objects.all() works fine. Filter is also similarily not working.
Thanks,
Do you have any functions named name or cat_name? If so, try changing them or the variable names you are using and trying again.
The helper maps the Django model manager (Category.objects in this case) back to the class instance of the model via the appengine_django.models.ModelManager. Through the inheritance chain you eventually come to appengine.ext.db.Model.get(cls, keys, **kwargs) so that is why you are seeing this error. The helper does not support the same interface for get that Django does. If you do not want to get by primary key, you must use a filter
To do your query, you need to use the GAE filter function like this:
this_category = Category.objects.all().filter('name =', cat_name).get()

Django's list_details views saving queryset to memory (not updating)?

I have a custom model manager that looks like this:
class MyManager(models.Manager)
def get_query_set(self):
'''Only get items that are 'approved' and have a `pub_date` that is in
the past. Ignore the rest.'''
queryset = super(MyManager, self).get_query_set()
queryset = queryset.filter(status__in=('a',))
return queryset.filter(pub_date__lte=datetime.utcnow())
And this works well enough; however, I have a problem using Django's generic.list_detail views object_detail and object_list: the queryset seems to be only loading once and, because of this, it isn't fetching the items it should be because, I assume, the utcnow() time has been called only once (when it first loaded).
I assume this is intentional and meant as a performance boost - however, it means that video's show up elsewhere on the site (in places I am not in a object_detail view) before they are available in an object_detail view (see urls.py below). This is leading to 404s ...
Any ideas ? Or do I have to write my own custom views to avoid this ?
Thanks!
urls.py
url(r'^video/(?P<object_id>\d+)$',
list_detail.object_detail,
{ 'queryset': Video.objects.all(), },
name='video_detail',
),
It is not a problem of cache: as you do it now, the queryset definition is evaluated once, while parsing urls, and then, it is never evaluated again.
Solution is actually pretty simple and described in the online documentation: Complex filtering with wrapper functions: just create a small custom view, that will simply call the generic view.
I am actually using a similar solution quite a lot and I feel it quite comfortable.
By the way, a small side note, for this case I would suggest not using a custom manager, and go back instead on a normal filtering.
Try correcting urls.py to:
url(r'^video/(?P<object_id>\d+)$',
list_detail.object_detail,
{ 'queryset': Video.objects.all, }, # here's the difference
name='video_detail',
)
Edit:
If this fail, try apply similar technique(passing callable instead of calling it) to filter():
return queryset.filter(pub_date__lte=datetime.utcnow)
I have an almost identical model Manager to thornomad, and the same problem with generic views.
I have to point out that neither of the suggestions above work:
doing Video.objects.all without parentheses gives an error
doing queryset.filter(pub_date__lte=datetime.utcnow), again without the parentheses, does not give an error but does not fix the problem
I have also tried another way, which is to use a lambda to return the queryset, eg:
qs = lambda *x: Video.objects.all()
url(r'^video/(?P<object_id>\d+)$',
list_detail.object_detail,
{ 'queryset': qs(), },
name='video_detail',
),
...it didn't work either and I can see now I must have been desperate to think it would :)
lazy_qs = lambda *x: lazy(Post.live_objects.all, QuerySet)
blog_posts = {
'queryset': lazy_qs(),
...doesn't work either (gives an error) as utils.functional.lazy doesn't know how to convert the result to a QuerySet properly, as best I can tell.
I think Roberto's answer of wrapping the generic view is the only one that will help.
The django docs should be amended to point out the limitations of the queryset used by generic views (currently the docs have a special note to tell you everything will be okay!)