I am pretty new to Django and I am trying to get a query set from a filter function. This filter function is supposed to be able to take 1 to 5 arguments and I am not sure how to handle that.
I have not found anything here that might help me, so if you do know of some other question that might help please let me know.
views.py:
#api_view(('Get',))
def update(request, REQUEST):
if request.method == "Get":
requestlist = REQUEST.split('&')
for keys in requestlist:
if 'module' in keys:
module = keys[8:]
if 'value' in keys:
value = keys[6:]
if 'user' in keys:
user= keys[5:]
if 'time1' in keys:
time1 = keys[6:]
if 'time2' in keys:
time2 = keys[6:]
item = Post.objects.filter(name=Name, user=USER, ...)
The full request string will look like name=NAME&value=VALUE&user=USER&time1=FIRSTTIME&time2=SECONDTIME but it could also be any combination of the individual variables like name&time1.
Now I want to be able to do that with one filter method instead of creating like 2^5 for each different szenario.
The full request string will look like name=NAME&value=VALUE&user=USER&time1=FIRSTTIME&time2=SECONDTIME.
This is a query string [wiki], and Django automatically parses this to a dictionary-like QueryDict, you thus should not specify this yourself. You can work with:
if request.method == 'GET':
Post.objects.filter(**request.GET.dict())
I would however advise to only allow specific keys, and thus not all keys, since then the database is less secure: one can use the filtering mechanism to retrieve data.
It thus might be better to work with:
datas = {}
accept_keys = {'module', 'value', 'user', 'time1', 'time2'}
for key, value in request.GET.dict().items():
if key in accept_keys:
datas[key] = value
if request.method == 'GET':
Post.objects.filter(**datas)
In that case the item after the path is the query string, and the separator between the path and the query string is a question mark (?).
The path thus looks like:
urlpatterns = [
# …,
path('some/path/', views.update, name='update'),
# …
]
and you thus query the path with some.host.com/some/path?name=NAME&value=VALUE&user=USER&time1=FIRSTTIME&time2=SECONDTIME.
Related
I have to make 2 search bars. I don't know how to add multiple fiels...
match= Staff.objects.filter(id=srch1...) here how can I add name=srch1
over here after trying many ways I found it but the problem is all input here is string how to change it to int
def search(request):
# Catch the data and search in Staff model.
if request.method=='POST':
srch1 = request.POST['srch']
print(type(srch1))
if type(srch1)== int:
match= Staff.objects.filter(id=srch1)
if match :
return render(request,'search.html',{'sr': match})
else:
messages.error(request,'no results,found')
elif type(srch1)== str:
catch= Staff.objects.filter(name=srch1)
if catch:
return render(request,'search.html',{'sr': catch})
else:
messages.error(request,'no results,found')
else:
return HttpResponseRedirect("/search")
return render(request,"search.html")
You should be using a GET request with querysting parameters or (url parameters, which is a bit more complicated) for this, not a POST. Here's how I would do this:
def search(request, *args, **kwargs):
# Initial empty query dictionary for use with query later.
query = {}
# Getting 'name' and 'id' from querystring parameters (i.e. ?id=1&name=foo)
name = request.GET.get('name', None)
id = request.GET.get('id', None)
# Add 'id' to the query dictionary if it exists
if id is not None:
query['id'] = id
# Add name to the query dictionary if it exists
if name is not None:
query['name'] = name
# If the query dictionary has name or id, get the Staff entry from the database
if query.get('name', None) or query.get('id', None):
# Note that .filter() returns a QuerySet. You should probably use .get()
# since my guess is that you only want one Staff object (judging by your
# search parameters). Also note that since we are using **query we will be
# using BOTH 'name' AND 'id' to search for the Staff, as long as both exist in
# the query dictionary.
match = Staff.objects.get(**query)
# If there is a match, send it in the rendered response context dict
if match:
return render(request, 'search.html', {'sr': match})
# no match, send message notifying that a Staff entry was not found matching
# the desired criteria
return render(request, 'search.html', {message: 'Not Found'}
# There were no query parameters, so we are not searching for anything.
else:
return render(request, 'search.html')
You can see that the above code is much simpler, and more concise. This will help you or anyone else checking out your code in the future to better understand what you're trying to acheive.
P.S. I typically only use POST requests when I am creating an entry in the database. Maybe this is preference, but to my knowledge it is best practice to use a GET request for search.
I want to write universal View with Django, in this function i want to handle several situations: first when i have url like vkusers3/11122233/1/2/ and also i want it working when 2 or third arguments is missing in url, like: vkusers3/11122233/ or vkusers3/11122233/1/
I cannot find it tutorials how to do that (https://docs.djangoproject.com/en/1.6/topics/http/urls/ etc).
The problem that this became a nightmare when you have more than 5 combinations in url parameters, then you should write 5 different url configurations, 5 times in html template hardcode this pattern.
BUT wait, even more!, what about combinatorics: i want /user/group/sex/smoking/ but also i want /user/group/smoking/ i.e. all users from group who is smoking of both man and woman. So the number is huge.
def list_groupmembers_sex(request, group_id, sex=None, smoking=None):
success = False
if group_id and sex and smoking==None:
vkusers = Vkuser._get_collection().find({"member_of_group": int(group_id), 'sex': int(sex)})# 62740364 81099158
success = True
elif group_id and sex and smoking!=None:
vkusers = Vkuser._get_collection().find({"member_of_group": int(group_id), 'sex': int(sex), 'personal.smoking': int(smoking)})
success = True
else:
vkusers = Vkuser._get_collection().find({'personal.smoking': 1})
ctx = {'vkuser_list': vkusers, 'group_id': group_id, 'sex': sex, 'smoking':smoking, 'success': success}
return render_to_response('blog/vkuser_list.html', ctx, context_instance = RequestContext(request))
In my urls.py:
url(r'^vkusers3/(\d{1,8})/(\d{1})/(\d{1})/$', 'blog.views.list_groupmembers_sex', name='vkuser-list3'),
In my base.html:
<li class="menu-level-1">users</li>
Django 1.6.10, MongoDB 2.7.1, mongoengine
At this point, you should probably bite the bullet and just go for query parameters - vkusers3/?sex=1&smoking=2&group= 11122233. You can drop the parameters completely from the URL and the view definition, and just use request.GET['sex'] etc in the view body.
You don't need so hairy logic. Just populate the search critera with arguments passed to the view like this:
criteria = {}
if group_id:
criteria['member_of_group'] = int(group_id)
if sex:
criteria['sex'] = int(sex)
if smoking:
criteria['personal.smoking'] = int(smoking)
vkusers = Vkuser._get_collection().find(criteria)
And yes, consider to switch to the regular GET parameters like #daniel-roseman suggested. With urls like in your question you can't determine the /user/group/sex/ url from the /user/group/smoking/.
UPDATE: request.GET is a dict-like object so you can use the in expression:
if 'sex' in request.GET:
criteria['sex'] = int(request.GET['sex'])
I am trying to iterate over form results and I can't help but think that I am re-inventing the wheel here.
filterlist = []
if request.POST:
form = FilterForm(request.POST)
if form.is_valid():
for key, value in form.cleaned_data.iteritems():
filterlist.append(key)
filterlist.append(value)
This works, but seems very awkward and creates lots of other problems. For example the values come back with u' so I have to use value.encode("utf8") but then if a value is None it throws in error. So now I have to check if it is None, if not then encode. There has to be a better way.
EDIT: What I am trying to do.
I am trying to filter what is shown on a page. The problem I am running into is that if a value is empty (the user don't fill the box because they only want to filter against one object) then I get no results. For example a user wants to search for all books by the author name "Smith" but doesn't want to search against a genre.
results = Books.objects.filter(author=author, genre=genre)
The user would get no results because this is an AND search. But, if a user put in "Smith" for the author and "mystery" for the genre then it works exactly like I want it to, only giving results where both are true.
So, I am trying to eliminate the empty stuff by iterating over the form results. Like I said I am probably re-inventing the wheel here.
In Python 3 use:
for key, value in form.cleaned_data.items():
If the field names are the same in the model and the form, try this:
filter = {}
if request.method == 'POST':
form = FilterForm(request.POST)
if form.is_valid():
for key, value in form.cleaned_data.iteritems():
if value:
filter[key] = value
results = Books.objects.filter(**filter)
Python is one of the few languages having named parameters. You can assemble a dict with the non-empty form fields and pass it to the filter method using the kwargs unpacking operator **.
For example:
kwargs = {"author": "Freud"}
results = Books.objects.filter(**kwargs)
Is the same as:
results = Books.objects.filter(author="Freud")
I think the problem is that by default the Model form is not valid if a form field does not have a value entered by the user, if you don`t require the field every time from the user you need to set the required field to false in the ModelForm class in forms.py as shown in the code below. Remember that the field is set false only in the model form not in the model itself
class myForm(forms.ModelForm):
myfield_id = forms.CharField(required=False)
myfield_foo = forms.CharField(required=False)
myfield_bar = forms.CharField(required=False)
myfield_name = forms.CharField(required=False)
class Meta:
model = myModel
exclude = ('myfield_ex','myfield_file')
fields = ['myfield_id','myfield_foo','myfield_bar','myfield_name',]
After you have the form entered by the user what you need is use the Q object which can be used to create complex queries as described in the manula page here
https://docs.djangoproject.com/en/1.7/topics/db/queries/#complex-lookups-with-q
A simple example code would look like
if form.is_valid():
qgroup = []
for key,value in form.cleaned_data.iteritems():
if value:
q_name = Q(**{"%s"%format(filterKey[key]) : value})
qgroup.append(q_name)
q = None
# can use the reduce as shown here qgroup = reduce(operator.or_, (Q(**{"{0}".format(filterKey[key]): value}) for (key,value) in form.cleaned_data.iteritems()))
for key,value in form.cleaned_data.iteritems():
if value:
q_name = Q(**{"%s"%format(filterKey[key]) : value})
qgroup.append(q_name)
for x in qgroup:
q &= x ### Or use the OR operator or
if q:
resultL = myModel.objects.filter(q).select_related()
The filterKey can look something on the lines of
filterKey = {'myfield_id' : "myfield_id",
'myfield_foo' : "myfield_foo__icontains",
'myfield_bar' : "myfield_bar__relative_field__icontains",
}
I have a django form and on my view function I do this :
search_packages_form = SearchPackagesForm( data = request.POST )
I would like to overwrite a form field called price which is decleared as such :
price = forms.ChoiceField( choices = PRICE_CHOICES, required = False,widget = forms.RadioSelect )
I would like to overwrite the form field before calling search_packages_form.is_valid()
I thought of doing :
search_packages_form.data['price'] = NEW_PRICE
But it does not work. Any ideas ?
Probably not the Django way but based on https://stackoverflow.com/a/17304350/2730032 I'm guessing the easiest way to change your form value before validation is to do something like the following:
def search_packages_view(request):
if request.method == 'POST'
updated_request = request.POST.copy()
updated_request.update({'price': NEW_PRICE})
search_packages_form = SearchPackagesForm(updated_request)
if search_packages_form.is_valid():
# You're all good
This works but I'd be interested if anyone has another way that seems more in line with Django, or if there isn't: then an explanation about why.
one trick for what you want is to do it like this:
changed_data = dict(request.POST)
changed_data['price'] = NEW_PRICE
search_packages_form = SearchPackagesForm(data = changed_data)
My solution is build on an earlier proposal. It is a working solution, which can be used in several cases.
#Milad Khodabandehloo
had a tricky solution to solve the problem.
changed_data = dict(request.POST)
changed_data['price'] = NEW_PRICE
search_packages_form = SearchPackagesForm(data = changed_data)
as #The EasyLearn Academy commented: it does not allow you to access actual data submitted in form.
This is because the request.POST is immutable.
But there is a solution to the problem - just have to be more tricky.
This solution is only good if a reference to the object is enough for the certain cause. It leaves the object itself the same.
# write object to variable (data)
data = request.POST
# set to mutable
data._mutable = True
# modify the values in data
data[modified_field] = new_value
# set mutable flag back (optional)
data._mutable = False
Hope it's useful!
form.is_valid() runs through your form's (and model's in case of a ModelForm) clean method's, returning True or False
If you plan on changing form data you can do it within the general clean method or at field level, e.g.
class YourForm(DerivingClass):
# regular stuff
def clean_<ATTR>(self):
# here
return self.cleaned_data
def clean(self):
# or here
return super(YourForm, self).clean()
I have the following function,
def facebooktest(request):
fb_value = ast.literal_eval(request.body)
fb_foodies = Foodie.objects.filter(facebook_id__in = fb_value.values())
for fb_foodie in fb_foodies:
state = request.user.relationships.following().filter(username = fb_foodie.user.username).exists()
userData = {
'fbid': fb_foodie.facebook_id,
'followState': int(state),
}
Basically I am checking to see which of the user's facebook friends are on my django app. If they are, return the followState. The followState basically returns a 1 or a 0. 1 if the user is already following them on my Django app and 0 if they are not following their facebook friend on my Django app.
I would like to return back a json type dictionary to that user that looks like this:
[{fbid:222222222222, followState: 0}, {fbid:111111111111, followState: 1}, {fbid:435433434534, followState:1}]
EDIT
I have the dictionary structure but I just want to return it like the structure above.
def facebooktest(request):
fb_value = ast.literal_eval(request.body)
fb_foodies = Foodie.objects.filter(facebook_id__in = fb_value.values())
response = []
for fb_foodie in fb_foodies:
state = request.user.relationships.following().filter(username = fb_foodie.user.username).exists()
userData = {
'fbid': fb_foodie.facebook_id,
'followState': int(state),
}
response.append(userData)
return json.dumps(response)
There is a function in the django.forms.models package for that: model_to_dict
from django.forms.models import model_to_dict
model_to_dict(your_model, fields=[], exclude=[])
From the help:
model_to_dict(instance, fields=None, exclude=None)
Returns a dict containing the data in ``instance`` suitable for passing as
a Form's ``initial`` keyword argument.
``fields`` is an optional list of field names. If provided, only the named
fields will be included in the returned dict.
``exclude`` is an optional list of field names. If provided, the named
fields will be excluded from the returned dict, even if they are listed in
the ``fields`` argument.
I think you're looking for this:
return HttpResponse(simplejson.dumps(response_dict), mimetype='application/json')
where 'response_dict' would be your dictionary.