django ModelForm foreign key - text widget add if not exist - python

I am just starting out with Django and have the following:
models.py:
class Song(models.Model):
name = models.CharField(max_length=200, blank=False, null=False)
artist = models.ForeignKey(Artist, blank=False, null=False)
class Artist(models.Model):
name = models.CharField(max_length=200, unique=True)
Now I have a model form for Song but currently have no ability to add artists that don't already exist (rendered as a dropdown). It would be nice to allow users to add artists on the fly but haven't been able to find a way to get that working. I saw lots of answers relating to replicating the admin "add another..." but kept running into roadblocks and outdated information.
What I tried:
replicating the "add another" from the admin console
Creating as a regular form - but abandoned it because ModelForms gives me a lot for free
Started researching on formsets but got stuck there, could not find a working example
Is there a way to easily add another artist from the song form? I don't mind rendering a new textbox below the artist selection where the user can add a new artist but I don't know how to do that with ModelForms and then add the artist into the database before saving.
Any advice would be much appreciated!

It would help to see what you are using to create your forms. I assume you are using a ModelFrom. If you are using jQuery I think you could use the following in your forms.py to capture a new artist. However, if you are using jQuery I would save individual forms as templates and display them as necessary depending on a button or link event for a new artist.
forms.py
class SongForm (forms.ModelForm):
new_artist_name = forms.CharField()
class Meta:
model = Song
def save(self, commit=True):
# do something with self.cleaned_data['new_artist']
new_artist = Artists.objects.filter('new_artist_name')
if new_artist.exists():
# Save song to artist.
else:
# Create and save new artist and save song to the
# new artist.
return super(SongForm, self).save(commit=commit)

Related

Django : submitting Foriegn key field with or without form object to models

we can submit foriegnkey data to models
through ModelForm
class BooksForm(forms.ModelForm):
class Meta:
model = Books
fields = "__all__"
where in templates we can add
{{form.author}} (author is foriegnkey field in books model)
Im aware that we can submit foriegnkey data using forms like this
but my question is.is there any way where we can submit a foriegnkey object which we have fetched using some other method (with or without form )
to a model(in my case its book)
Let me explain it in detail
lets say for instance there is a Search bar
when users search for author,
then the function fetches list of authors (choice field) to the user
where user can select and submit
which should get populated in the books model
there isnt any proper info related to this on web
all i could see is information on how to save data with Foriegnnkey using model form
any kind of insights is appreciated
I'm not 100% sure what your desired outcome is - this is how I understand your issue:
If you want to create a Book entry while passing an Author instance along you could set it as follows:
# models.py
class Author(models.Model):
name = models.CharField(max_length=50)
class Book(models.Model):
author = models.ForeignKey('Author', on_delete=models.CASCADE)
title = models.CharField(max_length=50)
# views.py
def example_view(request):
selected_author_instance = Author.objects.get(pk=1) # example query, adjust to your needs
# Create Book instance and pass author instance along
book_instance = Book.objects.create(
author=selected_author_instance,
title='example'
)
book_instance.save()
return render(...)

Django - How to dynamically restrict category of blog post?

I'm working on a blog project. I want to set primary and secondary categories for the posts. For example,
primary category: Music, Movie, Computer
and secondary categories for each primary category like:
Music - Dance, Rock, Country /
Movie - Script, Teaser, Review /
Computer - Hardware, Software /
And when I create a new post I want to restrict secondary category choices according to the primary category I chose.
(to be precise, in the post creation form,
first, I want both primary and secondary categories to be shown in dropdown menus, and
second, after I choose a primary category I want only the secondary category choices which belong to the primary category I chose to be shown in the dropdown menu for secondary category.)
Currently my models.py:
class PrimaryCategory(models.Model):
title = models.CharField('Primary Category', max_length=50)
class SecondaryCategory(models.Model):
title = models.CharField('Secondary Category', max_length=50)
primary = models.ForeignKey(PrimaryCategory,on_delete=models.CASCADE)
class Post(models.Model):
title = models.CharField(max_length=256)
content = models.TextField()
create_date = models.DateTimeField(auto_now_add=True)
author = models.ForeignKey(User, null=True, on_delete=models.CASCADE)
primary_category = models.ForeignKey(PrimaryCategory, on_delete=models.CASCADE, null=True)
secondary_category = models.ForeignKey(SecondaryCategory, on_delete=models.CASCADE, null=True)
and I searched and I can maybe use ForeignKey.limit_choices_to in my ModelForms, but I'm stuck here. Could anybody kindly help writing my forms.py?
currently I only have forms.py like:
from django import forms
from myblog.models import Post,PrimaryCategory,SecondaryCategory
class PostForm(forms.ModelForm):
secondary_category = models.ForeignKey(
PrimaryCategory,
on_delete=models.CASCADE,
limit_choices_to= ??? ,
)
class Meta:
model=Post
to summerize:
how to show category choices in dropdown menu instead of free text input?
how to dynamically restrict secondary category choices according to primary category choice in the form?
(Added) 3. I have no working knowledge of javascript, so I want to do it without JS if possible..If it is not possible to change choices dynamically, then is it at least possible to make the form to give me an error message if secondary category choice I made is not under chosen primary cagetory? I think I'll work on it but any advice would be of great help.
I would appreciate any help. Thank you.
I googled and found exactly what I wanted here:
https://simpleisbetterthancomplex.com/tutorial/2018/01/29/how-to-implement-dependent-or-chained-dropdown-list-with-django.html
It needs jQuery and I actually didn't fully understand what's happening in the jQuery part of the solution, but otherwise everything's clear and it works perfect!

