Django Python: Image Upload is not working not working - python

I am working on a Social Media Website, the base code is from an Open Source Project on GitHub.
On the base project you can only post text.
I was looking around the Internet and found a instruction to implement img upload.
But it doesn't work, because i get a lot of error codes.
Error Code:
AttributeError: module 'django.forms' has no attribute 'Post'
my Code:
forms.py
from django import forms
from django.forms import fields
from .models import Post, Comment
class Post(forms.Post):
class Meta:
model = Post
fields = ['name', 'Main_Img']
posts.py
""" Home page with all posts """
def first(request):
context = {
'posts':Post.objects.all()
}
return render(request, 'blog/first.html', context)
""" Posts of following user profiles """
#login_required
def posts_of_following_profiles(request):
profile = Profile.objects.get(user = request.user)
users = [user for user in profile.following.all()]
posts = []
qs = None
for u in users:
p = Profile.objects.get(user=u)
p_posts = p.user.post_set.all()
posts.append(p_posts)
my_posts = profile.profile_posts()
posts.append(my_posts)
if len(posts)>0:
qs = sorted(chain(*posts), reverse=True, key=lambda obj:obj.date_posted)
paginator = Paginator(qs, 50)
page = request.GET.get('page')
try:
posts_list = paginator.page(page)
except PageNotAnInteger:
posts_list = paginator.page(1)
except EmptyPage:
posts_list = paginator.page(paginator.num_pages)
return render(request,'blog/feeds.html',{'profile':profile,'posts':posts_list})
urls.py
urlpatterns = [...]
if settings.DEBUG:
urlpatterns += static (settings.MEDIA_URL,
document_root = settings.MEDIA_ROOT)
models.py
""" Post model """
class Post(models.Model):
title = models.CharField(max_length=150)
content = RichTextField(blank=True, null=True)
Main_Img = models.ImageField(upload_to='media/images/')
date_posted = models.DateTimeField(default=timezone.now)
date_updated = models.DateTimeField(auto_now=True)
author = models.ForeignKey(User, on_delete=models.CASCADE)
likes = models.ManyToManyField(User, related_name="blogpost", blank=True)
saves = models.ManyToManyField(User, related_name="blogsave", blank=True)
def total_likes(self):
return self.likes.count()
def total_saves(self):
return self.saves.count()
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post-detail', kwargs={"pk":self.pk})
post_form.py
<div class="m-auto w-100 container">
<div class="content-section">
<form method = "post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Upload</button>
</form>
</div>
</div>
This is the Website i got the code for the Img Upload from:
bit.ly/3IAKNQK
I have issues to implement them booth.
My problem is to sync the code from the website to my already existing code.

The problem is that there is no class named Post in django.forms module.
I am not sure what example you are refering to as https://de.acervolima.com/python-bilder-in-django-hochladen returns 404 not found, but I guess you replaced some class name in the example.
In Django, file upload can be implemented using FileField in django.forms
These Docs might help.
https://docs.djangoproject.com/en/4.0/topics/http/file-uploads/
https://docs.djangoproject.com/en/4.0/ref/forms/api/#binding-uploaded-files

Related

How can I configure these multiple slugs in my urls and views: Django

