I have a model and have added a Form FileField to take a file and save all their contents for a particular object. The content from the file should be read, parsed, and stored to synonym_name of the model.
model.py
molecule = models.ForeignKey('MoleculeDictionary', blank=False, null=False)
synonym_type = models.ForeignKey('SynonymType')
synonym_name = models.CharField(max_length=50, blank=True)
def __unicode__(self):
return u'%s' % (self.synonym_name)
And this is how I add Form field to the models(admin)page.
form.py
from django.forms import ModelForm
from django.forms import *
import pdb
import os
from django.core.files.uploadedfile import SimpleUploadedFile
from django.core.files import File
from idg.models.molecule_synonym import MoleculeSynonym
class MoleculeSynonymForm(ModelForm):
file_upload = FileField(required=False)
print "YES"
def save(self, commit=True):
print 'saving...'
file_upload = self.cleaned_data.get('file_upload', None)
file_upload.seek(0)
with open("../../Downloads/model_file_upload.txt", 'r') as f:
model_file = File(f)
names = model_file.read()
print(names)
form = MoleculeSynonymForm(names)
return super(MoleculeSynonymForm, self).save(commit=commit)
#
class Meta:
model = MoleculeSynonym
I have two questions:
How should I save the names to the Synonym_name for a chosen synonym_type and molecule. I use sqlite. My current code doesn't throw any errors other than:
The molecule synonym "" was added successfully.
How do I get the "full path for the file" without hardcoding them in the open statement.
Update: tried this :
I know this could be downright stupid :
try:
synonym_name = MoleculeSynonym.objects.create(synonym_name=names)
except:
synonym_name = None
print synonym_name
synform = MoleculeSynonymForm(instance=synonym_name)
print statement prints None.
I dont get what you are trying to this but if this helps have a look:
class MoleculeSynonymForm(ModelForm):
file_upload = FileField(required=False)
class Meta:
model = MoleculeSynonym
def clean_file_upload(self):
file_upload = self.cleanded_data['file_upload']
if file_upload:
model = YourModel()
model.file = file_upload
model.save()
else:
raise errors
Replace YourModel with your model and file with your model file field.
Related
class Setting(models.Model):
id=models.AutoField(primary_key=True, unique=True)
ldap_server = models.CharField(max_length=100, default='ldap://yourDomain.in')
ldap_server_username = models.CharField(max_length=100, null=True)
ldap_server_password = models.CharField(max_length=100, null=True)
def save(self, *args, **kwargs):
ldap_server=self.ldap_server
ldap_server_username = self.ldap_server_username
ldap_server_password = self.ldap_server_password
try:
l = ldap.initialize(ldap_server)
l.protocol_version = ldap.VERSION3
l.set_option(ldap.OPT_REFERRALS, 0)
l.simple_bind_s(ldap_server_username, ldap_server_password)
super(Setting, self).save(*args, **kwargs)
except:
messages.error(request, "You have logged in..!")
here I faced the error in
messages.error(request, "You have logged in..!")
I can't use
messages.error(request, "You have logged in..!")
Anybody know alternative way to show error
message.
Try this in admin.py:
#admin.py
from models import Setting
from django.contrib import admin
from django import forms
class SettingForm(forms.ModelForm):
class Meta:
model = Setting
def clean(self):
ldap_server = self.cleaned_data.get('ldap_server')
ldap_server_username = self.cleaned_data.get('ldap_server_username')
ldap_server_password = self.cleaned_data.get('ldap_server_password')
# your ldap logic here
if your_condition:
raise form.ValidationErro('You have logged in..!')
return self.cleaned_data
class SettingAdmin(admin.ModelAdmin):
form = SettingForm
list_display = ('ldap_server', 'ldap_server_username', 'ldap_server_password')
admin.site.register(Setting, SettingAdmin)
Remove save() method from your model.
You can move SettingForm in forms.py file and then import it in admin.py
I hope this will help
I have the following models:
from django.db import models
MNL = 50
MCL = 5
class Continent(models.Model):
"""
Fields
"""
name = models.CharField("name", max_length=MNL, unique=True)
code = models.CharField("code", max_length=MCL, default="", unique=True)
class Meta:
ordering = ['name']
"""
Methods
"""
def __str__(self):
return "%s, %s" % (self.name, self.code)
class Country(models.Model):
"""
Fields
"""
name = models.CharField("name", max_length=MNL, unique=True)
capital = models.CharField("capital", max_length=MNL)
code = models.CharField("code", max_length=MCL, default="", unique=True)
population = models.PositiveIntegerField("population")
area = models.PositiveIntegerField("area")
continent = models.ForeignKey(Continent, on_delete=models.CASCADE,
related_name="countries")
class Meta:
ordering = ['name']
"""
Methods
"""
def __str__(self):
return "%s, %s" % (self.name, self.code)
I need to be able to retrieve 2 things in JSON(P):
individual Country's capital, population and area fields in the form {"area":<area>,"population":<population>,"capital":<capital_name>} and
in the case of a Continent, all of the countries in that continent in the form {"code1":"name1", "code2":"name2",...}
I've tried implementing the following views to achieve this:
from django.http import HttpResponse, Http404, JsonResponse
from django.forms.models import model_to_dict
import json
from .models import Continent, Country
def continent_json(request, continent_code):
""" Write your answer in 7.2 here. """
try:
print("CONTINENT QuerySet: ", Continent.objects.filter(
code__exact=continent_code).values("countries"))
continent_data = json.dumps( list(Continent.objects.filter(
code__exact=continent_code).values("countries") ) )
print("CONTINENT JSON: ",continent_data)
except Continent.DoesNotExist:
raise Http404("Requested continent does not exist.")
# If JSONP
if "callback" in request.GET:
continent_data = "{}({})".format(
request.GET["callback"],
continent_data
)
return HttpResponse(continent_data)
# Normal JSON
return HttpResponse(continent_data, content_type="application/json")
def country_json(request, continent_code, country_code):
""" Write your answer in 7.2 here. """
try:
#print("COUNTRY_OBJECT: "Country.objects.filter(code__exact=country_code).values())
print("MODEL_LIST: ",list(Country.objects.filter(code__exact=country_code).values("capital","population","area")))
country_data = json.dumps( list(Country.objects.filter(
code__exact=country_code).values("code","name") ) )
print("COUNTRY DATA: ", country_data)
except Country.DoesNotExist:
raise Http404("Requested country does not exist.")
# If JSONP
if "callback" in request.GET:
country_data = "{}({})".format(
request.GET["callback"],
country_data
)
return HttpResponse(country_data)
# Normal JSON
return HttpResponse(country_data, content_type="application/json")
However, this is not producing the results I want: the data is not actually coming back as JSON(P), but as either a dict or a list. This is a lot of code to shift through, but I'm at my wits end here.
What am I doing wrong?
From what you explained on chat:
You need to change your views to something like this
country_data = json.dumps(dict(Country.objects.filter(
code__exact=country_code).values("code","name")[0])))
and for continent view:
continent = Continent.objects.get(code__exact=continent_code)
country_data = json.dumps(dict(continent.countries.values_list('code', 'name')))
I'm trying to set up my uploads so that if user joe uploads a file it goes to MEDIA_ROOT/joe as opposed to having everyone's files go to MEDIA_ROOT. The problem is I don't know how to define this in the model. Here is how it currently looks:
class Content(models.Model):
name = models.CharField(max_length=200)
user = models.ForeignKey(User)
file = models.FileField(upload_to='.')
So what I want is instead of '.' as the upload_to, have it be the user's name.
I understand that as of Django 1.0 you can define your own function to handle the upload_to but that function has no idea of who the user will be either so I'm a bit lost.
Thanks for the help!
You've probably read the documentation, so here's an easy example to make it make sense:
def content_file_name(instance, filename):
return '/'.join(['content', instance.user.username, filename])
class Content(models.Model):
name = models.CharField(max_length=200)
user = models.ForeignKey(User)
file = models.FileField(upload_to=content_file_name)
As you can see, you don't even need to use the filename given - you could override that in your upload_to callable too if you liked.
This really helped. For a bit more brevity's sake, decided to use lambda in my case:
file = models.FileField(
upload_to=lambda instance, filename: '/'.join(['mymodel', str(instance.pk), filename]),
)
A note on using the 'instance' object's pk value. According to the documentation:
In most cases, this object will not have been saved to the database yet, so if it uses the default AutoField, it might not yet have a value for its primary key field.
Therefore the validity of using pk depends on how your particular model is defined.
If you have problems with migrations you probably should be using #deconstructible decorator.
import datetime
import os
import unicodedata
from django.core.files.storage import default_storage
from django.utils.deconstruct import deconstructible
from django.utils.encoding import force_text, force_str
#deconstructible
class UploadToPath(object):
def __init__(self, upload_to):
self.upload_to = upload_to
def __call__(self, instance, filename):
return self.generate_filename(filename)
def get_directory_name(self):
return os.path.normpath(force_text(datetime.datetime.now().strftime(force_str(self.upload_to))))
def get_filename(self, filename):
filename = default_storage.get_valid_name(os.path.basename(filename))
filename = force_text(filename)
filename = unicodedata.normalize('NFKD', filename).encode('ascii', 'ignore').decode('ascii')
return os.path.normpath(filename)
def generate_filename(self, filename):
return os.path.join(self.get_directory_name(), self.get_filename(filename))
Usage:
class MyModel(models.Model):
file = models.FileField(upload_to=UploadToPath('files/%Y/%m/%d'), max_length=255)
I wanted to change the upload path in runtime, and none of the solutions were suitable for this need.
this is what I've done:
class Content(models.Model):
name = models.CharField(max_length=200)
user = models.ForeignKey(User)
file = models.FileField(upload_to=DynamicUploadPath.get_file_path)
class ContentSerializer(serializers.ModelSerializer):
class Meta:
model = Content
fields = '__all__'
class UploadDir(models.TextChoices):
PRODUCT = 'PRD', _('Product')
USER_PROFILE = 'UP', _('User Profile')
class DynamicUploadPath:
dir: UploadDir = None
#classmethod
def get_file_path(cls, instance, filename):
return str(cls.dir.name.lower() + '/' + filename)
def set_DynamicUploadPath(dir: UploadDir):
DynamicUploadPath.dir = dir
class UploadFile(APIView):
parser_classes = (MultiPartParser, FormParser)
def post(self, request):
# file save path: MEDIA_ROOT/product/filename
set_DynamicUploadPath(UploadDir.PRODUCT)
# file save path: MEDIA_ROOT/user_profile/filename
# set_DynamicUploadPath(UploadDir.USER_PROFILE)
serializer = ContentSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
If you have a user instance, let there be a quick setup to generate
<model-slug>/<username>-<first_name>-<last_name>/filename-random.png
eg:
/medias/content/ft0004-john-doe/filename-lkl9237.png
def upload_directory_name(instance, filename):
user = getattr(instance, 'user', None)
if user:
name = f"{user.username}-{user.get_full_name().replace(' ', '-')}"
else:
name=str(instance)
model_name = instance._meta.verbose_name.replace(' ', '-')
return str(os.path.pathsep).join([model_name, name, filename])
class Content(models.Model):
name = models.CharField(max_length=200)
user = models.ForeignKey(User)
file = models.FileField(upload_to=upload_directory_name)
[A Modified Version of #SmileyChris ]
Ive been trying to make this for two days now. I have created website that is capable of uploading one image file, but i would like to be able to upload more of them, that are connected to the same main model.
This is what i have for one picture upload:
forms.py:
from django import forms
from .models import Exam
class ExamForm(forms.ModelForm):
class Meta:
model = Exam
fields = ['exam_number', 'exam_file']
widgets = {
'exam_number': forms.NumberInput(
attrs={'id': 'exam_number', 'required': True,})
}
Models.py:
from django.db import models
from django.contrib.auth.models import User
from django.template.defaultfilters import slugify
from datetime import datetime
from django.core.validators import MaxValueValidator, MinValueValidator
class Exam(models.Model):
exam_number = models.PositiveIntegerField(validators=[MaxValueValidator(6),MinValueValidator(1)])
exam_path = models.CharField(max_length=255)
exam_file = models.ImageField() #i want to be able to upload more of these
exam_date = models.DateTimeField(auto_now_add=True)
exam_user = models.ForeignKey(User, null=True)
def __str__(self):
return self.exam_path
def __int__(self):
return self.exam_number
views.py:
def create_exam(request, letnik_id, classes_id, subject_id):
response_data = {}
if subject_id in SUBJECTS:
path = letnik_id + '/' + classes_id + '/' + subject_id
form = ExamForm(request.POST or None, request.FILES or None)
if form.is_valid():
exam = form.save(commit=False)
exam.exam_user = request.user
exam.exam_path = path
exam.exam_file = request.FILES['exam_file']
file_type = exam.exam_file.url.split('.')[-1]
file_type = file_type.lower()
if file_type not in IMAGE_FILE_TYPES:
context = {
'error_message': 'error',
}
return Http404("Napaka")
if Exam.objects.filter(exam_path=path, exam_number=exam.exam_number):
context = {
'form': form,
'error_message': 'error',
}
return render(request, 'tests.html', context)
exam.save()
return redirect('subject_id', letnik_id=letnik_id, classes_id=classes_id, subject_id=subject_id)
context = {
"form": form
}
raise Http404("error")
raise Http404("error")
ive heard that it would be best to make separated model for files, but i dont know how to make views that would connect to parent(exam) model.
Help is appreciated!
You need to create a separate model that would look something like this
class ExamFile(models.Model):
file = models.ImageField()
exam = models.ForeignKey(Exam, null=False)
Then in your view, instead of adding the exam_file to the exam, you will instead use it to create this new model. This will look something like this
from .models import Exam, ExamFile
...
exam_file = ExamFile.objects.create(
file = request.FILES['exam_file'],
exam=exam
)
For more information on fixing up the forms, you can check out the docs found here
I want to make changes to the data that is being saved in the admin page.
I've tried save_model. The only difficulty is that I'm using an inlined model as shown below:
# models.py
from django.db import models
class Material(models.Model):
type = models.CharField(max_length=20, primary_key=True)
def __unicode__(self):
return self.type
class Prop(models.Model):
color = models.CharField(max_length=20)
material = models.ForeignKey(Material)
def __unicode__(self):
return "%s_%s" % (self.color, str(self.material))
class Pen(models.Model):
label = models.CharField(max_length=20)
prop = models.ForeignKey(Prop)
def __unicode__(self):
return "%s: %s" % (self.label, str(self.prop))
#admin.py
from django.contrib import admin
from django.conf.urls import url
from .models import Material, Prop, Pen
class PropInlineAdmin(admin.TabularInline):
model = Prop
extra = 1
class MaterialAdmin(admin.ModelAdmin):
inlines = [PropInlineAdmin,]
def save_model(self, request, obj, form, change):
print obj.prop_set.values()
obj.prop_set.color = 'Red'
obj.save()
admin.site.register(Pen)
admin.site.register(Prop)
admin.site.register(Material, MaterialAdmin)
Let's say the user is creating a Material object with black color.
As an example, what I'm trying to do is to change that to be "Black" with first letter capitalized.
One problem is that prop_set does not have the color property until after it is saved.
Another problem is that the change above is not taking effect.
How can I manipulate the inlined values that are being saved?
I got it!
from django.contrib import admin
from django.conf.urls import url
from .models import Material, Prop, Pen
class PropInlineAdmin(admin.TabularInline):
model = Prop
extra = 1
class MaterialAdmin(admin.ModelAdmin):
inlines = [PropInlineAdmin,]
def save_formset(self, request, form, formset, change):
for f in formset.forms:
obj = f.instance
obj.color = obj.color.upper() # or whatever change you'd like
formset.save()
admin.site.register(Pen)
admin.site.register(Prop)
admin.site.register(Material, MaterialAdmin)