Seite 1 von 1

[Django] Dateien + Bilder speichern

Verfasst: Montag 8. Oktober 2012, 15:35
von Lasse
Hallo,
ich möchte in einer mysql Datenbank Bilder und Dokumente speichern (Datentyp: longblob). Die Datenbank besteht bereits, um die Erstellung muss ich mir also keine Sorgen machen.

Hier meine Models:

Code: Alles auswählen

class Image(models.Model): #11
    """Diese Tabelle enthaelt die Bilder fuer Artikel. Fuer jeden
    Artikel koennen mehrere Bilder in gleichen und verschiedenen
    Groessen gespeichert werden.
    """
    class Meta:
        db_table = 'Image'
        verbose_name = 'Bild'
        verbose_name_plural = 'Bilder'
    ID = UUIDField(primary_key=True, version=4)
    ArticleVariant = models.ForeignKey(ArticleVariant)
    Description = models.CharField(max_length=50)
    Attachment = models.ImageField()
    OriginalFileName = models.CharField(max_length=50)
    AttachmentSource = models.ForeignKey(AttachmentSource)
    ImageType = models.ForeignKey(ImageType) #wird automatisch aus Dateiendung abgeleitet
    Width = models.IntegerField() #wird automatisch bestimmt
    Height = models.IntegerField() #wird automatisch bestimmt
    Thumbnail = models.ImageField() #wird automatisch generiert
    Year = models.IntegerField() #wird aus dem Dateinamen abgeleitet

    public = models.BooleanField()
    editor = models.ForeignKey(User)
    timestamp = models.DateTimeField()
    
    def __unicode__(self):
        return self.OriginalFileName

class Document(models.Model): #12
    """Diese Tabelle kann je Artikelvariante mehrere Dokumente aufnehmen."""
    class Meta:
        db_table = 'Document'
        verbose_name = 'Dokument'
        verbose_name_plural = 'Dokumente'
    ArticleVariant = models.ForeignKey(ArticleVariant)
    Description = models.TextField(editable=False) #Automatisch abgeleitet aus Dateiname
    Attachment = models.FileField()
    OriginalFileName = models.CharField(max_length=50, editable=False)
    AttachmentSource = models.ForeignKey(AttachmentSource)
    DocumentType = models.ForeignKey(DocumentType, editable=False) #wird automatisch aus der Dateiendung abgeleitet
    Year = models.IntegerField() #wird automatisch aus dem Dateinamen gebildet

    public = models.BooleanField()
    editor = models.ForeignKey(User)
    timestamp = models.DateTimeField()
    
    def __unicode__(self):
        return self.OriginalFileName
Man soll ja für blobs TextField im Model auswählen allerdings weiß ich nicht ob die für 100MB reichen außerdem will ich sie auch im admin anzeigen.

Gruß
Lasse

Re: [Django] Dateien + Bilder speichern

Verfasst: Montag 8. Oktober 2012, 18:10
von /me
Lasse hat geschrieben:ich möchte in einer mysql Datenbank Bilder und Dokumente speichern (Datentyp: longblob). Die Datenbank besteht bereits, um die Erstellung muss ich mir also keine Sorgen machen.
Doch, musst du. Deine Vorstellung davon wo das Bild gespeichert wird stimmt nämlich nicht. Ein ImageField in Django speichert die Daten nicht in der Datenbank.

Lies mal die Dokumentation zu FileField das die Basis für ImageField darstellt.

Re: [Django] Dateien + Bilder speichern

Verfasst: Montag 8. Oktober 2012, 18:45
von EyDu
Warum willst du die Bilder denn in einer MySQL-Datenbank ablegen? Der Ansatz hat merh Nach- als Vorteile. Dein System hat bereits eine für diese Aufgabe eine hochspezialisierte Komponente, die nennt sich Dateisystem.

Re: [Django] Dateien + Bilder speichern

Verfasst: Dienstag 9. Oktober 2012, 14:23
von Lasse
Das liegt an einer existierenden Datenbankstruktur, mit Daten, die unter keinen Umständen verändert werden darf. (Vorgabe vom Auftraggeber)

@/me das das Image oder Document Field die Sachen im Dateisystem speichert ist mir klar. Ich meine, das Django die Tabellen nicht erstellen braucht.

Re: [Django] Dateien + Bilder speichern

Verfasst: Dienstag 9. Oktober 2012, 18:08
von noisefloor
Hallo,
allerdings weiß ich nicht ob die für 100MB reichen
Das wissen wir auch nicht. ;-) Wenn's eine bestehende Datenstruktur ist, dann kannst du doch in die DB schauen, wie groß das größte BLOB ist. Ansonsten hol' dir eine Vorgabe vom Auftraggeber. :-)

Gruß, noisefloor

Re: [Django] Dateien + Bilder speichern

Verfasst: Mittwoch 10. Oktober 2012, 17:13
von Lasse
Die Aufgabe ganz konkret:
-Dateien und Bilder über die Admin-Oberfläche uploaden. (Aber bitte komfortabel, also kein hex Editor *hrhr*)
-Dateien und Bilder in einer existierenden Datenbankstruktur abspeichern. Es ist eine mysql Datenbank und der Feldtyp ist longblob
-Es sollen Dateien bis mindestens um die 100MB speicherbar sein.

Re: [Django] Dateien + Bilder speichern

