1

I have a model where the location of pdf directory I'm pointing to with my FilePathField is based on the "client" and "job_number" fields.

class CCEntry(models.Model):
    client = models.CharField(default="C_Comm", max_length=64)
    job_number = models.CharField(max_length=30, unique=False, blank=False, null=False)
    filename = models.CharField(max_length=64, unique=False, blank=True, null=True)
    pdf = models.FilePathField(path="site_media/jobs/%s %s", match=".*\.pdf$", recursive=True

    @property
    def pdf(self):
            return "site_media/jobs/%s %s" % (self.client, self.job_number)

    def __unicode__ (self):
            return u'%s %s' % (self.client, self.filename)

    class Admin: 
            pass

I've tried to pass the client and job_number data to the pdf field dynamically by using a @property method on the model class, but either my approach or my syntax is fualty because the entire pdf field disappears in the admin. Any pointers on what I'm doing wrong?

kjarsenal
  • 934
  • 1
  • 12
  • 35
  • Try just returning the path instead of using the property decorator, and also change the name of the function, just for clarity, to something like get_pdf_path. – Brandon Taylor Sep 16 '11 at 02:03
  • ok, but if I eliminate the decorator and change the function name, how do I capture the returned value in the FilePathFields "path" argument? – kjarsenal Sep 16 '11 at 02:13
  • you set the parameter to the result of the function: FilePathField(path=get_pdf_path(), match=...). Also you would need to define the function in the class before the field is defined. – Brandon Taylor Sep 16 '11 at 02:16
  • ok, I've done everything except the last step. How do I define the function in the class? – kjarsenal Sep 16 '11 at 02:21
  • Just the same as you have in your example code in your question. `def` is the Python keyword for function. It just needs to go before the fields that you've defined. – Brandon Taylor Sep 16 '11 at 02:44

4 Answers4

4

Based on your subsequent post on similar functionality in the FileField (see last link below) And my inability to get any of the above to work, I'm gonna hazard a guess that it's not yet possible for the FilePathField field type.

I know that passing a callable works for most fields' 'default' parameters... https://docs.djangoproject.com/en/dev/ref/models/fields/#default ... as it appears to work for the upload_to param of FieldField (eg https://stackoverflow.com/questions/10643889/dynamic-upload-field-arguments/ ) andImageField` (eg Django - passing extra arguments into upload_to callable function )

Anyone interested in extending FilePathField to include this feature?

Community
  • 1
  • 1
dschruth
  • 41
  • 3
  • There is an open ticket trying to address this issue https://code.djangoproject.com/ticket/29529 – Ullullu Mar 22 '19 at 14:18
  • 1
    The ticket previously referenced is now resolved in 3.0, with FilePathField being able to accept a callable for path. – Supra621 Apr 26 '20 at 22:38
3

Anyone interested in extending FilePathField to include this feature?

I'd love to see this extension!

Just for the record, this is the solution that worked for me (django 1.3):

    # models.py
    class Analysis(models.Model):
        run = models.ForeignKey(SampleRun)
        # Directory name depends on the foreign key 
        # (directory was created outside Django and gets filled by a script)
        bam_file = models.FilePathField(max_length=500, blank=True, null=True)  

    # admin.py
    class CustomAnalysisModelForm(forms.ModelForm):
        class Meta:
            model = Analysis
        def __init__(self, *args, **kwargs):
            super(CustomAnalysisModelForm, self).__init__(*args, **kwargs)
            # This is an update
            if self.instance.id:
                # set dynamic path
                mypath = settings.DATA_PATH + self.instance.run.sample.name
                self.fields['bam_file'] = forms.FilePathField(path=mypath, match=".*bam$", recursive=True)

    class AnalysisAdmin(admin.ModelAdmin):
        form = CustomAnalysisModelForm

Hope this helps somebody out there.

user1255933
  • 212
  • 2
  • 10
1

Added an implementation of this based on Django v1.9 FilePathField implementation:

from django.db.models import FilePathField


class DynamicFilePathField(FilePathField):

    def __init__(self, verbose_name=None, name=None, path='', match=None,
                 recursive=False, allow_files=True, allow_folders=False, **kwargs):
        self.path, self.match, self.recursive = path, match, recursive
        if callable(self.path):
            self.pathfunc, self.path = self.path, self.path()
        self.allow_files, self.allow_folders = allow_files, allow_folders
        kwargs['max_length'] = kwargs.get('max_length', 100)
        super(FilePathField, self).__init__(verbose_name, name, **kwargs)

    def deconstruct(self):
        name, path, args, kwargs = super(FilePathField, self).deconstruct()
        if hasattr(self, "pathfunc"):
            kwargs['path'] = self.pathfunc
        return name, path, args, kwargs

And example use:

import os
from django.db import models

def get_data_path():
    return os.path.abspath(os.path.join(os.path.dirname(__file__), 'data'))

class GenomeAssembly(models.Model):
    name = models.CharField(
        unique=True,
        max_length=32)
    chromosome_size_file = DynamicFilePathField(
        unique=True,
        max_length=128,
        path=get_data_path,
        recursive=False)
shapiromatron
  • 569
  • 6
  • 11
1

try to set the path value as callable function

def get_path(instance, filename):
    return "site_media/jobs/%s_%s/%s" % (instance.client, instance.job_number, filename)


class CCEntry(models.Model):
    ....
    pdf = models.FilePathField(path=get_path, match=".*\.pdf$", recursive=True)

but I'm not sure if this works, I didn't test it.

jargalan
  • 5,006
  • 5
  • 27
  • 36
  • throws a type error "coercing to Unicode: need string or buffer, function found" I'll keep working with it. – kjarsenal Sep 16 '11 at 02:34
  • i think you need to change the __unicode__ method as returning unicode value. Like: def __unicode__ (self): return unicode( u'%s %s' % (self.client, self.filename) ) – jargalan Sep 16 '11 at 02:44
  • pdf = models.FilePathField(path=get_path(), ...) – Brandon Taylor Sep 16 '11 at 02:44
  • I'll solidify the syntax but, after further investigation, you guys are definitely right. The model method is definitely the way to go. Gracias. – kjarsenal Sep 16 '11 at 03:20