I have this in my database
paragraph1
paragraph2
paragraph2
I would like to place a picture in between paragraphs.
I tried this
<img src="where/photo/is">
class Post(models.Model):
STATUS_CHOICES = (
('draft','Draft'),
('published', 'Published'),
)
title = models.CharField(max_length=250)
slug = models.SlugField(max_length=250, unique_for_date ='publish')
author = models.ForeignKey(User, related_name='blog_posts')
body = models.TextField()
publish = models.DateTimeField(default=timezone.now)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
image = models.ImageField(upload_to='posts', default='path/to/my/default/image.jpg')
status = models.CharField(max_length=10, choices=STATUS_CHOICES,
default='draft')
objects = models.Manager()
published = PublishedManager()
tags = TaggableManager()
class Meta:
ordering = ('-publish',)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('blog:post_detail',
args=[self.slug])
Note: This is the post table that takes the data in paragraphs, there is not picture in between, I would like to add it after getting this text body.
Here is my view
current_site = get_current_site(request)
namesite = current_site.name
domain = current_site.domain
post = Post.published.get(slug=post)
profile = Profile.objects.get(id=1)
if request.method == 'POST':
comment_form = CommentForm(data=request.POST)
if comment_form.is_valid():
#create Comment object but do not say to database just yet
new_comment = comment_form.save(commit=False)
#Assigng the current post to the comment
new_comment.post = post
#save the comment to the database
new_comment.save()
comment_form = CommentForm()
else:
comment_form = CommentForm()
return render(request, 'blog/detail.html',
{'post': post, 'comments': comments,
'comment_form': comment_form, 'namesite': namesite, 'domain': domain, 'profile': profile })
in the database and I use the | safe filter, but that still prints the same as above.
Do you have any idea how to perform that acction?
Hi If you want to create long description with image means you can go with django-ckeditor link, this package will provide you the RichTextField so you can create the bulk paragraphs with images.
Related
I am making a todo app for practice, the functionality I want to achieve is that, when a user create a task,Only the time field should be unique about all of his tasks, I have done (unique=True) In the time field in model but that make it unique all over the database, but I want it to be unique only with the tasks associated with the user.
the view is below:
#login_required(login_url='login')
def home(request):
tasks = Task.objects.filter(name__username=request.user.username)
form = TaskForm()
if request.method == 'POST':
form = TaskForm(request.POST)
if form.is_valid():
obj = form.save(commit=False)
obj.name = request.user
obj.save()
return redirect('home')
else:
print(request.POST)
print(request.user.username)
messages.warning(request, 'Invalid Data!')
return redirect('home')
context = {'tasks' : tasks}
return render(request, 'task/home.html', context)
task model:
class Task(models.Model):
choices = (
('Completed', 'Completed'),
('In Complete', 'In Complete'),
)
name = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True)
task = models.CharField(max_length=200, null=False, blank=False)
time = models.TimeField(auto_now_add=False, blank=True)
status = models.CharField(max_length=200, choices=choices, null=True, blank=False)
def __str__(self):
return self.task
def get_task_author_profile(self):
return reverse('profile')
as you can see, I want to show the task that the logged in user has added.
the form is:
class TaskForm(ModelForm):
class Meta:
model = Task
fields = '__all__'
exclude = ['name']
the functionality I talked about above, I tried to achieve through view:
#login_required(login_url='login')
def home(request):
tasks = Task.objects.filter(name__username=request.user.username)
time = []
for task in tasks:
time.append(task['time'])
form = TaskForm()
if request.method == 'POST':
form = TaskForm(request.POST)
if form.is_valid() and form.cleaned_data['time'] != time:
obj = form.save(commit=False)
obj.name = request.user
obj.save()
return redirect('home')
else:
print(request.POST)
print(request.user.username)
messages.warning(request, 'Invalid Data!')
return redirect('home')
context = {'tasks' : tasks}
return render(request, 'task/home.html', context)
but that gave an error: TypeError: 'Task' object is not subscriptable
I know its not right, but how can I achieve it, does Django have anything that can provide such fuctionality?
The problem is coming from here:
for task in tasks:
time.append(task['time']) #<--
Here if you want to use access time, you need to use task.time because task is an object.
Also need to fix another thing in your exisiting code to make it work, because time is a list:
if form.is_valid() and form.cleaned_data['time'] in time:
# ^^^
BTW, you don't need to make it that complicated, you can add Database level constraint from the model to make the times unique for a specific user. Also, use DateTime field for that. You can use unique_togather for that:
class Task(models.Model):
choices = (
('Completed', 'Completed'),
('In Complete', 'In Complete'),
)
name = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True)
task = models.CharField(max_length=200, null=False, blank=False)
time = models.DateTimeField(auto_now_add=False, blank=True)
status = models.CharField(max_length=200, choices=choices, null=True, blank=False)
class Meta:
unique_togather = ['name', 'time']
Hello guys I am making a ecommerce website as part of learning django. I have a review model but I want to make sure that a customer can only put a review once. How to do that with my existing model and views. Please have a look at my codes:
views
def product_review(request, slug):
user = request.user
product = get_object_or_404(Product, slug=slug)
reviews = ProductFeedback.objects.filter(product=product).order_by('-id')
if request.POST:
if product.user == request.user:
messages.error(request, 'You can\'t review your own product')
return redirect('store:product_detail', product.slug)
else:
p_review_form = ProductReviewForm(request.POST or None)
if p_review_form.is_valid():
product_rating = request.POST.get('product_rating')
product_review = request.POST.get('product_review')
p_review = ProductFeedback.objects.create(product=product, user=user,
product_rating=product_rating, product_review=product_review)
p_review.save()
return redirect('store:product_detail', product.slug)
else:
p_review_form = ProductReviewForm()
context = {
'product':product,
'p_review_form':p_review_form,
'reviews': reviews,
}
return render(request, 'store/product/product_detail.html', context)
model
class ProductFeedback(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='product')
product_rating = models.CharField(choices=RATINGS, max_length=10, null=True)
product_review = models.TextField(max_length=1000)
reply = models.ForeignKey('ProductFeedback', null=True, related_name='replies', blank=True, on_delete=models.CASCADE)
timestamp = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f'{self.user.username}--{self.product.title} review'
You can filter all reviews by the user if there is any review then raise an error. The main idea is to get the reviews and filter them by request.user and see if there are any.
from django.core.exceptions import PermissionDenied
def product_review(request, slug):
product = get_object_or_404(Product, slug=slug)
# Get the reviews posted by the user for this product
user_review = Product.product.filter(user=request.user)
if request.method == 'POST':
if user_review:
# If there is/are any reviews, raise an error
raise PermissionDenied('You have already given your review on this post.')
Hope this helps.
Intro: I have a post which can have multiple images I achieving this with the help of 2 models namely. Post and Prep. The post model has a user, title, a message and a post_image
class Post(models.Model):
user = models.ForeignKey(User, related_name='posts')
title = models.CharField(max_length=250, unique=True)
message = models.TextField()
post_image = models.ImageField(upload_to='post_images/')
I am using another model to get additional images called Prep This can have multiple images.
class Prep (models.Model): #(Images)
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='post_prep')
image = models.ImageField(upload_to='post_prep_images/', blank=True, null=True)
image_title = models.CharField(max_length=100)
image_description = models.CharField(max_length=250)
However unlike before each of the images from the prep model has a image_title and a image_description
The Issue: I am able to create a post successfully and also almost edit the post with one exception I cannot reduce the number of images.
If I have 3 Prep images I can add more images up to the max allowed
I can edit existing images
I cannot reduce the number of prep images
I get an error in the form
This field is required.
How do I fix this error
my post_edit view
def post_edit(request, slug):
post = get_object_or_404(Post, slug=slug)
ImageFormSet = modelformset_factory(Prep, fields=('image', 'image_title', 'image_description'), extra=7, max_num=7,
min_num=2)
if post.user != request.user:
raise Http404()
if request.method == "POST":
form = PostEditForm(request.POST or None, request.FILES or None, instance=post)
formset = ImageFormSet(request.POST or None, request.FILES or None)
if form.is_valid() and formset.is_valid():
form.save()
data = Prep.objects.filter(post=post)
for index, f in enumerate(formset):
if f.cleaned_data:
if f.cleaned_data['id'] is None:
photo = Prep(post=post, image=f.cleaned_data.get('image'), image_title=f.cleaned_data.get('image_title'),
image_description=f.cleaned_data.get('image_description'))
photo.save()
#I thought the below code will do the trick but it doesn't seem to be
elif f.cleaned_data['image'] is False or f.cleaned_data['image_title'] is False or f.cleaned_data['image_description'] is False:
photo = Prep.objects.get(id=data[index].id)
photo.image.delete()
photo.image_title.delete()
photo.image_description.delete()
photo.id.delete()
else:
photo = Prep(post=post, image=f.cleaned_data.get('image'), image_title=f.cleaned_data.get('image_title'),
image_description=f.cleaned_data.get('image_description'))
d = Prep.objects.get(id=data[index].id)
d.image=photo.image
d.image_title=photo.image_title
d.image_description=photo.image_description
d.save()
return HttpResponseRedirect(post.get_absolute_url())
else:
form = PostEditForm(instance=post)
formset = ImageFormSet(queryset=Prep.objects.filter(post=post))
context = {'form': form, 'post': post, 'formset': formset}
return render(request, 'posts/post_edit.html', context)
can_delete=True, in modelformset_factory
All I'm trying to do is save the simple form. Everything looks fine but after I click save and the form is re-rendered there is no new trade in the Database. No error message is thrown either.
At first, I thought there was an issue with the user but it looks fine as well. Been reading a lot of documentation on this topic but haven't found where the issue is yet.
Thanks for any help and please let me know if there is anything extra I can add.
create.html
<form id='trade_create_view' method='POST' action='.'>
{% csrf_token %}
{{ form.as_p }}
<input type='submit' value='Submit' >
</form>
views.py
def trade_create_view(request):
form = TradeForm(request.POST or None, instance=request.user)
if form.is_valid():
print(form.cleaned_data)
form.save()
form = TradeForm()
context = {
'form': form,
}
return render(request, "tj/cp/trade/create.html", context)
forms.py
from django import forms
from .models import Trade
class TradeForm(forms.ModelForm):
class Meta:
model = Trade
fields = [
'user',
'target_size',
'target_entry',
'target_exit',
'ticker',
'exchange',
'short',
'comments',
'size',
'entry_price',
'exit_price',
'entry_date',
'exit_date',
'fees',
'permission',
]
exclude = ['user',]
model.py
class Trade(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=False)
comments = models.TextField(max_length=10000, blank=True, null=True)
created = models.DateField(auto_now_add=True)
last_edit = models.DateField(auto_now=True)
#general trade info
ticker = models.ForeignKey(Ticker, on_delete=models.CASCADE)
short = models.BooleanField(default=False)
exchange = models.ForeignKey(Exchange, on_delete=models.CASCADE)
#target trade outline
target_size = models.DecimalField(null=True, blank=True, max_digits=50, decimal_places=20)
target_entry = models.DecimalField(null=True, blank=True, max_digits=50, decimal_places=20)
target_exit = models.DecimalField(null=True, blank=True, max_digits=50, decimal_places=20)
#real trade
size = models.DecimalField(null=True, blank=True, max_digits=50, decimal_places=20)
entry_price = models.DecimalField(null=True, blank=True, max_digits=50, decimal_places=20)
exit_price = models.DecimalField(null=True, blank=True, max_digits=50, decimal_places=20)
entry_date = models.DateField(blank=True, null=True, default=datetime.now)
exit_date = models.DateField(blank=True, null=True, default=datetime.now)
fees = models.DecimalField(blank=True, null=True, max_digits=50, decimal_places=20)
PER_OPTIONS = [
('0', 'Public'),
('1', 'Private'),
('2', 'Mentor Only'),
]
permission = models.CharField(max_length=1, choices=PER_OPTIONS, default=0)
I think you just have to check if your request is a post or a get method:
def trade_create_view(request):
if request.method == "POST":
form = TradeForm(request.POST or None, instance=request.user)
if form.is_valid():
print(form.cleaned_data)
form.save()
form = TradeForm()
context = {
'form': form,
}
return render(request, "tj/cp/trade/create.html", context)
OR
You just can add a post def to your view as follows:
def post(self, request):
form = TradeForm(request.POST or None, instance=request.user)
if form.is_valid():
print(form.cleaned_data)
form.save()
form = TradeForm()
...
This line doesn't make sens: TradeForm(request.POST or None, instance=request.user)
When you use instance for your form, you give an instance of the object concerned. But your object is Trade not User. You can choose different ways to solve the problem, I give one:
def trade_create_view(request, id):
form = TradeForm()
if request.method == "POST":
trade, created = Trade.objects.get_or_create(id=id) # you get or create your instanced Trade
form = TradeForm(request.POST, instance=trade) # you give to your form the instance of your Trade
if form.is_valid():
print(form.cleaned_data)
form.save()
context = {
'form': form,
}
return render(request, "tj/cp/trade/create.html", context)
I arbitrarily took the id to query an object Trade. As I understand your code you can use this function to create and edite any Trade object with your TradeForm.
get_or_create is document on the Django Website. If you don't when to use it, you can use Trade.objects.get(id=id) you you need to check if the object exist before.
But if you just when to create an object Trade just remove instance=XXX, and use TradeForm(request.POST). Instance is used to get an object in your database and overwrite with the new data posted and processed by your form.
So I switched everything over to Class-Based Views and for some reason now it works perfectly and instantly.
What came even more as a shock is that when I checked my database again after the first Class-Based View test there were about 15 test trades that now appeared (and trust me I checked/refreshed the database after every function view test). So.. I guess it worked all along which is nice because I really read the documentation 10x to figure out what was wrong and was getting really frustrated. What's not so nice is that the database took hours to update or maybe they were frozen somewhere else. That I can't explain yet.
the new views.py
class TradeCreateView(CreateView):
template_name = "tj/cp/trade/create.html"
form_class = TradeForm
queryset = Trade.objects.all()
def form_valid(self, form):
print(form.cleaned_data)
return super().form_valid(form)
Thanks for the help everyone!
I know this maybe not the perfect resolve you guys were hoping for but at least there is some closure.
I am writing a control view function edit_article to update fields of title and content of model table Article:
To update the title and content, I employed article=form.save
def edit_article(request, pk):
article = Article.objects.get(pk=pk)
if request.method == "POST":
form = ArticleForm(data=request.POST)
print(request.POST)
if form.is_valid():
article = form.save()
It reports error when issue submitting
django.db.utils.IntegrityError: (1048, "Column 'owner_id' cannot be null")
I did not change owner_id, just keep it as its previous state.
The problem is solved by explicitly re-assign attribute:
if form.is_valid():
# article = form.save()
article.title = form.cleaned_data['title']
article.content = form.cleaned_data['content']
article.save()
The model Article
class Article(models.Model):
STATUS = (
(1, 'normal'),
(0, 'deleted'),
)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
block = models.ForeignKey(Block, on_delete=models.CASCADE)
title = models.CharField(max_length=100)
content = models.TextField() # set the widget
status = models.IntegerField(choices=STATUS)
date_created = models.DateTimeField(auto_now_add=True)
date_updated = models.DateTimeField(auto_now=True)
class Meta:
ordering = ("id",)
def __str__(self):
return self.title
Why form.save() failed as a shortcut?
If you want to update existing record, you should pass instance object of that model to the form.
So your code would change to
if request.method == "POST":
form = ArticleForm(instance=article, data=request.POST)
...