Verfasst: Mittwoch 10. Oktober 2012, 21:19
von apollo13
Eigenes Django ModelField implementieren und gut ist…

Re: [Django] Dateien + Bilder speichern

Verfasst: Mittwoch 24. Oktober 2012, 18:38
von Lasse
Danke an alle Anwortenden, das hat mir geholfen.

Ein eigenes ModelField habe ich jetzt (schon fast). Nur noch das abspeichern bereitet Probleme.
Hier die Funktion die für das Speichern zuständig ist:

Code: Alles auswählen

    def get_prep_value(self, value):
        return value.chunks().next()

    def get_db_prep_value(self, value, connection, prepared=False):
        if connection.settings_dict['ENGINE'] == 'django.db.backends.mysql':
            if not prepared:
                value = self.get_prep_value(value)
            return "X'" + binascii.hexlify(value).upper() + "'"
Funktioniert auch ohne Fehlermeldungen und es wird auch etwas in die Datenbank geschrieben, allerdings werden die hex buchstaben nicht in bytes umgewandelt.

Ich vermute dass Django Anführungszeichen um die Anweisung drumherum setzt. Stimmt das? Und wenn ja wie kann man dieses Verhalten ändern?

Re: [Django] Dateien + Bilder speichern

Verfasst: Mittwoch 24. Oktober 2012, 21:30
von apollo13
Siehe: https://docs.djangoproject.com/en/dev/h ... prep_value -- dabei vor allem: "This conversion should not include any database-specific conversions. If database-specific conversions are required, they should be made in the call to get_db_prep_value()."

Re: [Django] Dateien + Bilder speichern

Verfasst: Donnerstag 25. Oktober 2012, 08:33
von Lasse
@apollo13: Um Formsachen wollte ich mich eigendlich kümmern wenn es funktioniert. Trotzdem habe ich es jetzt so geändert, dass get_prep_value nur noch Datenbank unspezifische Aufgaben erfüllt. Villeicht kannst du mir ja jetzt eine Antwort auf meine Frage geben.

Re: [Django] Dateien + Bilder speichern

Verfasst: Donnerstag 25. Oktober 2012, 12:58
von apollo13
Ich habe zum Glück keine Ahnung von Mysql :) Aber wenn du Hilfe willst solltest du genauer werden: Wie schaut das komplette ModelField aus, was speicherst du, was ist dann in der DB, was ist der Query der ausgeführt wird (aus dem mysql query log) etc…

Re: [Django] Dateien + Bilder speichern

Verfasst: Donnerstag 25. Oktober 2012, 15:37
von Lasse
Eine Query die eigendlich eine Datei in das Blob Feld einfügen soll, allerdings fügt django zusätzliche Anführungszeichen vor und nach der Hex Anweisung ein -> Es wird exakt der hex code in die Datei geschrieben.

Code: Alles auswählen

		   37 Query	INSERT INTO `Document` (`ID`, `ArticleVariant`, `Description`, `Attachment`, `OriginalFileName`, `AttachmentSource`, `DocumentType`) VALUES ('fe00d0a5-4e2a-4f65-8b28-a7f407677e43', 'cb24cb9f-7db9-476a-853d-1cebea7341b1', '', 'X\'0F222228FFBBBB3737BB000073FBF827FF27FFFFFBB3B874000B300073BBFF728F27FFFF8BBB8F74470730003BBB8F82222788FFBBBB8F74B370F0001FF\'', '0.ico', '27528db8-63eb-47b4-98e1-859e69288ca9', '3e25a3ed-fc9b-4920-a856-9433ddb79f11')
Hier mal ein Beispiel wie so ein fehlerhaftes Blob dann aussieht wenn man es wieder aus der Datenbank holt:
X'0000010001002020040000000000E802000016000000280000002000000040000000010004000'
Es ist 1:1 das was ich darin abgelegt habe, der hex code von der Datei wurde nicht umgewandelt in binary.

Code: Alles auswählen

class DocumentField(Field):
    def __init__(self, *args, **kwargs):
        super(DocumentField, self).__init__(*args, **kwargs)
    
    def db_type(self, connection):
        #Muss fuer postgre Datenbank geaendert werden!
        return 'LONGBLOB'

    def formfield(self, **kwargs):
        defaults = {'form_class': forms.FileField}
        defaults.update(kwargs)
        return super(DocumentField, self).formfield(**defaults)

##    def get_prep_value(self, value):
##        return "X'" + binascii.hexlify(value.chunks().next()).upper() + "'"

    def get_prep_value(self, value):
        return value.chunks().next()

    def get_db_prep_value(self, value, connection, prepared=False):
        if connection.settings_dict['ENGINE'] == 'django.db.backends.mysql':
            if not prepared:
                value = self.get_prep_value(value)
            return "X'" + binascii.hexlify(value).upper() + "'"

Re: [Django] Dateien + Bilder speichern

Verfasst: Freitag 26. Oktober 2012, 13:14
von apollo13
Also einen formattierten String in get_db_prep_value zu returnen ist eher falsch, du musst das returnen was die MySQLdb API für ein Blob erwartet, was das ist steht sicherlich irgendwo in der MySQLdb Dokumentation.

EDIT:// Laut http://stackoverflow.com/questions/1294 ... ing-python sollte es reichen den Raw-String ohne hex encoding als zu speichern.