I've been trying to configure my urls and views for this password safe app
a site can have many accounts, and to edit an account I plan to use this url config:
home/[sitename]/[accountusername]/edit/. but its bringing errors. How do I go about this?
views.py:
class SiteDetailView(DetailView):
model = Site
template_name = "site_detail.html"
class SiteDeleteView(DeleteView):
model = Site
template_name = "site_delete.html"
success_url = reverse_lazy("home")
class SiteEditView(UpdateView):
model = Site
template_name = "site_edit.html"
fields = ("siteName",)
class AccountDeleteView(DeleteView):
model = Account
template_name = "account_delete.html"
# def get_success_url(self):
# return reverse_lazy("site_detail", kwargs={"slug": self.object.slug})
class AccountEditView(UpdateView):
model = Account
template_name = "account_edit.html"
fields = (
"username",
"password",
)
urls.py:
from django.urls import path
from .views import (
IndexView,
HomePageView,
SiteDetailView,
SiteDeleteView,
AccountDeleteView,
AccountEditView,
SiteEditView,
)
urlpatterns = [
path("home/<slug:slug>/edit/", SiteEditView.as_view(), name="site_edit"),
path(
"home/<slug:slug>/<slug:slug_field>/edit/",
AccountEditView.as_view(),
name="account_edit",
),
path(
"home/<slug:slug>/<slug:slug_field>/delete/",
AccountDeleteView.as_view(),
name="account_delete",
),
path("home/<slug:slug>/delete/", SiteDeleteView.as_view(), name="site_delete"),
path("home/<slug:slug>/", SiteDetailView.as_view(), name="site_detail"),
path("home", HomePageView.as_view(), name="home"),
path("", IndexView.as_view(), name="index"),
]
models.py:
from django.db import models
from django.urls import reverse
from django.conf import settings
from django.template.defaultfilters import slugify
class Site(models.Model):
siteName = models.CharField(max_length=200)
author = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
slug = models.SlugField(null=False, unique=True)
date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.siteName
def get_absolute_url(self):
return reverse("site_detail", kwargs={"slug": self.slug})
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.siteName)
return super().save(*args, **kwargs)
class Account(models.Model):
site_name = models.ForeignKey(Site, on_delete=models.CASCADE)
username = models.CharField(max_length=140)
password = models.CharField(max_length=50)
slug_field = models.SlugField(null=False, unique=True)
def __str__(self):
return self.username
def get_absolute_url(self):
return reverse("home")
def save(self, *args, **kwargs):
if not self.slug_field:
self.slug_field = slugify(self.username)
return super().save(*args, **kwargs)
my site_detail.html:
{% extends 'base.html' %}
{% block content %}
<h2>{{ object.siteName }}</h2>
<hr>
{% for username in object.account_set.all %}
<p>Username: {{ username.username }}</p>
<p>Password: {{ username.password }}</p>
<p><button type="button">Edit account</button>
<button type="button">Delete account</button></p>
<hr>
{% endfor %}
<p><button type="button">Delete site</button>
<button type="button">Edit site</button></p>
{% endblock content %}
The current error I am facing:
raise FieldError(
django.core.exceptions.FieldError: Cannot resolve keyword 'site' into field. Choices are: id, password, site_name, site_name_id, slug_field, username
This is how a detail view looks at url http://127.0.0.1:8000/home/redditcom/
this is how a detail view looks at url http://127.0.0.1:8000/home/redditcom/
For Django to clearly handle the slug, the field name should be named as "slug", so, for your Site model there will be no problem, but, for account model you named it "slug_field", then, you have 2 options:
Change the "slug_field" to just "slug".
Override the slug field in the Account Views so Django takes them as the slug field, like this:
slug_field = "slug_field"
slug_url_kwarg = "slug_field"
You use siteName in your Site model and site_name in your Account model. I'm not sure what code is generating the error since I don't see anything referencing just site in what you posted here, but if you look at the error, you can see from the other fields listed that it's referencing the Account model. So you need to replace site with site_name somewhere.
For me, when doing stuffs like this, you use use a unique slug. You can add a random unique number to the slug by generating it from uuid4, and using a while loop go make sure no slug repeats its self .
Just create a util.py file in your app and write the function to generate a random unique number the add it to your slug in the models

Using Django DeleteView and getting a 404 after delete confirmation

After clicking on "confirm" in my organism_delete.html form, I used to be redirected back to the list of organisms (organism_list.html template) as specified in the view. But now I get a 404 error instead.
Page not found (404) Request Method: GET Request
URL: http://localhost:8000/library/organisms/ABC1233/delete/post?csrfmiddlewaretoken=Rdk575IEp5bbvrriJ1szlYNjmq8V1DvuYzNWEWz07s78IJSal9foHdkvxwcimIEp
Using the URLconf defined in itslibrary.urls, Django tried these URL
patterns, in this order:
admin/
accounts/ [name='home']
library/ organisms/ [name='organism_list']
library/ organisms/new/ [name='organism_new']
library/ organisms/ [name='organism_detail']
library/ organisms//update/ [name='organism_update']
library/ organisms//delete/ [name='organism_delete']
^media/(?P.*)$ The current path,
library/organisms/ABC1233/delete/post, didn’t match any of these.
Two things that stand out to me is first that the error says it's a GET request, not a POST as the form specifies.
And second is why is it trying to get to .../delete/post...?
It might be important to know that I changed my model and added "Primary Key = True" to a unique CharField, and I've been modifying the rest of the app to match that. It may not be related because I can list the organisms and I can get to the delete page, I just can't submit it.
I don't know how to debug this, it seems to be hidden behind the Django magic, any guidance will be very appreciated.
Code below:
Models.py:
#Organism
class Organism(models.Model):
genbank = models.CharField(max_length = 10, primary_key=True, unique=True)
genus = models.CharField(max_length = 50)
species = models.CharField(max_length = 50)
strain = models.CharField(max_length = 50)
organism_sequence = models.TextField()
created_at = models.DateTimeField(auto_now_add = True)
fasta = models.FileField(upload_to='organism_fasta/', null=True, blank=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete = models.SET_NULL, null=True)
def __str__(self):
return self.genus[:10] + ', ' + self.species[:10] + ', ' + self.strain[:10]
def get_absolute_url(self):
return reverse('organism_detail', args=[str(self.genbank)])
#Motif
class Motif(models.Model):
organism = models.ForeignKey('Organism', on_delete = models.CASCADE, related_name= "motifs")
region_name = models.CharField(max_length = 15, choices = MOTIF_CHOICES)
motif_sequence = models.CharField(max_length = 600)
structure_image = models.ImageField(upload_to='structures/', blank=True, null=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete = models.SET_NULL, null=True)
created_at = models.DateTimeField(auto_now_add = True)
def __str__(self):
return self.region_name[:10]
app urls.py
urlpatterns = [
path('organisms/', views.OrganismListView.as_view(), name='organism_list'),
path('organisms/new/', views.OrganismCreateView.as_view(), name='organism_new'),
path('organisms/<pk>', views.OrganismDetailView.as_view(), name='organism_detail'),
path('organisms/<pk>/update/', views.OrganismUpdateView.as_view(), name='organism_update'),
path('organisms/<pk>/delete/', views.OrganismDeleteView.as_view(), name='organism_delete'),
]
Delete View in views.py:
#Delete
class OrganismDeleteView(LoginRequiredMixin, DeleteView):
model = Organism
success_url = '/library/organisms'
template_name = 'library/organism_delete.html'
login_url = "/login"
organism_delete.html template
{% extends "base.html" %}
{% block content %}
<form action="post">
{% csrf_token %}
<p>Are you sure you want to delete {{organism.genus}} {{organism.species}} {{organism.strain}}?</p>
<p>This cannot be undone!</p>
<input type="submit" class="btn btn-danger" value="confirm"/>
</form>
{% endblock content %}
The method="…" of the form is "POST", not the action="…":
<form method="post">
{% csrf_token %}
<p>Are you sure you want to delete {{organism.genus}} {{organism.species}} {{organism.strain}}?</p>
<p>This cannot be undone!</p>
<input type="submit" class="btn btn-danger" value="confirm"/>
</form>
It might be better to work with reverse_lazy(…) [Django-doc] to determine the path of the success_url:
from django.urls import reverse_lazy
class OrganismDeleteView(LoginRequiredMixin, DeleteView):
model = Organism
success_url = reverse_lazy('organism_list')
template_name = 'library/organism_delete.html'
login_url = '/login'
When you do <form action="post" ..., you are asking the form to "append post to the current URL, using a GET request, and go the endpoint with 'your data'".
More details here: https://www.w3schools.com/tags/att_form_action.asp
I am not sure how will you manage to make the page call again the same page (maybe omit action="...", but you should add (change) method="..."; from the implicit method="get", make it a method="post" instead.
Without being a django connoisseur myself, it would be nice if you could "easily" teach django to listen to the method="delete" instead of POST, as it will make your API a tad more semantic.

NOT NULL constraint failed: posts_comment.post_id django

I have the basics of a blogs app (I have been following Corey Schafer's tutorial, part 10, if that matters) and I am trying to post and display comments on the post that other users have wrote that only relate to that post. Similar to that of a comment section on Facebook or YouTube.
Currently I'm displaying all comments in the database on every post because I don't know how to filter the results to only show comments for the specific post and I also don't know how to post comments to a specific post, that's where I get the error.
My code is below:
Models.py
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
user = models.ForeignKey(User, on_delete=models.CASCADE)
date_posted = models.DateTimeField(default=timezone.now)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('core:post-detail', kwargs={'pk': self.pk})
class Comment(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
content = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.user.username
Views.py
class PostDetailView(DetailView):
model = Post
context_object_name = 'posts'
def get_context_data(self, **kwargs):
context = super(PostDetailView, self).get_context_data(**kwargs)
context['comment'] = Comment.objects.all()
return context
class CommentCreateView(LoginRequiredMixin, CreateView):
model = Comment
fields = ['content']
def form_valid(self, form):
form.instance.user = self.request.user
return super().form_valid(form)
urls.py (This is the urls.py file in my main app where I'm calling the blogs app views)
path('posts/<int:pk>/', PostDetailView.as_view(), name='post-detail'),
path('posts/<int:pk>/comment', CommentCreateView.as_view(), name='comment-create'),
I then have this form in a file called comment_form.html that I can connect to when I got to http://127.0.0.1:8000/posts/5/comment but when I click reply I get
IntegrityError at /posts/5/comment NOT NULL constraint failed: posts_comment.post_id
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4"> Reply to Post </legend>
{{ form|crispy}}
</fieldset>
<div class="form-group">.
<button type="submit" class="btn btn-success">Reply</button>
</div>
</form>
If someone could throw their eye over it and let me know if you can find anything that I could do to get it to work, I would greatly appreciate it. Let me know if you need more information/code.
Thanks
the problem is that you're creation form is missing a non nullable field, that's why django is complaining about the "NOT NULL CONSTRAINT"
so you have to add the post field to the form fields, or you can add it in the form_valid method:
def form_valid(self, form):
form.instance.post = Post.objects.get(pk=self.kwargs.get("pk"))
form.instance.user = self.request.user
return super().form_valid(form)
if you want to ignore the post field, you can put null=True in the Comment Model:
class Comment(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey(Post,null=True,blank=True,on_delete=models.CASCADE)
content = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)

Django Many-to-Many Accessing both Models

I'm looking to build a small 'Twitter style' site using Django to get to grips with things and have decided to try and allow multiple users edit each post (eventually based on permissions). Now what I'm struggling with is accessing each user's posts. Below is the code for my model, view and template which shows "There aint no post here" for all users. I'm looking to be able to show all posts that the user has and don't seem to be getting anywhere:
models.py
from django.db import models
class User(models.Model):
username = models.CharField(max_length = 200)
email = models.EmailField(max_length = 75)
password = models.CharField(max_length = 64)
created_date = models.DateTimeField('date created')
def __unicode__(self):
return self.username
class Meta:
ordering = ('created_date',)
class Post(models.Model):
users = models.ManyToManyField(User)
title = models.CharField(max_length = 300)
post = models.TextField()
posted_date = models.DateTimeField('date created')
votes = models.IntegerField()
def __unicode__(self):
return self.title
class Meta:
ordering = ('posted_date',)
views.py
from django.shortcuts import render, get_object_or_404
from django.http import HttpResponse
from users.models import User, Post
def index(request):
latest_user_list = User.objects.order_by('username')[:5]
context = {'latest_user_list': latest_user_list}
return render(request, 'users/index.html', context)
def detail(request, user_id):
user = get_object_or_404(User, pk=user_id)
post_list = Post.objects.filter(id == user.id)
return render(request, 'users/detail.html', {'user': user, 'post': post_list})
urls.py
from django.conf.urls import patterns, url
from users import views
urlpatterns = patterns('',
url(r'^$', views.index, name='index'),
url(r'^(?P<user_id>\d+)/$', views.detail, name='detail'),
)
(template) - detail.html
<h1>{{ user.username }}</h1>
{% if post_list %}
<ul>
{% for post in post_list%}
<li>{{ post.title }}</li>
{% endfor %}
</ul>
{% else %}
<p> There aint no posts here </p>
{% endif %}
The variable you're passing to the template is called post not post_list.
Change the name for the list object in your view.
def detail(request, user_id):
user = get_object_or_404(User, pk=user_id)
post_list = Post.objects.filter(id == user.id)
return render(request, 'users/detail.html', {'user': user, 'post_list': post_list})

FK not populating in django form

I have a small question to ask the community. I am wondering why my foreign key will not show up when I go to my edit form. When I go to edit the information, all my data is populated except for status (which is a foreignkey that points from the status table to project table), which is left with nothing selected. I use the same forms.py for both adding and editing information.
models.py
from django.db import models
from clients.models import Clients
from django.contrib.auth.models import User
from settings import STATUS_CHOICES
class Project(models.Model):
client = models.ForeignKey(Clients, related_name='projects')
created_by = models.ForeignKey(User, related_name='created_by')
#general information
proj_name = models.CharField(max_length=255, verbose_name='Project Name')
pre_quote = models.CharField(max_length=3,default='10-')
quote = models.IntegerField(max_length=10, verbose_name='Quote #', unique=True)
desc = models.TextField(verbose_name='Description')
starts_on = models.DateField(verbose_name='Start Date')
completed_on = models.DateField(verbose_name='Finished On')
def __unicode__(self):
return u'%s' % (self.proj_name)
def current_status(self):
try:
return self.status.all().order_by('-id')[:1][0]
except:
return None
class Status(models.Model):
project = models.ForeignKey(Project, related_name='status')
value = models.CharField(max_length=20, choices=STATUS_CHOICES, verbose_name='Status')
date_created= models.DateTimeField(auto_now=True)
def __unicode__(self):
return self.value
class Meta:
verbose_name = ('Status')
verbose_name_plural = ("Status")
views.py
#login_required
def addProject(request):
if request.method == 'POST':
form = AddSingleProjectForm(request.POST)
if form.is_valid():
project = form.save(commit=False)
project.created_by = request.user
project.save()
project.status.create(
value = form.cleaned_data.get('status', None)
)
return HttpResponseRedirect('/project/')
else:
form = AddSingleProjectForm()
return render_to_response('project/addProject.html', {
'form': form, 'user':request.user}, context_instance=RequestContext(request))
#login_required
def editProject(request, proj_id):
proj = Project.objects.get(pk=proj_id)
if request.method == 'POST':
form = AddSingleProjectForm(request.POST,instance=proj)
if form.is_valid():
form.save()
return HttpResponseRedirect('/project/')
else:
form = AddSingleProjectForm(instance=proj)
return render_to_response('project/edit_project.html', {
'form': form}, context_instance=RequestContext(request))
forms.py
from django.db import models
from project.models import Project, Status
from django.forms import *
from django import forms
from settings import STATUS_CHOICES
class AddSingleProjectForm(ModelForm):
status = forms.ChoiceField(choices=STATUS_CHOICES)
class Meta:
model = Project
exclude = ('pre_quote', 'created_by')
Snippet from editproject template:
{% block content %}
<FORM METHOD="POST" ACTION="">
{% csrf_token %}
<table>
{{ form.as_table }}
</table>
<input type="submit" value="Save Project">
</FORM>
{% endblock %}
Any suggestions would be greatly appreciated.
Thank you.
I think this is because project is defined as a ForeignKey on status, and not the other way around. ForeignKey is a One-To-Many relationship. Each project can have multiple statuses connected to it.
That's why on the project instance you'll find: project.status_set and not project.status.
You'll need to add the status to the form manually, by looking for the latest status connected to the project. Or perhaps change the ForeignKey to a OneToOne relationship, depending on your requirements.

Categories