I am trying to setup an user-uploaded class through the backend as Django admin. I am trying to make it so the path of the ImageField is based on the user-inputted DateField information; this is what I have.
from django.db import models
from datetime import date
class Article(models.Model):
def img_date(self):
return str(self.date.year) + str(self.date.month) + str(self.date.day)
#main_title = models.
title = models.TextField(max_length=200)
date = models.DateField()
content = models.TextField()
link = models.CharField(max_length=200)
image = models.ImageField(upload_to=img_date)
However, when I submit the object, I get an error saying "img_date() takes 1 positional argument but 2 were given". I need some help figuring out how to set a manual path like I explained earlier.
Thanks,
Have a look at the FileField docs (ImageField inherits from FileField).
In particular, note that the upload_to callable must accept two arguments, the model instance, and the original file name. So your code could look something like this (I removed the date import because it was unused):
from django.db import models
def img_date(instance, filename):
return str(instance.date.year) + str(instance.date.month) + str(instance.date.day)
class Article(models.Model):
title = models.TextField(max_length=200)
date = models.DateField()
content = models.TextField()
link = models.CharField(max_length=200)
image = models.ImageField(upload_to=img_date)
I've used your example code but you'll probably want to modify it so that two articles with the same date don't use the same image path.
Related
I'm trying to generate a unique filename for the uploaded file using the Django forms. I've tried uuid_upload_path app but that app doesn't work with the form. Below is my code
Forms.py
class HelpGuideForm(forms.ModelForm):
title = forms.CharField(max_length = 50)
image = forms.ImageField(required = False)
class Meta:
model = Helpguide
fields = ['title', 'image']
Models.py
from uuid_upload_path import upload_to
class HelpguideImage(models.Model):
image = models.ImageField(upload_to = upload_to, blank=True, null=True)
I want a unique name for all uploaded files. something like sd564sadasd61.jpg. I'm using Django 2.2
In your Model you can set the upload_to of the imagefield to a function and then generate the uuid.
A very simple (untested) example:
import uuid
Class MyModel(models.Model):
def get_path(instance, filename):
extension = filename.split('.')[-1]
uuid = uuid.uuid1().hex
return f'path/to/file/{uuid}.{extension}'
image = ImageField(upload_to=get_path)
What I understand of your problem, you can set initial for FORM class when initialising it. like:
help_guide_form = HelpGuideForm(initial={'headline': uuid.uuid4().hex}, instance= Helpguide)
from django docs. Also see the initial reference.
How i can get relative urls in my field after serialize? now i get abolute.
My model:
class Article(models.Model):
title = models.CharField(max_length=120)
image = models.ImageField()
text = models.TextField()
link = models.URLField()
And serializer:
class ArticleSerializer(ModelSerializer):
link = URLField()
class Meta:
model = Article
fields = '__all__'
Actually, without the http://... prefix, the url will not be a valid url. If you want to link somewhere inside your app, you can take the output of something like django's reverse and store it in a CharField (or just do some string manipulation by declaring a method, prior to inserting to the database or prior to serialization-deserialization).
I am very new to Django and I was wondering if I could request some help with an issue I am facing. I'm trying to build a set of models in Django that is structured as follows:
An app_user describes a user of the application I am building.
An app_job describes a job that the user wants to run on the app, with several associated inputs (upload1, upload2, upload3). A user can run many jobs; hence, I use the many-to-one (ForeignKey) relationship between job and user. When an app_job is created, I want its associated files to be uploaded to a directory determined by the associated user's username and num_jobs attribute, as shown.
When I run python manage.py makemigrations, I receive the following error: AttributeError: 'ForeignKey' object has no attribute 'user'. Which begs the question, how can I access the underlying app_user's information from the app_job class?
Thanks for the help.
# models.py
from django.db import models
from django.contrib.auth.models import User
from django.forms import ModelForm
class app_user(models.Model):
user = models.OneToOneField(User)
num_jobs = models.IntegerField(default = 0)
def __unicode__(self):
return self.user.get_username()
class app_job(models.Model):
app_user = models.ForeignKey(app_user)
upload1 = models.FileField(upload_to = app_user.user.get_username() + "/" + str(app_user.num_jobs) , blank = True, null = True)
upload2 = models.FileField(upload_to = app_user.user.get_username() + "/" + str(app_user.num_jobs))
upload3 = models.FileField(upload_to = app_user.user.get_username() + "/" + str(app_user.num_jobs) )
Okay there are a couple of issues here. But nothing a little education cannot fix.
models should be CamelCased this makes it easier to read and is generally good practise.
You do not need to prefix models with app_ its much cleaner and easier to read without this.
Anyway,
You app_job model ForeignKey should be to User not to the app_user model. By doing this you can still gain access to the app_user data.
You also need to modify the upload_to attributes also. Whilst uploads_to can be a string value it cannot be evaluated the way you are currently doing this. Check out the django filefield documentation for details (shameless plug, I recently re-wrote this part of the documentation).
Instead you need to do the following:
def user_directory_path(instance, filename):
# file will be uploaded to MEDIA_ROOT/user_<id>/<filename>
return 'user_{0}/{1}'.format(instance.user.id, filename)
class app_job(models.Model):
app_user = models.ForeignKey(User)
upload1 = models.FileField(upload_to=user_directory_path , blank = True, null = True)
upload2 = models.FileField(upload_to=user_directory_path
upload3 = models.FileField(upload_to=user_directory_path, blank=True, null=True)
What this is doing is upload_to calls the function user_directory_path to generate the file path.
By following the above you should have something like:
# models.py
from django.db import models
from django.contrib.auth.models import User
from django.forms import ModelForm
class UserProfile(models.Model):
"""
In settings.py you will want to add a link to AUTH_USER_PROFILE
See https://docs.djangoproject.com/en/1.8/topics/auth/customizing/#extending-the-existing-user-model
"""
user = models.OneToOneField(User)
num_jobs = models.IntegerField(default=0)
def __unicode__(self):
return self.user.get_username()
def upload_dir(instance, filename):
return instance.user.get_username() + "/" + str(instance.user.num_jobs)
class Job(models.Model):
user = models.ForeignKey(User)
upload1 = models.FileField(upload_to=upload_dir, blank = True, null = True)
upload2 = models.FileField(upload_to=upload_dir, blank=True, null=True)
upload3 = models.FileField(upload_to=upload_dir, blank=True, null=True)
Based on this answer to a similar question something like this should work:
# models.py
from django.db import models
from django.contrib.auth.models import User
class app_user(models.Model):
user = models.OneToOneField(User)
num_jobs = models.IntegerField(default = 0)
def __unicode__(self):
return self.user.get_username()
def content_file_name(instance, filename):
return '/'.join([instance.app_user.user.get_username(), str(instance.app_user.num_jobs), filename])
class app_job(models.Model):
app_user = models.ForeignKey(app_user)
upload1 = models.FileField(upload_to = content_file_name , blank = True, null = True)
upload2 = models.FileField(upload_to = content_file_name)
upload3 = models.FileField(upload_to = content_file_name)
As you have been told there are several issues. But its good to learn :).
First the class name should start with an upper letter and use "camelCase",
in your case, "AppUser" and "AppJob". Personally I would not use "App" as suffix instead I would just use "MyUser" and "Job".
The error you are getting "'ForeignKey' object has no attribute 'user" is because in your "app_job" model you have a ForeignKey to app_user, which is OK, that creates the relationship between the both models, but then in the FileField's you are using that "foreignkey" object which have the same name as your model "app_user" and that ForeignKey instance does not have an attribute called "user", Do you get this?
The information the guys gave you related to the "upload_to" is correct :).
you can get more info in the Django docs
Thanks
versions:
Python 3.4
Django 1.7
I created a gallery app with different galleries and their own images.
my models:
from django.db import models
class Gallery(models.Model):
title = models.CharField(max_length=200)
pub_date = models.DateTimeField('publish date')
def __str__(self):
return self.title
class Image(models.Model):
title = models.CharField(max_length=200)
gallery = models.ForeignKey(Gallery)
pub_date = models.DateTimeField('publish date')
file = models.ImageField(upload_to='img/gallery/'+str(Gallery.objects.get(pk=str(gallery)).id)+'/')
def __str__(self):
return self.title
you see my Gallery and Image model. While creating an Image in the Backend it should create a folder dynamicly in "img/gallery/gallery_id"
my problem is that Image.gallery is a ForeignKey here and I cant convert it into a int or string to use it. Is there a function to get the ID from my Gallery object with the ForeignKey from my Image object?
my solution
Gallery.objects.get(pk=str(gallery)).id
is not working.
btw: I thought foreignkey is always an int like id? isnt it?
The way Django works, a convenient method is automatically added that will give you the model instance that the foreign key represents. This is your gallery field. There is another field, called the same but with _id appended, that holds the actual foreign key value.
As petkostas said, you can pass a function that accepts the instance and filename arguments. You should use gallery_id instead of gallery.id to prevent an unnecessary call to the database.
def gallery_folder(instance, filename):
return '/'.join(['img/gallery', instance.gallery_id, filename])
class Image(models.Model):
...
file = models.ImageField(upload_to=gallery_folder)
upload to can be a callback:
https://docs.djangoproject.com/en/1.6/ref/models/fields/#django.db.models.FileField.upload_to
so:
def gallery_folder(instance, filename):
return '/'.join(['img/gallery', instance.gallery.id, filename])
class Image(models.Model):
title = models.CharField(max_length=200)
gallery = models.ForeignKey(Gallery, related_name='images')
pub_date = models.DateTimeField('publish date')
file = models.ImageField(upload_to=gallery_folder)
def __str__(self):
return self.title
Also add related_name, makes reverse queries easier, also you can opt for instance.gallery.title if you want.
i have following models
class tags(models.Model):
tag = models.CharField(max_length=15) # Tag name
tagDescription = models.TextField() # Tag Description
tagSlug = models.TextField() # Extra info can be added to the existing tag using this field
class stores(models.Model):
storeName = models.CharField(max_length=15) # Store Name
storeDescription = models.TextField() # Store Description
storeURL = models.URLField() # Store URL
storePopularityNumber = models.IntegerField(max_length=1) # Store Popularity Number
storeImage = models.ImageField(upload_to=storeImageDir) # Store Image
storeSlug = models.TextField() # This is the text you see in the URL
createdAt = models.DateTimeField() # Time at which store is created
updatedAt = models.DateTimeField() # Time at which store is updated
storeTags = models.ManyToManyField(tags)
class tagsAdmin(admin.ModelAdmin):
list_display = ('tag', 'tagDescription', 'tagSlug')
class storesAdmin(admin.ModelAdmin):
list_display = ('storeName','storeDescription','storeURL',
'storePopularityNumber','storeImage',
'storeSlug','createdAt','createdAt','storeTags'
)
admin.site.register(tags,tagsAdmin)
admin.site.register(stores,storesAdmin)
Whenever I am trying to run command : python manage.py syncdb
I got the error: django.core.exceptions.ImproperlyConfigured: 'storesAdmin.list_display[8]', 'storeTags' is a ManyToManyField which is not supported.
I don't understand what I am doing wrong here. I want to simply display all the models in the django admin site.
You can't reference a Many2ManyField like that, you have to use a method instead in the stores class that looks like this
def get_tags():
return self.storeTags.all()
and reference that in your list_display(...'get_tags')
This is done because the M2M field would result in lots of SQL queries that would slow the entire thing down so therefore the choice would have to come from the developer and not from the framework.
Please check:
ModelAdmin.list_display
"ManyToManyField fields aren’t supported, because that would entail executing a separate SQL statement for each row in the table. If you want to do this nonetheless, give your model a custom method, and add that method’s name to list_display. (See below for more on custom methods in list_display.)"
You can use a custom method to show values of ManyToManyField or simply remove storeTags from list_display