I am trying to create a form that uses ajax to create a new user. All the other fields work, besides the ImageField. I don't get a error when submitting, but the image will still not save.
Github Repo: https://github.com/VijaySGill/matching-app
urls.py
from django.contrib import admin
from django.urls import include, path
from django.conf import settings
from django.conf.urls.static import static
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
urlpatterns = [
path('matchingapp/', include('matchingapp.urls')),
path('admin/', admin.site.urls),
]
urlpatterns += staticfiles_urlpatterns()
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
models.py
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
gender = models.CharField(max_length=6, blank=False)
dateOfBirth = models.DateField(null=True, blank=False)
bio = models.TextField(max_length=500, blank=True)
profileImage = models.ImageField(upload_to="profileimage", blank=True, null=True)
hobby = models.ManyToManyField(Hobby, blank=False)
views.py
#csrf_exempt
def registerUser(request):
...
image = ImageUploadForm(request.POST, request.FILES, instance=newUser)
if image.is_valid():
userprofile = image.save(commit=False)
userprofile.user = request.user
userprofile.save()
...
return JsonResponse(data, safe=False)
register.html
$('form').on('submit',function(e){
e.preventDefault();
...
var fd = new FormData($("#profileImage").get(0));
fd.append("username", $("#username").val());
fd.append("email", $("#email").val());
fd.append("password", $("#password").val());
fd.append("firstName", $("#firstName").val());
fd.append("lastName", $("#lastName").val());
fd.append("gender", gender);
fd.append("dateOfBirth", dob);
fd.append("hobbies", JSON.stringify(selectedHobbies));
if($("#password").val() == $("#confirmPassword").val()){
$.ajax({
type:'POST',
url: '/matchingapp/registerUser/',
processData: false,
contentType: false,
data: fd,
...
});
forms.py
class ImageUploadForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('profileImage',)
I suggest using the following method:
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
gender = models.CharField(max_length=6, blank=False)
dateOfBirth = models.DateField(null=True, blank=False)
bio = models.TextField(max_length=500, blank=True)
profileImage = models.ImageField(upload_to="UploadTo('user_photo')", blank=True, null=True)
hobby = models.ManyToManyField(Hobby, blank=False)
Where UploadTo is a class for saving your photos under a directory called user_photo in your media folder.
from django.utils.deconstruct import deconstructible
from uuid import uuid4
#deconstructible
class UploadTo(object):
def __init__(self, path):
self.sub_path = path
def __call__(self, instance, filename):
ext = filename.split('.')[-1]
# get filename
if instance.pk:
filename = '{}.{}'.format(instance.pk, ext)
else:
# set filename as random string
filename = '{}.{}'.format(uuid4().hex, ext)
# return the whole path to the file
return os.path.join(self.sub_path, filename)
This class will set properly the path to be used so that your photo can be found, because the problem is in the path you are passing to upload_to.
Disclaimer: the code above is not mine, but worked well for me.
I would comment, but I can't. How does the post data look like and is the image actually in there?
You might wanna remove blank=True and null=True from the ImageField for testing purposes. Django should complain about the image not being there or something.
if image.is_valid()
might return false and therefore not save the image
Related
Urls.py:
urlpatterns = [
path("", views.index, name="blogHome"),
path("blogpost/<int:id>/", views.blogpost, name="blogHome")
]
Views.py:
django.shortcuts import render
from .models import Blogpost
# Create your views here.
def index(request):
return render(request, 'blog/index.html')
def blogpost(request, id):
post.Blogpost.objects.filter(post_id = id)[0]
print(post)
return render(request, 'blog/blogpost.html')
Models.py:
from django.db import models
class Blogpost(models.Model):
post_id = models.AutoField(primary_key=True)
title = models.CharField(max_length=50)
head0 = models.CharField(max_length=500, default="")
chead0 = models.CharField(max_length=10000, default="")
head1 = models.CharField(max_length=500, default="")
chead1 = models.CharField(max_length=10000, default="")
head2 = models.CharField(max_length=500, default="")
chead2 = models.CharField(max_length=10000, default="")
pub_date = models.DateField()
thumbnail = models.ImageField(upload_to='blog/images', default="")
def __str__(self):
return self.title
Error
Error in cmd
Not Found: /blog/blogpost
[21/Jun/2022 12:29:33] "GET /blog/blogpost HTTP/1.1" 404 2678
The current error means Django doesn't find anything with the route blog/blogpost, it is because you have also defined an id to be pass in route, so kindly try http....blog/blogpost/1/ any id you can give.
Also, id is generally used to get a single object, and you are doing filtering on it. I think you should use get_object_or_404 if you want to retrieve single object.
As #lvanStarostin stated in the above comment that URL patterns should also have unique names. You should change one of the names.
Note: Models are classes of python so they must be written in PascalCase, so you may change your model name to BlogPost from Blogpost.
I am trying to create 'project' pages that have their paths generated with the
{{ project.title }} values, rather than the current method I have which uses ints. I don't quite understand how I can do this, but feel I am close?
Models.py
from django.db import models
# Create your models here.
class Project(models.Model):
title = models.CharField(max_length=100)
description = models.TextField()
technology = models.CharField(max_length=20)
image = models.FilePathField(path='projects/static/img/')
live = models.URLField()
source = models.URLField()
def __str__(self):
return self.title
Urls.py
from django.urls import path
from . import views
urlpatterns = [
path("", views.project_index, name="projects"),
path("<int:pk>/", views.project_details, name="project_details"), # PK for Primary Key
]
Views.py
from django.shortcuts import render
from .models import Project
# Create your views here.
def project_index(request):
projects = Project.objects.all()
context = {'projects': projects}
return render(request, 'projects/project_index.html', context)
def project_details(request, pk):
project = Project.objects.get(pk=pk)
context = {'project': project}
return render(request, 'projects/project_details.html', context)
I figure path("<int:pk>/", will need to be a slug, but I just cannot figure out how to tie in the DB data.
Potentially context = {'project': project}?
Currently the url is http://127.0.0.1:8000/projects/1/ - I am looking for http://127.0.0.1:8000/projects/EXAMPLE/
Thanks
You have to add a SlugField to your models.py file:
Models.py
from django.db import models
from django.utils.text import slugify
# Create your models here.
class Project(models.Model):
title = models.CharField(max_length=100)
description = models.TextField()
technology = models.CharField(max_length=20)
image = models.FilePathField(path='projects/static/img/')
live = models.URLField()
source = models.URLField()
slug = models.SlugField(default="", blank=True, null=False, db_index=True)
def __str__(self):
return self.title
def save(self, *args, **kwargs):
self.slug = slugify(self.title)
super().save(*args, **kwargs)
Views.py
from django.shortcuts import render
from .models import Project
# Create your views here.
def project_index(request):
projects = Project.objects.all()
context = {'projects': projects}
return render(request, 'projects/project_index.html', context)
def project_details(request, slug):
project = Project.objects.get(slug=slug)
context = {'project': project}
return render(request, 'projects/project_details.html', context)
Urls.py
from django.urls import path
from . import views
urlpatterns = [
path("", views.project_index, name="projects"),
path("<slug:slug>/", views.project_details, name="project_details"),
]
Make sure to run makemigrations and then migrate.
urls.py
path("<title>/", views.project_details, name="project_details"),
views.py
def project_details(request, title: str):
project = Project.objects.filter(title=title).first()
if project is None:
titles = list(Project.objects.all().values_list('title', flat=True))
msg = f'Project(title=title) not found. Exist titles are: {titles}'
raise Exception(msg)
...
I am trying to add markdownx support to my model, which will enable preview editing from the admin panel. However, once i change my content field from models.FileField to MarkdownXFromField() django just deletes the content field when migrating and ignores it as if it wasn't part of the model at all.
I've followed these docs exactly but it's not working.
I have also ran collectstatic.
# models.py
from os.path import splitext
from uuid import uuid4
from django.db import models
from markdownx.fields import MarkdownxFormField
def hashImageFilename(instance, name):
ext = splitext(name)[1]
return "images/{}{}".format(uuid4(), ext)
class Article(models.Model):
title = models.CharField(("title"), max_length=100)
content = MarkdownxFormField()
description = models.TextField(("description"), default='')
uploadDate = models.DateTimeField(("uploadDate"), auto_now=True)
lastModified = models.DateTimeField(("uploadDate"), auto_now=True)
publicationDate = models.DateField("publicationDate")
image = models.ImageField("image", upload_to=hashImageFilename)
def __str__(self):
return self.title
# urls.py
from django.contrib import admin
from django.urls import path, include
from django.conf.urls.static import static
from django.conf.urls import url
from django.conf import settings
from markdownx import urls as markdownx
urlpatterns = [
path('admin/', admin.site.urls),
path('api-auth/', include('rest_framework.urls')),
path('api/articles/', include('articles.api.urls')),
url(r'^markdownx/', include('markdownx.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
# admin.py
from django.contrib import admin
# Register your models here.
from markdownx.admin import MarkdownxModelAdmin
from .models import Article
admin.site.register(Article, MarkdownxModelAdmin)
# settings.py
INSTALLED_APPS = [
#...
'markdownx'
]
You are confusing the MarkdownxFormField form field with the MarkdownxField model field. You should rewrite the model to:
# models.py
from os.path import splitext
from uuid import uuid4
from django.db import models
from markdownx.models import MarkdownxField
def hashImageFilename(instance, name):
ext = splitext(name)[1]
return "images/{}{}".format(uuid4(), ext)
class Article(models.Model):
title = models.CharField(("title"), max_length=100)
content = MarkdownxFormField()
description = models.TextField(("description"), default='')
uploadDate = models.DateTimeField(("uploadDate"), auto_now=True)
lastModified = models.DateTimeField(("uploadDate"), auto_now=True)
publicationDate = models.DateField("publicationDate")
image = models.ImageField("image", upload_to=hashImageFilename)
def __str__(self):
return self.title
The MarkdownxFormField is used for forms, it will thus render with a specific widget, etc. In order to store content in the database, you need a model field.
I am a beginner in django and i want to create a new web page which i can edit and add to a database model like the admin site page but this will be in the website to enable the user to control it and i can extend my base.html page in it, I search for it and i didn't find a simple solution like admin base site that enable me to control the models, i tried to send all objects of this model in the context but i cant add or edit it in the database model, just i can view it only.
can any one help me? thanks.
This is my models.py for this web page:
from django.db import models
class Email(models.Model):
type = models.CharField(max_length=200, null=True, blank=True)
subject = models.TextField()
from_email = models.CharField(max_length=200, null=True, blank=True)
to_email = models.CharField(max_length=200, null=True, blank=True)
reply_to_email = models.CharField(max_length=200, null=True, blank=True)
body_text = models.TextField()
body_html = models.TextField()
status= models.CharField(max_length=200, null=True, blank=True,default='waiting')
def __unicode__(self):
return self.to_email
class EmailTemplate(models.Model):
template_name=models.CharField(max_length=200)
subject = models.CharField(max_length=200)
from_email = models.CharField(max_length=200, null=True, blank=True)
reply_to_email = models.CharField(max_length=200, null=True, blank=True)
body_text = models.TextField()
body_html = models.TextField()
def __unicode__(self):
return self.template_name
my views.py
from django.http import HttpResponse
from django.shortcuts import render_to_response
from django.template import RequestContext
from survey.models import *
from user_management.models import Candidate
from django.contrib.auth.decorators import login_required
from django import forms
import settings
from emailtemplates import models
from email_sender.models import *
from report.pdf import DrawarmPDF,send_pdf_in_email
from decorators import superuser_required
#login_required
#superuser_required()
def home(request):
query_results = EmailTemplate.objects.all()
return render_to_response('emailtemplates/emailtemplates.html',
{"query_results":query_results},
context_instance=RequestContext(request))
you need add action for POST method:
def home(request):
if request.method == 'POST':
# ^^^^^^
# do save action code
query_results = EmailTemplate.objects.all()
return render_to_response('emailtemplates/emailtemplates.html',
{"query_results":query_results},
context_instance=RequestContext(request))
And you may use forms for save action, more details here: forms view
And it be good to read about form class view class-based-views
For some reason, the classes archive and album show all of their fields in the django admin panel, but image isn't showing an album field when I go to add an image to the image panel. If I open a shell, it shows that album is a subset of image, it just isn't showing up in the image's admin interface (but it does through the CLI). Why?
class archive(models.Model):
name = models.CharField(max_length = 30)
archivedata = models.TextField(blank=True, help_text="Documentation for album/image.archivedata methodology is put here")
def __unicode__(self):
return self.name
class tag(models.Model):
archive = models.ForeignKey(archive)
tag = models.CharField(max_length=60)
def __unicode__(self):
return self.tag
class album(models.Model):
archive = models.ForeignKey(archive)
title = models.CharField(max_length=60)
tags = models.ManyToManyField(tag, blank=True, help_text="Searchable Keywords")
archivedata = models.TextField(blank=True, null=True, help_text="Data specific to particular archiving methods or processes can be stored here")
def __unicode__(self):
return self.title
class image(models.Model):
album = models.ForeignKey(album)
archive = models.ForeignKey(archive)
imagefile = models.ImageField(upload_to='ns/') #image.width/height
title = models.CharField(max_length=60, blank=True, help_text="Descriptive image title")
tags = models.ManyToManyField(tag, blank=True, help_text="Searchable Keywords")
Update: Including my admin.py per request:
from django.db.models import get_models, get_app
from django.contrib import admin
from django.contrib.admin.sites import AlreadyRegistered
def autoregister(*app_list):
for app_name in app_list:
app_models = get_app(app_name)
for model in get_models(app_models):
try:
admin.site.register(model)
except AlreadyRegistered:
pass
autoregister('appname')
Your admin.py file should typically look like this.
from django.contrib import admin
admin.site.register(archive)
admin.site.register(album)
admin.site.register(image)
Based on your admin.py I would do this.
autoregister('archive', 'album', 'image')
That said a few pointers - Your admin.py is a bit overly complicated and not needed when 3 lines will suffice. Additionally you should be naming your models in uppercase (Archive, Album, Image)
I do not see any problem do you have some extra code in admin? Some code that overrides the album field ?