django admin, displaying all instances of a model1 associated with model2 on model2's change page?

Consider these two models Keyword and Statement (model1 and model2 respectively):
#python_2_unicode_compatible
class Keyword(models.Model):
word = models.CharField(max_length=200)
statement = models.ManyToManyField(Statement)
def __str__(self):
return self.word
#python_2_unicode_compatible
class Statement(models.Model):
statement_id = models.CharField(max_length=200)
title = models.CharField(max_length=200)
issue_date = models.DateField("Issue-Date")
author = models.ForeignKey(Person)
released_by = models.ForeignKey(Organization)
kicpairs = models.ManyToManyField('KeywordInContext')
So on the admin site right now, the only way one would be able to determine what keywords are associated with each statement is that they have to go check the Keyword model in admin, and check each Keyword's display page and scroll through the menu.
At least with regards to the admin site, it's important for someone to be able to see a Statement model's display with all of its associated Keywords visible, and for users to be able to choose additional Keywords within the database (or make new ones). I also hope to be able to have a Statement's keywords modifiable on the admin page via the filter_horizontal widget, since that seems to be the most user friendly.
But I'm having trouble just starting with that. I'm not sure what I need to use or how.

How to create Create for ManyToMany relation with through?

I have models like:
class Playlist(models.Model):
key = models.CharField(max_length=255, blank=True, unique=True)
user = models.ForeignKey(User)
title = models.CharField(max_length=200)
pub_date = models.DateTimeField(auto_now_add=True)
videos = models.ManyToManyField(Video, through='PlaylistVideo')
class PlaylistVideo(models.Model):
playlist = models.ForeignKey(Playlist)
video = models.ForeignKey(Video)
position = models.IntegerField()
class Video(models.Model):
title = models.CharField(max_length=255,blank=True)
description = models.TextField(blank=True)
thumb = models.URLField(blank=True)
duration = models.IntegerField(default=0)
I want to write POST (create) for Playlist an API. Not sure how to handle videos field.
How to send values for videos field?
Django 1.8 and django-rest-framework
Thanks
From DRF documentation :
By default, relational fields that target a ManyToManyField with a through model specified are set to read-only.
So you most definitely CAN NOT create Video instances when creating a Playlist.
Now, considering you already have Video objects, and you want to create a Playlist which contains some of those videos, there are two ways to go about this.
You create your m2m relations at the same time as you create the Playlist :
class PlaylistSerializer(ModelSerializer):
videos = PrimaryKeyRelatedField(many=True)
class Meta:
model = Playlist
You only create the Playlist on POST, without any videos, and then you create another endpoint (e.g. playlist/<playlist_id>/videos/) where you add/remove the videos that you want.
Both have pros and cons, but my opinion is that you should first design you API, thinking also about how you will continue editing that Playlist.
Do you add videos one by one ? Do you add them in bulk ?
How do you remove a video ? Can that be done in bulk ?
Once you've got the right answer to those questions, implementation should be fairly simple.
Good luck!

Django Adding a ManyToManyField to ModelForm

Sorry that this is like the thousandth question for this issue but I still can't see a light at the end of the tunnel.
Lets say I have two models:
class Video(models.Model):
title = models.CharField(u"Titel",max_length=200)
slug = AutoSlugField(populate_from='title',unique=True)
date = models.DateField("Datum")
description = models.TextField(u"Beschreibung")
user = models.OneToOneField(User, blank=True, null=True)
class Channel(models.Model):
name = models.CharField(u"Name",max_length=30)
slug = AutoSlugField(populate_from='name',unique=True)
videos = models.ManyToManyField('videoportal.Video',related_name="contained_videos",blank=True,null=True)
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
As you see I want to have a channel with video(s) in it. So if I ad a video using a ModelForm like this
class VideoForm(ModelForm):
class Meta:
model = Video
the form I get will not contain a input field to select a channel (of course not). So how can I do this? How can I have a input field in my form to select one channel with a drop down?
Thanks,
Philip
If a video only belongs in one channel just give your Video model a ForeignKey to your Channel model. If it should belong to more than one channel I'd use a ManyToManyField in the Video model, as already suggested.
I think this would fit the idea of uploading videos and adding it to a channel far better than doing it the other way around.
Try putting the ManyToMany field in the Video model and omit it from the Channel model:
class Video(model.Model):
...
channels = model.ManyToManyField('videoportal.Channel', related_name='videos')
...
If you want a simple dropdown to select a single channel, why is it a many-to-many realationship between videos and channels?
Use a custom form instead of Django ModelForm.
probably something like this,
class VideoForm(forms.Form):
title = forms.CharField()
description = forms.TextField()
channel = forms.ModelChoiceField(queryset= Channel.objects.all(), empty_label=None)
do your validation in a view. Use Model save() method to save information contained in your POSTed form.

Categories