Really new to Django so bear with me :)
I am running into an issue to display the posts titles in the Django admin.
I have tried both in Python 3
class Post(models.Model):
title = models.TextField(max_length=100)
text = models.TextField(max_length=10000)
tags = models.TextField(max_length=300)
comments = models.TextField(max_length=400)
def __str__(self):
return self.title
and Python 2
class Post(models.Model):
title = models.TextField(max_length=100)
text = models.TextField(max_length=10000)
tags = models.TextField(max_length=300)
comments = models.TextField(max_length=400)
def __unicode__(self):
return self.title
but unfortunately in the Django admin I see
"Post object "in the list of posts
Thanks in advance for your help.
Maybe you can try this:
from django.utils.encoding import python_2_unicode_compatible
#python_2_unicode_compatible
class Post(models.Model):
title = models.CharField(max_length=255)
text = models.TextField(max_length=10000)
tags = models.TextField(max_length=300)
comments = models.TextField(max_length=400)
def __str__(self):
return self.title
For those who might come here after me, you'd have to add this method inside the model class.
def __str__(self):
return self.title
Make sure it's indented right or else it might not work.
Add your post models to the administration site. Edit the admin.py file of your app and make it look like this:
from django.contrib import admin
from .models import Post
admin.site.register(Post)
The admin has many hooks for customization check documentation
There is no way to have Django return, say, a MyPerson object whenever you query for Person objects. A queryset for Person objects will return those types of objects. The whole point of proxy objects is that code relying on the original Person will use those and your own code can use the extensions you included (that no other code is relying on anyway
class Person(models.Model):
name = models.CharField(max_length=128)
def __str__(self):
return self.name
Know more
For those who come after, make sure post is in lowercase.
And after which make migrations again.
make sure name='post' not 'Post'...
migrations.AlterModelOptions(
name='post',
Related
I am working on a project where I want to create a slug for each post based on its title. Is it possible to generate a slug in such a way that it will be unique to the post, but will not change even if the title of the post is changed? I am using the model provided in the file 'model.py'. Can you provide guidance on how to accomplish this?
class Post(models.Model):
username = models.ForeignKey(UserProfile, on_delete=models.CASCADE)
description = models.CharField(('Description'),max_length=250)
title = models.CharField(('Content Title'), max_length=250)
create_date = models.DateTimeField(default = timezone.now)
image_data = models.ImageField(upload_to='User_Posts', height_field=None, width_field=None, max_length=None)
slug = (title)
def __str__(self):
return self.title
I recommend checking out the Django documentation for slugify. You will need to override the save method of your model to do this, so your new code will most likely look something like this:
from django.utils.text import slugify
slug=models.SlugField()
def save(self,*args,**kwargs):
self.slug=slugify(self.title)
super(Post,self).save(*args,**kwargs)
I would keep in mind the unique parameter that you can set to either true or false in your slugfield.
I am learning django by building a simple blogging app. While its all but done, I currently have individual posts having a url in the format https://my_site_dot_com/blog/entry/38/ where the number 38 corresponds to the primary key of said post.
What i want is it to have the format https://my_site_dot_com/blog/entry/this_is_custom_title/ where "this_is_custom_title" corresponds to the heading of the post. I have no idea how to accomplish this. Can anyone offer any assistance?
My model looks like:
class Entry(models.Model):
entry_title = models.CharField(max_length=50)
entry_text = models.TextField()
image = models.FileField(upload_to="media", blank=True)
entry_date = models.DateTimeField(auto_now_add=True)
entry_author = models.ForeignKey(User, on_delete=models.CASCADE)
class Meta:
verbose_name_plural = "blog"
def __str__(self):
return self.entry_title
I want the entry_title to the the custom url instead of the primary key.
My urls.py looks like this:
urlpatterns = [
path('', HomeView.as_view(), name="blog-home"),
path('entry/<int:pk>/', EntryView.as_view(), name="entry-detail"),
path('create_entry/', CreateEntryView.as_view(success_url='/'), name='create_entry'),
]
Edit:
The class handing the post looks like this:
class EntryView(DetailView):
model = Entry
template_name = 'blog/entry_detail.html'
data_set = random_info()
stuff_for_post = {
"info": data_set
}
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['rand_im'] = random_image()
context['tags'] = ['tag1','tag2','tag3']
return context
I'm an absolute noob in django and come from android/java. So please give an easy to understand explanation.
Thanks in advance
You may add a slug field to your Entry model and a get_absolute_url method. Don't forget to import reverse function from Django's url module.
from django.urls import reverse
class Entry(models.Model):
entry_title = models.CharField(max_length=50)
entry_text = models.TextField()
image = models.FileField(upload_to="media", blank=True)
entry_date = models.DateTimeField(auto_now_add=True)
entry_author = models.ForeignKey(User, on_delete=models.CASCADE)
slug = models.SlugField()
def get_absolute_url(self):
return reverse('entry_detail', kwargs={'slug': self.slug})
class Meta:
verbose_name_plural = "blog"
def __str__(self):
return self.entry_title
Then, within the urls.py module of your app, add the following url pattern to the urlpatterns list. Don't forget to load the corresponding view, I guess it may be EntryView in this case.
from django.urls import path
from .views import EntryView
urlpatterns = [
...
path('<slug:slug>', EntryView.as_view(), name='entry_detail'), # new
...
]
Then the slug should replace the primary key pattern in the url.
To go a bit further, you can use a method within your model that slugify your title for instance. (define the method within the model then call it from the save method of the model, by overriding the save method)
https://docs.djangoproject.com/en/3.0/ref/utils/#django.utils.text.slugify
Currently you are passing an integer through your url. All you need to do is modify this slightly to pass a string through the url. Here is a similar question that discusses how to accomplish this.
As for changes you need to make in your code, urls.py will need to be updated
path('entry/<str:title>/', EntryView.as_view(), name="entry-detail")
You haven't provided your blog post view, but it will then look something like this:
def post(request, title):
template = "template.html"
post = Posts.objects.filter(entry_title==title)
return render(request, template, {'post':post})
If you are using a Class Based View you should use a slug.
First add a new field entry_slug to your Entry model and override the save method in order to automatically generate the entry_slug field:
class Entry(models.Model):
entry_title = models.CharField(max_length=50)
entry_slug = models.CharField(max_length=50)
...
def save(self, *args, **kwargs):
self.entry_slug = slugify(self.entry_title )
super(Entry, self).save(*args, **kwargs)
You can do by replacing the pk with entry_slug:
path('entry/<slug:entry_slug>/', EntryView.as_view(), name="entry-detail")
I am new with python and django, i want to know how can i implement the admin search bar on my project model? i notice that the user model has it by default.
My code is below, after the makemigration command still no search bar i think i am missing something. sorry for the noob question.
class Todo(models.Model):
search_fields = ('title', 'text', 'created_at',)
title = models.CharField(max_length=200)
text = models.TextField()
created_at = models.DateTimeField(default=datetime.now)
def __str__(self):
return self.title
in the apps admin.py
inside the class for which you are registering the model
add
search_fields = ['column_name']
add search fields in admin file instead of models file
I'm hoping this is just an issue of my poor regex understanding.
I'm attempting to use the exact code on Django 1.9's generic views to build a blog and personal site, and, down to the testing, here's where I run into trouble:
def test_post_page(self):
post = PostModelFactory()
first_post = Post.objects.all()[0]
post_url = first_post.get_absolute_url()
print(post_url)
response = self.client.get(post_url, follow=True)
self.assertEqual(response.status_code, 200)
So, through that print statement, I determined models.Post.get_absolute_url() was returning my homepage URL. Here's models.py:
class Post(models.Model):
title = models.CharField(max_length=200)
subtitle = models.CharField(max_length=200, default="")
pub_date = models.DateTimeField(auto_now_add=True)
text = models.TextField()
slug = models.SlugField(max_length=40,unique=True)
def get_absolute_url(self):
return "%s/" % (self.slug)
Should it come up, I copied down what the generic views documentation has, so my Detailview in /blog/urls.pyis as follows:
url(r'^(?P<slug>[-\w]+)/$', PostDetailView.as_view(), name='post-detail'),
Same of views.py:
class PostDetailView(DetailView):
model = Post
def get_context_data(self, **kwargs):
context = super(PostDetailView, self).get_context_data(**kwargs)
context['now'] = timezone.now()
return context
As far as I can tell, my get_absolute_url() function is simply not doing what I think it's doing, let alone what the regex in urls.py expects it to do.
Also: Is there anyone who can fully explain how slugfield works? I know it's a keyword generator to create a url, but I'm not sure how it works (or doesn't, as in this example).
Then, finally, in both a tutorial that I'm quasi-following alongside the documentation, and the documentation, itself, I'm not fully understanding where the variable names in templates are coming from (my understanding is that the request hit's the URL, which generates the data from views.py). The "ListView" object in the template shares the model name, "post" (or "article" in the documentation), where its pageview at the bottom is accessed simply through "page_obj", and the "DetailView" object is simply called "object". I also may be having a problem with paginating my ListView, ( which is identical to the documentation example, but with the extra line paginate_by = 2 right above get_context_data.
Thank you.
EDIT:
I've included PostModelFactory:
class PostModelFactory(DjangoModelFactory):
class Meta:
model = Post()
django_get_or_create = (
'title',
'subtitle',
'text',
'pub_date',
)
title = 'This is a test.'
subtitle = 'This is only a test.'
text = 'Madness? This is Sparta.'
pub_date = timezone.now()
def __init__(self):
self.save()
Edit: The issue turned out to be the lack of a slug in the PostModelFactory.
Ideally, you should use reverse in get_absolute_url, instead of hardcoding it.
from django.core.urlresolvers import reverse
class Post(models.Model):
...
def get_absolute_url(self):
return reverse('post-detail', args=[self.slug])
If you do hardcode the URL, it should contain a leading slash.
def get_absolute_url(self):
return "/%s/" % (self.slug)
If first_post.get_absolute_url is returning the homepage url with your current get_absolute_url, that suggests that the slug is an empty string.
I have a blog app that consists of 3 models: department, author, post
I am having trouble structuring the models correctly and creating the corresponding forms
models.py
from django.db import models
class Department(models.Model):
name=models.CharField(max_length=20)
posts = models.ForeignKey('Post')
authors = models.ManyToManyField('Author')
def __unicode__(self):
return self.name
class Author(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
post = models.ForeignKey('Post')
def __unicode__(self):
return self.last_name
class Post(models.Model):
title=models.CharField(max_length=20)
post = models.TextField()
creation_date = models.DateField(auto_now_add=True)
def __unicode__(self):
return self.title
The idea is that a department can have many posts, but each post belongs to only one department. A department can also be made up of multiple authors and authors can be in multiple departments. Where I'm really having trouble is with the forms.
The relevant urls.py looks like this:
url(r'^(?P<department_id>\d+)/posts/$', views.posts, name='posts'),
url(r'^(?P<department_id>\d+)/add_post/$', views.add_post, name="add_post"),
So I can pull in all the posts by department. The goal of the form is for the department id to be recognized and added automatically to the post.
def add_post(request, department_id):
department = Department.objects.get(pk=department_id)
if request.method == 'POST':
new_post_form = PostForm(data=request.POST)
if new_post_form.is_valid():
new_post = new_post_form.save(commit=False)
new_post.department = department
new_post.save()
return redirect('posts', department_id=department_id)
Now I realize that the Post model does not have a department attribute, which is the error that I get, but I'm guessing that there's a way to make this happen, I just don't know what it is.
Thanks as always for your help. Please let me know if anything is unclear.
The fact that the Post model does not have a department attribute should have given you the clue that your structure is wrong: it clearly needs one. The issue is that you have your ForeignKey the wrong way round: a FK is a one-to-many relationship, and lives on the "many" side, in your case Post, pointing to the "one", ie the Department.
Then your view code will work exactly as it is, and you can retrieve all posts for a department with my_department.post_set.all().