Django query: field is substring - django

In Django I have my Site model that contains the field "base_url" that's the base url of the site. I've an object like this:
foo = Site(base_url="http://foo_base_url.com/")
foo.save()
I receive an url and I want to obtain the site object having this url. I would like to perform a query in django like this:
Site.objects.get(base_url__is_substring="http://foo_base_url.com/something_non_base_url")
How can I perform this query?
Thanx
edit:
It doesn't exist a pattern for base_url, my foo site can be:
foo = Site(base_url="http://foo.com/base/url/")

What you want is not provided by the Django ORM but you can use the where param described under the reference for QuerySet:
url = "http://foo_base_url.com/something_non_base_url"
Site.objects.extra(where=["%s LIKE CONCAT('%%',field,'%%')"], params=[url]).get()
Keep in mind that there is no standard method of concatenation across DMBS so if you migrate, you'll have to migrate this code.
The only portable method would be to filter it using Python:
sites = [site for site in Site.objects.all() if site.base_url in url]
although this is of course not ideal for huge data sets.

Related

how to create params in django url?

I have a django project where url is like this
url(r'^invoice/(?P<invoice_id>[A-Za-z0-9]+)/(?P<order_id>[A-Za-z0-9]+)$',GenerateInvoicePdf,name='invoice'),
which generates url localhost:8000/invoice/2341wq23fewfe1231/3242
but i want url to be like localhost:8000/invoice?invoice_id=2341wq23fewfe1231&order_id=3242
i tried documentation and used syntax like this re_path(r'^comments/(?:page-(?P<page_number>\d+)/)?$', comments), But did not get desired result.
how can i do so?
The parts which you are trying to write after ? is called url query string. You don't need to define them in the urls.py. You can just use:
re_path(r'^comments/$', comments),
And inside comments views, you can access the query string like this:
def comments(request):
invoice_id = request.GET.get('invoice_id')
order_id = request.GET.get('order_id')
# rest of the code

Is it possible to query Django objects by their FileField's url attribute

I have a Django class with a FileField. I know that you can get the FileField's url, or path, by calling filefield.path, or filefield.url . I tried to query for all of those objects by their FileField's url using
media = MediaLibraryFile.objects.filter(media_file__url='some_key')
but I get this error.
Unsupported lookup 'url' for FileField or join on the field not permitted.
I looked around the web, and found that you can only use lookup fields on foreignkey related objects, so my question is how can you query objects by file field url if thats the case ? It seems like this would be a very common query performed.
This is what I get when I do a simple query on media_file with icontains
In[27]: MediaLibraryFile.objects.all()[0].media_file.url
Out[27]: '/media/2017/6/13/444e35c2-0432-479a-805d-c46638ee3600.jpg'
In [28]: MediaLibraryFile.objects.filter(media_file__contains='/media/2017/6/13/444e35c2-0432-479a-805d-c46638ee3600.jpg')
Out[28]: <QuerySet []>
If you know exactly what you want to match you could do;
MediaLibraryFile.objects.filter(media_file__exact='some_key')
Or alternatively you could do a query like;
MediaLibraryFile.objects.filter(media_file__contains='some')
Just beware, the above is case sensitive. If you don't know the case, you can do filter(media_file__icontains='something')
The docs for field lookups are here; https://docs.djangoproject.com/en/2.0/topics/db/queries/#field-lookups

Error database query using ManyToManyField on model

