Django queryset - get created object from database and equal the values - django

I wrote a simple selenium test that fills all fields from submit form (adding news on site). There is one of them below (title field):
# type title
for t in range(2):
try:
title = driver.find_element_by_xpath("//*[#id='id_title']")
print "I found text!"
title.send_keys("SomeText")
except NoSuchElementException as e:
print "I didn't find it!"
else:
print "Retry"
It success and in /admin/news/ (Django) I am able to see my automatically filled new article.
Right now I'd like to check if the data send from this form equals to the data the is being stored on database.
Does anyone would explain how to use a proper queryset to retrieve these data and print the results ? I've created a new class and by a logic I think it's gonna be something like below:
class NewsModelTestCompare(TestCase):
def test_creating_news(self):
# getting object
n = News.objects.get(title="SomeText")
self.assertEqual(News.objects.get(pk=n.id), n)

To check if the data is already in database, you could first query on News model with the data submitted from the form and check if database returns any result, like:
matching_objects = News.objects.filter(title="SomeText")
# this means the query returned at least one result
self.assertNotEqual(matching_objects.count(), 0)

Related

Queryset in django admin action is always empty

I wrote an action that is supposed update a field in every record selected by the user according to this document.
The problem is that queryset is always empty and thus, no changes take place.
def SendCommandAction(self, request, queryset):
print(self._Command)
commandStatus = {
'Command':self._Command,
'Fetched':False
}
print(queryset) #output from console: <QuerySet []>
updated = queryset.update(Command_Status = commandStatus,)
self.message_user(request, ngettext(
'%d record was successfully updated.',
'%d records were successfully updated.',
updated,
) % updated, messages.SUCCESS)
After I select records and hit "Go" button this message appeares:
0 records were successfully updated.
I'm having a similar issue and found that this method options.response_action is responsable for handling the action and the queryset it gets.
In my case, I'm using mongodb, and that method response_action is overwriting my queryset (the method is filtering by objects pks, but for mongodb you need to provide ObjectId instances to the filter function and django admin use just strings).
if not select_across:
# Perform the action only on the selected objects
queryset = queryset.filter(pk__in=selected)
# `selected` here is a list of strings (and for mongodb should be bson.ObjectId)
# that is the reason the queryset is empty in my case
I solved this creating a custom queryset class for my model and overwrite the filter function carefully to convert list of strings to list of bson.ObjectIDs only if the filter includes pk on it.
I think you need to debug this method and figure out what is happening in your case.
Good luck!
Luis.-

Test case for Django ModelForm with ModelChoiceField

I'm trying to write a simple test case to test a Django form that permits the assignment of an Orange object to an Apple object.
forms.py
class AppleOrangeAssignmentForm(forms.ModelForm):
orange = forms.ModelChoiceField(required=True, \
queryset=Orange.objects.filter(apple=None))
class Meta:
model = Apple
fields = ('orange')
The queryset on orange is there to ensure that the values in the dropdown are only Oranges that aren't already assigned to other Apples. This code works correctly and consistently in the view that calls it.
In the test case below, I am create a brand new Orange to ensure that I have one that it is not assigned anywhere else.
test.py
def test_apple_orange_assignment(self):
apple = Apple.objects.get(pk=1)
self.assertEquals(apple.orange, None)
orange = Orange.objects.create(name='clementime')
form_data = { 'orange': orange }
form = AppleOrangeAssignmentForm(data=form_data, instance=apple)
self.assertTrue(form.is_valid()) # <=== Fails here
Weirdly, the form does not validate in the test case! form.errors says: {'orange': ['Select a valid choice. That choice is not one of the available choices.']}. When I dig in further, I can see that the orange I am trying to assign does appear in form.fields['orange'].queryset, though.
I have tried everything to try to get this to validate. I have tried changing the queryset in the form field to Orange.objects.all(). I have tried changing the creation of the orange variable in the test case to form.fields['orange'].queryset[0] to ensure I'm picking an orange that is in its choices. But nothing works.
As I said, this all works perfectly in the view. Any ideas what I'm doing wrong here in the test case? Thank you!
Firstly there's no need to put a \ after required=True \ because the statement will end with a bracket.
You need to specify the object id rather than the whole orange object when instantiating the form class.
def test_apple_orange_assignment(self):
# More code here
form_data = { 'orange': orange.id }
form = AppleOrangeAssignmentForm(data=form_data, instance=apple)
assert form.is_valid(), form.errors
That's it!
Tip: You can use assert False, form.as_p() to make the test fail and trace the form html, and there you'll find that it isn't looking for the object but the object_id.
From Django's official docs on the topic of Django's role in forms:
receiving and processing submitted forms and data from the client
The form is expecting data coming from the client not programmatically. In your test you attempt to pass an instance (orange) of a python class (Orange), but since django forms are built for accepting data from the client, it does not make sense to allow objects, but rather only values that can be inputted by a client e.g. integers, strings, floats, etc.
Because of that, Django converts ForeignKey fields to ModelChoiceField and expects the input to be the id of the instance not the instance itself, so when you pass an instance, the form attempts to validate with the passed instance as an id, and thus fails.
From the docs
class ModelChoiceField(**kwargs)
Default widget: Select
Empty value: None
Normalizes to: A model instance.
Validates that the given id exists in the queryset.
Error message keys: required, invalid_choice
Example solution:
form_data = {'orange': orange.id}

Django request.session does not resolve

