Django formsets and files - python

I have this web app, created with Django framework and I'm struggling with one particular issue. I would like to create formset with file attachment (Attachment is related to Document vie FK relationship), and I would like to provide url to mentioned file in frontend.
model.py
class Attachment(models.Model):
name = models.CharField(max_length=100, verbose_name='name')
file = models.FileField(upload_to='attachments', null=True,
verbose_name='file')
class Document(models.Model):
attachment = models.ForeignKey(
'Attachment', null=True, on_delete=models.CASCADE)
date = models.DateField(blank=True, null=True,)
title = models.CharField(max_length=250, null=True, blank=False)
def get_attachment_file(self):
return self.attachment.file.url
def get_attachment_filename(self):
return str(self.attachment.file)[12:]
form.py
class DocumentForm(forms.ModelForm):
class Meta:
model = Contract
fields = ('attachment', 'date', 'title', 'approved')
DocumentFormset = modelformset_factory(Document, form=DocumentForm, extra=0)
view.py
def documents(request):
... some logic and filtering, get doc_id
documents = Document.objects.filter(document=doc_id)
formset = DocumentFormset(queryset=documents)
return render(request, 'documents.html', {'formset': formset})
template: documents.html
{% for form in formset %}
<div class="form-group">
<label for="{{ form.attachment.id_for_label }}">Title</label>
{{ form.attachment}}
</div>
{% endfor %}
I have hard time to access file url in attachment object, in template engine I cant call get_attachment_file() function, form.attachment.file.url is empty.
Is there a way to get file url from attachment object?
Thank you.

Related

Select2 widget showing on Django Admin site but not on the form template in Django4

I have two object models, NewsObject and StockObject. The stock object is a foreign key in the news object.
class stockObject(models.Model):
stock_name = CharField(max_length=100, blank=True, null=True)
stock_tag = CharField(max_length=100, blank=True, null=True)
def __str__(self):
return self.stock_name
class newsObject(models.Model):
title = CharField(max_length=100, blank=True, null=True)
body = TextField(blank=True, null=True)
stock = ForeignKey(stockObject, on_delete=models.SET_NULL, blank=True, null=True)
I have used autocomplete_fields property in the ModelAdmin class as I want a searchable dropdown for stocks in news. I have also added search_fields in the stocks ModelAdmin as mentioned in the documentation.
This is what my admin.py looks like:
class stockAdmin(admin.ModelAdmin):
list_display = ['stock_name', 'stock_tag']
search_fields = ['stock_name']
class newsAdmin(admin.ModelAdmin):
list_display = ['title', 'body', 'stock']
search_fields = ['title', 'body', 'stock']
autocomplete_fields = ['stock']
Now, the issue is that I get a searchable dropdown on the Django Admin site for this field, but it is only a dropdown (not searchable) on the actual template screen. I have a basic view which calls the template, like so:
Views.py
def createNews(request):
form = NewsForm()
if request.method == 'POST':
form = NewsForm(request.POST)
if form.is_valid():
form.save()
return redirect('/backoffice/')
context = {'form' : form}
return render(request, 'NewsForm.html', context)
And NewsForm.html is:
{% extends "base.html" %}
{% load static %}
{% block content %}
<form action="" method="POST">
{% csrf_token %}
{{ form }}
<input type="submit" name="Submit">
</form>
{% endblock %}
I've been wondering what might be the cause of this behavior. Tried multiple things but none of them work. What might I be missing here?
Django Admin site image
Django Template Image
I think you have written all your models in camelCase so first changed them to PascalCase.
Second, you have missed models in all your models:
Write them like this add models before every datatype like:
from django.db import models
class Musician(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
instrument = models.CharField(max_length=100)
Not only datatype of fields.

Forigen Key not displaying in rendered model form

I am looking for guidance on where I am going wrong. My model form is rendering correctly however the author has no option to select or input. I suspect this is is because the author is a foreign key. How do I get around this so the form will display a list of users or allow to manually input a name. Any help would be greatly appreciated :)
models.py
class Post(models.Model):
title = models.CharField(max_length=200, unique=True)
slug = models.SlugField(max_length=200, unique=True)
author = models.ForeignKey(User, on_delete=models.CASCADE,
related_name="workout_posts")
updated_on = models.DateTimeField(auto_now=True)
featured_image = CloudinaryField('image', default='placeholder')
content = models.TextField(default='SOME STRING')
excerpt = models.TextField(blank=True)
created_on = models.DateTimeField(auto_now_add=True)
class Meta:
# ordered created on field starting with newest first
ordering = ['-created_on']
def __str__(self):
return self.title
forms.py
class MakeWorkOutForm(forms.ModelForm):
class Meta:
model = Post
fields = '__all__'
views.py
def createWorkOut(request):
form = MakeWorkOutForm
context = {'form': form}
return render(request, "add-workout.html", context)
html
{% extends "base.html" %} {% block content %} {% load static %}
<h1>Create A Workout</h1>
<form action="" method="POST">
{% csrf_token %}
{{form}}
<input type="submit" name="submit">
</form>
{% endblock content %}

Django Querying: How do i query an account page through a blog post that the account owner has created? aka link from one to another