I'm fairly new to django web development. And I got an error whereby I try to change a 'post' under admin url - so localhost:8080/admin. I'm able to create it successfully but when I try to click the post that I had just added. I'm getting this error:
Exception Type: DatabaseError Exception Value: This query is not
supported by the database.
And this is the code that I know is 'messing' with this query:
#Post is an abstract class
class BlogPost(Post):
...
translators = models.ManyToManyField(Staff, related_name='translators')
photographers = models.ManyToManyField(Staff, related_name='photographers')
authors = models.ManyToManyField(Staff, related_name='authors')
...
To explain what is going on with this blog post - it can have multiple 'owners'/people that contributed to this post and thus the decision using ManyToManyField. And vice-versa with the 'Staff' member - the type of 'member' can have multiple ownership on multiple posts (Let me know if this logic doesn't make any sense because it does to me).
I'm using mongodb for the database, django 1.5.11 and I have installed djangotoolbox. I've tried the following solutions with adding a relationship to BlogPost as shown below:
Class Staff(Member):
...
staff_posts = models.ManyToManyField(BlogPost, related_name="staff_posts")
...
But I'm getting an error on 'cannot import BlogPost'. I tried figuring out the reason of this error and I don't think that I have a circular dependance - after checking all of the files, there's no circular dependance.
MongoDB (or mongoengine, which I'm guessing you're using) doesn't support joins, so the typical way to model many-to-many relations in a relational database has to be implemented some other way.
One way is to use a ReferenceField inside a ListField. It might look like this (not tested):
class BlogPost(Post):
authors = models.ListField(models.ReferenceField(Staff))
...
Also see these answers:
https://stackoverflow.com/a/18747306/98057
https://stackoverflow.com/a/25568877/98057
Just to put it out there, I'm not real familiar with MongoDB.
However, I don't believe you need to define a ManyToManyField on your Staff class. You already have a ManyToMany defined in your BlogPost, having it defined in one class file is all that is required. (At least for MySQL).

Django: How to access the model id's within an AJAX script?

I was wondering what is the correct approach,
Do I create HiddenInput fields in my ModelForm and from the
View I pass in the primaryKey for the models I am about to edit into
the hiddenInput fields and then grab those hiddenInput fields from
the AJAX script to use it like this?
item.load(
"/bookmark/save/" + hidden_input_field_1,
null,
function () {
$("#save-form").submit(bookmark_save);
}
);
Or is there is some more clever way of doing it and I have no idea?
Thanks
It depends upon how you want to implement.
The basic idea is to edit 1. you need to get the existing instance, 2. Save provided information into this object.
For #1 you can do it multiple ways, like passing ID or any other primary key like attribute in url like http://myserver/edit_object/1 , Or pass ID as hidden input then you have to do it through templates.
For #2, I think you would already know this. Do something like
inst = MyModel.objects.get(id=input_id) # input_id taken as per #1
myform = MyForm(request.POST, instance=inst)
if myform.is_valid():
saved_inst = myform.save()
I just asked in the django IRC room and it says:
since js isn't processed by the django template engine, this is not
possible.
Hence the id or the object passed in from django view can't be accessed within AJAX script.

How can I get access to a Django Model field verbose name dynamically?

I'd like to have access to one my model field verbose_name.
I can get it by the field indice like this
model._meta._fields()[2].verbose_name
but I need to get it dynamically. Ideally it would be something like this
model._meta._fields()['location_x'].verbose_name
I've looked at a few things but I just can't find it.
For Django < 1.10:
model._meta.get_field_by_name('location_x')[0].verbose_name
model._meta.get_field('location_x').verbose_name
For Django 1.11 and 2.0:
MyModel._meta.get_field('my_field_name').verbose_name
More info in the Django doc
The selected answer gives a proxy object which might look as below.
<django.utils.functional.__proxy__ object at 0x{SomeMemoryLocation}>
If anyone is seeing the same, you can find the string for the verbose name in the title() member function of the proxy object.
model._meta.get_field_by_name(header)[0].verbose_name.title()
A better way to write this would be:
model._meta.get_field(header).verbose_name.title()
where header will be the name of the field you are interested in. i.e., 'location-x' in OPs context.
NOTE: Developers of Django also feel that using get_field is better and thus have depreciated get_field_by_name in Django 1.10. Thus I would suggest using get_field no matter what version of Django you use.
model._meta.get_field_by_name('location_x')[0].verbose_name
You can also use:
Model.location_x.field.verbose_name
Model being the class name. I tested this on my Animal model:
Animal.sale_price.field.verbose_name
Animal.sale_price returns a DeferredAttribute, which has several meta data, like the verbose_name
Note: I'm using Django 3.1.5
If you want to iterate on all the fields you need to get the field:
for f in BotUser._meta.get_fields():
if hasattr(f, 'verbose_name'):
print(f.verbose_name)
# select fields for bulk_update : exclude primary key and relational
fieldsfields_to_update = []
for field_to_update in Model._meta.get_fields():
if not field_to_update.many_to_many and not field_to_update.many_to_one and not field_to_update.one_to_many and not field_to_update.one_to_one and not field_to_update.primary_key and not field_to_update.is_relation :
fields_to_update = fields_to_update + [field_to_update.name]
Model.objects.bulk_update(models_to_update , fields_to_update)