I have a function:
def save_to_models(all_item_tags):
from article.models import Articles
for item in all_item_tags:
newobj = Articles()
try:
newobj.pub_date =item.contents[9].contents[0]
except:
continue
try:
newobj.title =item.contents[1].contents[0]
except:
continue
try:
newobj.description =item.contents[5].contents[0]
except:
continue
try:
newobj.image =get_the_picture(item.contents[7])
except:
continue
newobj.save()
each model has unique=True so I'm using try, except to skip over the error I get when its trying to input a data that's already in the database. How can I condense this code? I feel like its a lot of unnecessary lines of code.
Django is smart: like stated in one of the comments, it's only gonna raise an error when the save() method is called. Until then, Article is a normal Python object. What you should would look more like this :
from psycopg2 import IntegrityError # this is the actual error raised by psycopg2 (the postgres python driver)
from article.models import Articles
for item in all_item_tags:
try:
new_article = Articles(
pub_date=item.contents[9].contents[0],
title=item.contents[1].contents[0],
description=item.contents[5].contents[0],
image=get_the_picture(item.contents[7])
new_article.save() # this is where the actual save happens
except IntegrityError:
# Handle the exception here
Another (more advanced) option is to override the save() method and put your logic there.
That said, you could also use get_or_created to do that. It looks like this:
for item in all_item_tags:
# this methods returns a boolean True of False if the object is already in the DB.
# use your unique identifier here
article, created = Article.objects.get_or_create(unique_id=...)
# You can then do a classic if-else without handling any errors...
if created:
# Great! The object a
else:
# the object exist, do something with it or not...
However, there are a few things I would suggest. My feeling is that you are diving into Django without really knowing Python. Django is a big beast that makes a lot of things really convenient (almost magical) but it's still Python. If you dive too deep and something breaks, it will be very hard for you to know what's going on. I would suggest furthering your knowledge of Python (it's an amazing language so it's gonna be fun) and then go back to Django or maybe start with a smaller framework like Flask which does less magic! For now, here's a link to the official doc on error handling so you can learn a bit more about it. Also, Django has really good doc so I would first look there if a problem arises.
Cheers and happy coding!
Related
I have some questions about django exists() and DoesNotExist exception.
Example code:
id = 1
# first
if User.objects.get(pk=id).exists():
# my logic
pass
# second
try:
User.objects.get(pk=id)
# my logic
pass
except User.DoesNotExist:
return 0
I often use get() method. Which practice is better? Which code is better? The first or second?
if User.objects.get(pk=id).exists()
This won't work, so the question is pretty easy to answer: This way is inferior to the ways which do work :-)
I guess you actually didn't make a Minimal Complete Verifiable Example and so missed the error when you posted un-verified code.
So instead, I suppose you are asking about the difference between:
QuerySet.exists() when you have a QuerySet (e.g. from a filter operation).
For example:
if User.objects.filter(pk=id).exists():
# ... do the things that need that user to exist
Model.objects.get(…) and catching the Model.DoesNotExist exception type (or, if you want to be more general, the parent type ObjectDoesNotExist).
For example:
try:
user = User.objects.get(pk=id)
except User.DoesNotExist:
# ... handle the case of that user not existing
The difference is:
The QuerySet.exists method is on a queryset, meaning you ask it about a query (“are there any instances matching this query?”), and you're not yet attempting to retrieve any specific instance.
The DoesNotExist exception for a model is raised when you actually attempted to retrieve one instance, and it didn't exist.
Use whichever one correctly expresses your intention.
You can find more info in docs:
about exists(),but exists() works only for QuerySet
Returns True if the QuerySet contains any results, and False if not. This tries to perform the query in the simplest and fastest way possible, but it does execute nearly the same query as a normal QuerySet query.
exists() is useful for searches relating to both object membership in a QuerySet and to the existence of any objects in a QuerySet, particularly in the context of a large QuerySet.
But ObjectDoesNotExist works only with get().
Also you can try another approach:
user = User.objects.filter(id=2)
if user:
# put your logic
pass
Since we are in Django, we'll try to catch the error with Django functionality instead of the common way(which is using Exceptions with Python).
id = 1
def a_query(id):
qs = User.objects.filter(pk=id)
if qs.exists():
return qs.first()
return None
In here, the method exists() helps you catching the error(if there's any).
ref: https://docs.djangoproject.com/en/3.0/ref/models/querysets/#django.db.models.query.QuerySet.exists
in django model,
if you gonna use model.objects.get() if it wasn't exist it raise an error. in that case you can use DoesNotExist along with except:
try:
val = Model.objects.get(pk=val) # if nothing found it will raise an exception
exception:
you can trace an exception without mentioning anything on top.
(or)
exception ObjectDoesNotExist:
# it will come here if exception is DoesNotExist
For Django version 2.0.6, you can do the following, and it will work:
if Model.objects.filter(my_id=objectid).exists():
myobject = get_object_or_404(Model, my_id=objectid)
context = {'myobject': myobject}
return render(request, self.template_name, context)
You can get more info here: https://docs.djangoproject.com/en/2.1/ref/models/querysets/
It's my understanding that you're asking whether to use if statements or try catch on your code. I personally prefer to avoid using try catch, a think it's an ugly syntax, when I do want to raise an exception, I use a python keyword raise, to me, it makes the code cleaner.
Code example:
user = User.objects.filter(id=2)
if not user:
raise ObjectDoesNotExist
Suppose I have some django model and I'm updating an instance
def modify_thing(id, new_blah):
mything = MyModel.objects.get(pk=id)
mything.blah = new_blah
mything.save()
My question is, if it happened that it was already the case that mything.blah == new_blah, does django somehow know this and not bother to save this [non-]modification again? Or will it always go into the db (MySQL in my case) and update data?
If I want to avoid an unnecessary write, does it make any sense to do something like:
if mything.blah != new_blah:
mything.blah = new_blah
mything.save()
Given that the record would have to be read from db anyway in order to do the comparison in the first place? Is there any efficiency to be gained from this sort of construction - and if so, is there a less ugly way of doing that than with the if statement in python?
You can use Django Signals to ensure that code like that you just posted don´t write to the db. Take a look at pre_save, that's the signal you're looking for.
Given that django does not cache the values, a trip to DB is inevitable, you have to fetch it to compare the value. And definitely we have less ugly ways to do that. You could do it as
if mything.blah is new_blah:
#Do nothing
else:
mything.blah = new_blah
mything.blah.save()
I'm trying to get an object, if it existed ok if not then something else and so on. Is it correct to do the following? I've heared that exceptions are expensive and shuold be avoided, is that correct?
try:
user = User.objects.get(user=id)
except ObjectDoesNotExist:
try:
user = User.objects.get(email=id)
except ObjectDoesNotExist:
try:
# ...
finally:
# do the final thing
They are somewhat expensive, but certainly not too expensive to use when needed. I'd be more concerned about hammering the database with multiple queries You can avoid both problems by getting the results for all possible fields back in one query.
from django.contrib.auth.models import User
from django.db.models import Q
user = User.objects.filter(Q(user=id) | Q(email=id) | [...])[0]
This relies on django's Q-objects, which allow you to create conditions joined together in more complex ways than the usual AND joins that you usually get when building filters. If you aren't concerned about the possibility of getting multiple objects back, you can still use the get() method like you did in your example.
The cost of a try/except is explained here: cost-of-exception-handlers-in-python
I suggest to catch things that should not happen or only happen rarely (real exceptions) with a try/except and more common situations with conditions.
Especially in a case like a Model.objects.get() where the underlying sql returns an empty list that wouldn't raise an exception if called as a filter.
users = User.objects.filter(user=id)[:1]
user = users and users[0]
I have a User object and a UserInfo object which have a one to one relationship. I am just adding the UserInfo object so some users already have User objects but not UserInfo objects. I want to check to see if the User object has a UserInfo object associated with it yet and if not redirect them to a page where I can get some info. I am still new to python and have tried doing an if request.user.user_info: which throws an exception when it doesn't exist so I ended up doing this:
user = request.user
try:
user.user_info.university
except:
print 'redirect to info page'
which works fine, but I feel like exceptions should be for exceptions and not for if statement substitutes. Is there a better way to do this?
I'd say that handling this with exceptions is the pythonic approach. You can do something like this:
try:
# do your thing when user.user_info exists
except AttributeError: # Be explicit with catching exceptions.
# Redirect.
There's a programming concept called it's easier to ask for forgiveness than permission (EAFP) which is used extensively in Python. We assume that attributes, keys and so forth exist for a given object and catch exceptions when they do not.
Here are some references and SO questions about EAFP.
Python glossary
What is the EAFP principle in Python
EAFP and what is really exceptional
am trying to simulate django's settings file. Where I've built a model to host some of the settings where it can be changed by admin. The concepts works fine, but its acting strange when the value is changed the code is not picking up the new changes.
Here is my core_settings
class CoreSettings(object):
def __getattr__(self, item):
try:
return Configuration.objects.get(key=item).value
except Configuration.DoesNotExist :
return getattr(settings, item)
core_settings = CoreSettings()
am basically using the above as follows
SF_PUBLICATION_PAGINATION_PP = int(getattr(core_settings, 'SF_PUBLICATION_PAGINATION_PP'))
SF_PUBLICATION_PAGINATION_PP is getting the correct value from the Configuration model, but when I update the field value its not reflected. Only when I alter the file causing it to recompile where am getting the changes..
Any ideas?
update:
it seems like am seeing the changes only when the runserver is refreshed.
Yes, the value of your setting is not being refreshed, because its value is set when your settings.py is 'loaded', which happen when e.g you do 'runserver' in a dev enviroment.
So, you can deal with, doing something like this:
def get_live_setting(key):
try:
return Configuration.objects.get(key=key).value
except Configuration.DoesNotExist :
return getattr(settings, key)
# get SF_PUBLICATION_PAGINATION_PP's value
get_live_setting('SF_PUBLICATION_PAGINATION_PP')
with this you can solve your problem, but the correct way is using lazy evaluation, here some samples and here a funny post about 'lazy-python'.
What about using a package designed for this purpose?
Have a look at: django-livesettings
Even if you decide not to use it, you can always have a look at how it's done there!
Regarding your specific issue. how do you update the field value? Are you sure the value is retrieved from the database and not from your except clause?