Django Querying: How do i query an account page through a blog post that the account owner has created? aka link from one to another. So I have an account model and a blog post model, with the author as the foreign key. I am unsure of how i can do the querying of the account. Can anyone advise how this is normally done? Because I tried to do user_id=request.user.id but this would take me to my own account view. Thanks!
html
<a class="dropdown-item" href="{% url 'account:view' %}">{{blog_post.author}}</a>
views.py
def detail_blog_view(request, slug):
context = {}
blog_post = get_object_or_404(BlogPost, slug=slug)
context['blog_post'] = blog_post
return render(request, 'HomeFeed/detail_blog.html', context)
urls.py for Blogs
path('<slug>/detail/', detail_blog_view, name= "detail"),
urls.py for accounts:
path('<user_id>/', account_view, name="view"),
models.py
class Account(AbstractBaseUser):
email = models.EmailField(verbose_name="email", max_length=60, unique=True)
username = models.CharField(max_length=30, unique=True)
class BlogPost(models.Model):
title = models.CharField(max_length=50, null=False, blank=False)
body = models.TextField(max_length=5000, null=False, blank=False)
slug = models.SlugField(blank=True, unique=True)
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
You don't really need to query the author, what you do is just get the foreign key value from the BlogPost object like this:
views.py
def post(request, pk):
post = BlogPost.objects.get(pk=pk)
author = post.author
return render(request, 'post.html', {'post': post,
'author': author})
Then display it in a template:
post.html
{{ author }}
(or you can use {{ post.author }} here aswell) says:
{{ post.title }} | {{ post.body }}
EDIT
in your urls where you have a path to your user profile you actually need to specify the argument type like:
path('<int:user_id>/', account_view, name="view"), # btw dont call your views 'view', name should describe what the view actually does or shows

How to create new issues without selecting 'project'(manually select project_id)?

I am doing my school project by using Django to create a task management web application. My responsibilities are to create 'issue tracker', something like 'StackOverflow', but I am still at the very early stage of it. So I used crispy form to let the user create their own new issues. Since we use 'project_id' and 'issue_id' as parameters to direct users to different pages, so I encountered this problem, users have to manually choose 'project' when they create a new issue. I do not know how to put the issue which created by the user under right project without having to choose 'project' manually.
form.py
from django import forms
from .models import Comment,Issue
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ('body',)
class IssueForm(forms.ModelForm):
class Meta:
model = Issue
fields = ('title','content','project','status')
class NewIssueForm(forms.ModelForm):
class Meta:
model = Issue
fields = ('title','content','project','status')
new_issue.html
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<h1>Add New Issue </h1>
<form method="POST" class="Issue-form">{% csrf_token %}
{{form|crispy}}
<button type="submit" class="btn btn-success">Submit</button>
</form>
{% endblock %}
models.py
class Issue(models.Model):
STATUS_CHOICES = (
('draft', 'Draft'),
('published', 'Published'),
)
project = models.ForeignKey(Project,on_delete=models.CASCADE)
title = models.CharField(max_length=250)
slug = models.SlugField(max_length=250)
content = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE)
published = models.DateTimeField(default=timezone.now)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
status = models.CharField(max_length=9, choices=STATUS_CHOICES, default='draft')
def save(self, *args, **kwargs):
self.slug = slugify(self.title)
super(Issue, self).save(*args, **kwargs)
def get_absolute_url(self):
return reverse('project:issue_tracker:issue_detail', kwargs={'project_id':self.project_id, 'issue_id':self.id})
def __str__(self):
return self.title
urls.py
urlpatterns =[
path('',views.list_of_issue,name='list_of_issue'),
path('<int:issue_id>/',views.issue_detail,name='issue_detail'),
path('<int:issue_id>/comment',views.add_comment,name='add_comment'),
path('new_issue/',views.new_issue,name='new_issue'),
path('<int:issue_id>/edit_issue/',views.edit_issue,name='edit_issue'),
path('<int:issue_id>/delete_issue/',views.delete_issue,name='delete_issue'),
path('<int:issue_id>/delete', TemplateView.as_view(template_name="issue_tracker/issue/nice_delete.html"), name='success_deletion'),
]
You can set an initial value for the project field in the issue form. An explanation of how that can be done can be found here.
Since you are using project_id and issue_id as parameters, something similar to the following will solve your problem (I guess):
def new_issue(request, project_id, issue_id):
.
.
form = IssueForm(initial={'project': project_id})
.
.

Bringing Information from django.contrib.auth.models.User into View

I have the following model in my Django project:
from django.contrib.auth.models import User
class Project(models.Model):
project_title = models.CharField(max_length=200)
project_description = models.CharField(max_length=200, default="")
created_date = models.DateTimeField('date created')
owner = models.ForeignKey(User)
def __str__(self):
return self.project_title
This view uses the Project model as follows:
class ProjectView(generic.edit.UpdateView):
model = Project
fields = ['project_title','project_description']
template_name = 'steps/project.html'
success_url = reverse_lazy('steps:index')
My question is how can I bring the User's fields into my ProjectView so I can then use them in templates? In particular, I would like to display the logged-in user's name and email.
user information placed on request, not on views. So you can write in template {{user.username}}, or {{user.email}}. and you'll get it. Of course if user.is_authenticated
in your template write:
{% if request.user.is_authenticated %}
{{ request.user.username }}
{{ request.user.email }}
{% endif %}

Categories

Resources