I have a ManyToMany relation between 2 of my models in the same app. This looks like following:
class Event(models.Model):
eventID = models.CharField(deafult = random_eventID)
signal = models.ManyToManyField(Signal)
....
....
Now, in my Form (using ModelForm) my eventID field is already populated with the eventID every time i refresh the page (because it gets a new random_eventID every time i refresh the page).
This way when, in my forms i select to add a new signal (I want to be able to add signals when i create an event)...it goes to a different view. I save the event and when i return back to the Event page, the eventID is changed again. I want to have all the data which the user has already filled/selected in the form to be present when it returns back to the Event page after adding lots of different stuff.
Solutions i thought of :
1 - I cannot make changes to my model so as to include another column and save the Event before going to another page & later retrieve it back.
2 - Using sessions i save all the data already present in all the fields an later retrieve it back..( This way HTTP is no more stateless, but it serves my purpose.)
3 - Will Ajax help in doing any update (which i don't understand it will)
I tried it using session and came cross this silly error, which i am not able to resolve.
views.py
def create(request):
if request.POST:
form = EventForm(request.POST)
form .save()
del request.session['event_id']
return HttpResponseRedirect('/Event')
else:
event_session = request.session.get('event_id')
if event_session is not None:
form = EiEventForm(initial={'eventID' : event_session}
else:
form = EventForm()
request.session['event_id'] = form('eventID').value()
args = {}
args.update(csrf(request))
args['form'] = form
return render_to_response('event.html', args)
With the above, after debugging i do not get the current value in the eventID field..I tried some other ways as well but with no success.
The request.GET.get('eventID') returns None..How can i get the values from my field ?
Also, is there a better way to accomplish the desired result except sessions.
Any help would be great help!

django - checking to see if filter returns anything in the queryset

I'm a newb to Django. I need to check to see if a queryset returns any values at all, and if not, to skip to the next item in the loop. I tried try.. except ObjectDoesNotExist and that's not working. If a filter doesn't find anything, what does it return? How do I check for it?
Here's the existing code:
def assign_family_riders(leg):
remaining_leg_riders = list(leg.riders.all())
for car in CarAssignment.objects.filter(leg=leg):
driver_family = car.driver.family
try:
riders = leg.riders.all().filter(family=driver_family)
except ObjectDoesNotExist:
continue
for rider in riders:
car.riders.add(rider)
remaining_leg_riders.remove(rider)
return remaining_leg_riders
You don't need to specifically check. If the filter doesn't return any objects, an EmptyQuerySet will be returned and the forloop will never be entered.
riders = leg.riders.filter(family=driver_family)
for rider in riders:
...
If you really want to, you could simply do:
riders = leg.riders.filter(family=driver_family)
if riders:
for rider in riders:
...
The ObjectDoesNotExist exception is only raised when you are trying to retrieve a particular record using get():
try:
rider = leg.riders.get(...)
except Rider.DoesNotExist:
...
As Timmy said in his answer, your loop will not be entered if the queryset returns nothing. On the other hand, if you really want to know the number of records a filter will return, you can call its count() method: CarAssignment.objects.filter(leg=leg).count()
This performs a SELECT COUNT(*) for you in the background without retrieving any records.
See here for more information.
The most efficient way to do this is to use exists() on the queryset before iterating over it or doing anything else that might perform a more intensive interaction with your database.
An example from the docs;
The most efficient method of finding whether a model with a unique field (e.g. primary_key) is a member of a QuerySet is:
entry = Entry.objects.get(pk=123)
if some_queryset.filter(pk=entry.pk).exists():
print("Entry contained in queryset")
Which will be faster than the following which requires evaluating and iterating through the entire queryset:
if entry in some_queryset:
print("Entry contained in QuerySet")
I'm pretty sure queryset returns nothing. You can probably check it using ./manage.py shell then see what is in riders.

Django - storing queryset in request.session still queries the db - why?

def mysearch(request):
"""This view builds a Q object query based on which fields are filled."""
if 'submit' in request.POST:
# build Q object depending on fields submitted
q = Q()
if request.POST['first_field']:
q &= Q(firstfield__icontains = request.POST['first_field'])
...
if request.POST['sixth_field']:
q &= Q(sixthfield__icontains = request.POST['sixth_field'])
results_list = MyModel.objects.filter(q)
count = len(results_list)
# store results
request.session['results_list'] = results_list
request.session['count'] = count
# 'p' is an arbitrary marker to detonate pagination of a page other than 1
if 'p' in request.GET:
results_list = request.session['results_list']
count = request.session['count']
if count and count > 0:
...
# pagination code
...
else:
pass
return render_to_response('search_results.html',
locals(), context_instance=RequestContext(request))
All works well in my templates using the paginator. The problem is that Django debug toolbar tells me that I am hitting the database the same number of times on pages > 1 than I am on the first page. Why is this? In fact - why is it hitting the database at all? Shouldn't the whole results_list be being pulled from request.session? Any advice much appreciated.
You're saving a queryset object in the session. Querysets are like SQL statements, but they cache the results. You haven't run the query when you put it in the session, so what you're storing is essentially just the query. When it gets pulled out it's still just a query that hasn't run, so the queryset gets run again. To ensure that you're storing just the actual results, do this:
request.session['results_list'] = list(results_list)
and to save you another query when you find count you can...
request.session['count'] = len(request.session['results_list'])
Also keep in mind that session data is (by default) saved in the database, so you might not be doing yourself any favors by storing a python pickled representation of the full data. It might in fact be faster just to go to the original table and pull it out that way.