Access "upload_to" of a Model's FileFIeld in Django? - python

I have a Model with a FileField like that:
class Video(MediaFile):
""" Model to store Videos """
file = FileField(upload_to="videos/")
[...]
I'm populating the DB using a cron script.
Is it possible to somehow access the "upload_to" value of the model?
I could use a constant, but that seems messy. Is there any way to access it directly?

You can access this with:
Video.file.field.upload_to # 'videos/'
or through the _meta object:
Video._meta.get_field('file').upload_to # 'videos/'
The upload_to=… parameter [Django-doc] can however also be given a function that takes two parameters, and thus in that case it will not return a string, but a reference to that function.

Related

How does Django loaddata know which fields make the natural key?

I am using Django's dumpdata to save data and loaddata to reload it. I am also using natural keys. My model looks similar to this:
class LinkManager(models.Manager):
def get_by_natural_key(self, url):
return self.get(url=url)
class Link(models.Model):
objects = LinkManager()
title = models.CharField(max_length=200)
url = models.URLField()
def natural_key(self):
return (self.url, )
If I export and reimport the data, Django recognizes that the objects already exist and doesn't create duplicates. If I change the title, it correctly updates the objects. However, if I change the URL, it correctly treats it as a new object - although I forgot to mark url unique! How does it guess my intent?
How does django know that my url field is the natural key? There is no get_natural_fields function. Django could call natural_key on the class instead of an instance to get the fields, but that seems really brittle:
>>> [f.field_name for f in Link.natural_key(Link)]
['url']
The reason I want to know this is that I am writing my own special importer (to replace my use of loaddata), and I would like to take advantage of natural keys without hardcoding the natural key (or the "identifying" fields) for each model. Currently, I "identify" an object by it's unique fields - I do:
obj, created = Model.objects.update_or_create(**identifying, defaults=other)
but Django seems to be choosing it's "identifying" fields differently.
I think I've found it out. Django does not just call get_by_natural_key, it first calls natural_key. How does it do that, if it doesn't have an instance of the model?
It simply creates an instance, not backed by the database, from the constructor (d'oh!): Model(**data). See build_instance in django.core.serializers.base. Then it calls natural_key on the newly created object, and immediately get_by_natural_key to retrive the pk that belongs to the object, if present in the database. This way, Django does not need to know what fields the natural key depends on, it just needs to know how to get it from data. You can just call save() on the retrieved instance, if it is in the database it will have a pk and will update, if not it will create a new row.
Source of the build_instance function (Django 1.11.2):
def build_instance(Model, data, db):
"""
Build a model instance.
If the model instance doesn't have a primary key and the model supports
natural keys, try to retrieve it from the database.
"""
obj = Model(**data)
if (obj.pk is None and hasattr(Model, 'natural_key') and
hasattr(Model._default_manager, 'get_by_natural_key')):
natural_key = obj.natural_key()
try:
obj.pk = Model._default_manager.db_manager(db).get_by_natural_key(*natural_key).pk
except Model.DoesNotExist:
pass
return obj

django foreignkey - format output value in selectlist

A form generates a list of all available foreign key elements. They are displayed depending on the __str__ function defined in the model.
I don't know how to search for this, but need to change this without touching the model.
My model connects with the User model. This model shows the username, but i would like to call the _get_full_name function to get a better list.
class Trainer(models.Model):
user=models.OneToOneField(User)
Is it possible to define it inside the definition of the Foreignkey or inside the model which connects (in my example the Trainer model)?
This should work:
def user_new_unicode(self):
return self.get_full_name()
User.__unicode__ = user_new_unicode #or User.__str__ = user_new_unicode
Of course it should be placed in your class.

django save() method saving the manytomany field why do we need save_m2m()

I have refered this documentation page for save() method
https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#the-save-method
But in my view I have the following code
def saveEvent(request):
eventForm = EventForm(request.POST)
if eventForm.is_valid():
event=eventForm.save(commit=False)
requestor=None
if(event.is_hp_requestor):
#Save and get requestor
requestorHPPersonForm = PersonHiddenForm(request.POST, prefix = 'hp_requestor')
requestorHPEmployeeForm = HPEmployeeForm(request.POST, prefix = 'hp_requestor')
requestor=saveHPEmployeeHelper(requestorHPEmployeeForm, requestorHPPersonForm).person
else:
requestorHPPersonForm = PersonHiddenForm(request.POST, prefix = 'hp_requestor')
requestor=get_object_or_404(Person, pk=requestorHPPersonForm.data[requestorHPPersonForm.prefix+'-'+'email'])
if (requestor is not None) and eventForm.is_valid():
event.requestor_new=requestor
event.save()
if request.POST['opportunities']:
for str_sfid in request.POST['opportunities'].split(','):
sfid = int(str_sfid)
opportunity_object, dummy = Opportunity.objects.get_or_create(sfdc_id=sfid)
event.opportunities.add(opportunity_object)
event.save()
return HttpResponseRedirect(reverse('dashboard'))
else:
errors = eventForm.errors
return HttpResponse(json.dumps(errors), status=500, mimetype='application/json')
In my view I do not invoke the save_m2m() method, but still it save many2many field data.
How is it works, if this is working then why we need the save_m2m() method?
The docs you linked to explain this:
Calling save_m2m() is only required if you use save(commit=False). When you use a simple save() on a form, all data – including many-to-many data – is saved without the need for any additional method calls.
Also, it looks like event is itself a model instance rather than a form. save_m2m is required for forms, not model instances.
To paraphrase the explanation in the docs: a form's save method, if called with commit=True (the default) does two things - it creates a new model instance using the form's cleaned data, and it writes that model instance to the database. Then, if there are any many-to-many relationships, it writes those to the database as well. It does that after writing the instance because you can't write a many-to-many relationship until the instance has a primary key, which is auto-generated when you write it to the database.
If you call the form's save method with commit=False, it creates the new model instance but it does not write it to the database. Thus, it has no primary key yet and the many-to-many information can't be saved either. After you save the model instance and therefore generate a primary key for it, the many-to-many information is still stored only in the form object. So you need to notify the form object that it's now OK to save the many-to-many information, by calling save_m2m.
edit Since you've added more of your code I can see more clearly what you're asking. The above code will not save many-to-many relationships that are set in your EventForm instance. Is that what your loop to set opportunities is doing?

String Dictionary Representation of a Model/Object instance in Python/Django?

I feel that this is a very simple question, but I'm new to Python, and I'm learning Django at the same time.
My objective is to create a string dictionary representation i.e. it's dictionary formatted but a string, of a Model's instance in Django. How could I do that? Is there a built-in function that I can call straight from the object's instance, or do I have to define one?
UPDATE:
I would like to call this functionality within the model definition itself i.e. I'm implementing a class method or function which needs this functionality. I'm thinking of a functionality which behaves like python's built-in function locals() but should only return the model's attributes.
I also would like to add that I'll be calling this functionality on a model's instance which has not been saved yet to the database. So in essence, I'll be working on a model's instance representing a record which is not yet in the database. So anything function using a Manager or QuerySet I guess is not why I'm looking for.
Example:
class Person(models.Model):
name = ...
age = ...
def func_doing_something(self):
#get the string dictionary representation of this model's instance
#do something to it
#return something
Thanks everyone!
Use p = Person(name='john', age=10).values()
See here: https://docs.djangoproject.com/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.values
To get it to a string use:
s = str(p[0])
You can serialize your objects to json format, e.g. with django build-in serializers
This allows you deserialize quite easily.
I found from this SO post the solution I was looking for...
some Django object obj
[(field.name, getattr(obj,field.name)) for field in obj._meta.fields]
and just call dict() on the result.

django: create object from constructor or model form

After obtaining data from a model form based on a Model, say
form_data = MyModelForm(request.POST)
Then I can either create an instance of Model by
instance = Model(**form_data.cleaned_data)
Or by
instance = form_data.save()
I wonder which one is the preferred way in the django world
There is a significant difference between the two.
instance = Model(**form_data.cleaned_data) doesn't save the object in the database. It only creates a local instance.
instance = form_data.save() adds the object to the database (it performs a commit, if so supported), and it also has the side effect of triggering validation.
If you want to do custom post-processing of the object before saving it, you pass commit=False to the save() method.
instance = form_data.save(commit=False)
# do some stuff with instance
instance.save()

Categories

Resources