django-autocomplete-light icon indicating copy to clipboard operation
django-autocomplete-light copied to clipboard

Create new item with foreign key

Open Ashwin-MJ opened this issue 6 years ago • 7 comments

I am trying to create a form in which a user first selects a Category, and then selects from a list of Messages which change depending on the Category selected.

I have managed to implement autocomplete for my first field Category, so the user can type in a Category and if it does not exist they are able to create a new one.

Next, I have been able to change the Messages displayed depending on the Category selected using 'forward'. However, I also want to allow the user to create a new Message in this second field. So far I have managed to allow the user to create the new Message, but the chosen Category is not saved in the new object. So only the text passed to the create_field is saved and I am therefore unable to retrieve the Category associated with that new Message.

My Message model only has two fields - the text, and a foreign key to Category model.

Is it possible to create a foreign key as I am trying to do? If not, could you suggest any alternative methods to achieve my target.

Here's a link to a previous question I asked on Stack Overflow which has some of my code:

https://stackoverflow.com/questions/53353161/django-autocomplete-light-create-new-choice/53361751#53361751

Appreciate any help!

Ashwin-MJ avatar Nov 18 '18 17:11 Ashwin-MJ

Did you try using firefox debugger where it is supposed to forward the data to the create option ?

Is yl.getForwards($(this)) empty ?

Also maybe try a breakpoint here and see what happens ?

Maybe also check the POST request with firefox debugger it might have a clue.

jpic avatar Nov 18 '18 21:11 jpic

Will give that a try and get back to you thanks!

So should DAL allow me to do what I'm trying to do?

Ashwin-MJ avatar Nov 18 '18 21:11 Ashwin-MJ

It seems so, maybe @gagarski can share some thoughts too

In my experience, it's always less work to use parts of DAL to achieve an autocomplete than to do it from scratch, there are so many things that make an autocomplete feature complete ... you can even override the js to initialize your widget and hack the create code.

If it's not working, you're welcome to make a pull request because I think it makes sense to forward fields by default to the create option as well, to set relations, you're probably not the first one to try.

jpic avatar Nov 18 '18 21:11 jpic

I have managed to develop a workaround by setting the foreign key of my Message model after I have validated the form. Feels like a bit of a hack but it works I guess!

I'm still quite new with Django and web development altogether, so as much as I would love to be able to try and implement this I'm not sure how successful I would be. If I get some free time I will definitely try and a have a look into it.

Thanks again for your help!

Ashwin-MJ avatar Nov 18 '18 22:11 Ashwin-MJ

Sure, go ahead and try to modify DAL and remove the hack you have in favor of a refactor, I will try to merge your pull request.

Have fun !

jpic avatar Nov 18 '18 23:11 jpic

Hello, I'm facing same issue. Using the "Create new" link on Select2, to create an object having an foreignkey to another model

I sort of solve it as follow, but I'm still looking for advice

Looking at Classy Class-Based Views website, under GENERIC EDIT CreateView, found method post

So I added def post to the Class view. This overrides the post method when "Create new" link is cliked

class CountryAutocomplete(autocomplete.Select2QuerySetView): def get_queryset(self):

# Don't forget to filter out results depending on the visitor !
if not self.request.user.is_authenticated():
  return Documento.objects.none()

qs = Documento.objects.all()

cliente = self.forwarded.get('cliente', None)

if cliente:
  qs = qs.filter(cliente=cliente)

if self.q:
  qs = qs.filter(codigo__istartswith=self.q)

return qs

def post(self, request): if request.user.is_authenticated(): texto = request.POST.get('text') forward = request.POST.get('forward') data = json.loads(forward)

  cliente = Cliente.objects.get(pk=data['cliente'])
  d = Documento(cliente=cliente,codigo=texto)
  d.save()
  return reverse('country-autocomplete')

This works creating the new object with correct reference to the foreignkey

But I need now to redirect from "def post" to somewhere, I guess the same

class CountryAutocomplete(autocomplete.Select2QuerySetView): def get_queryset(self):

Also I would like to get some error notice when I pick "Create new" without having selected some of the foreignkey field options

Please any advice is welcome, thanks

gusantor avatar Dec 27 '19 17:12 gusantor

@gusantor and anyone wondering about this, you don't have to override the post method, just the create_object method. so in you example, in the view that extends Select2QuerySetView you would do

def create_object(self, text):
        cliente_pk = self.forwarded.get('cliente', None)
        cliente = Cliente.objects.get(pk=cliente_pk)
        return Documento.objects.create(cliente=cliente, codigo=text)

eroncanc avatar May 02 '20 16:05 eroncanc