【问题标题】:Adding to manytomany field, on added field from form在表单中添加的字段上添加到 manytomany 字段
【发布时间】:2020-07-25 16:19:03
【问题描述】:

我有一个模型,需要一个用户(ForeignKey)和一个类别(M2M),对于表单中的类别字段,我通过向其添加自定义字段来扩展其功能(数据列表但也有输入) ,但我无法使用类别和用户保存表单。

models.py

from django.contrib.auth.models import AbstractUser
from django.db import models


class User(AbstractUser):
    pass

class Category(models.Model):
    name = models.CharField(max_length=20, blank=True)

class Listings(models.Model):
    title = models.CharField(max_length=64, null=False, blank=False)
    description = models.CharField(max_length=64, blank=True)
    bid = models.IntegerField(null=False, blank=False)
    timestamp = models.DateField(db_index=True, auto_now_add=True)
    image_url = models.URLField(blank=True)
    category = models.ManyToManyField(Category)
    owner = models.ForeignKey(User, on_delete=models.CASCADE)

    class Meta:
        ordering=['timestamp', 'title']

forms.py

from auctions.models import Listings
from django import forms

class ListTextWidget(forms.TextInput):
    def __init__(self, data_list, name, *args, **kwargs):
        super(ListTextWidget,self).__init__(*args, **kwargs)
        self._name = name
        self._list = data_list
        self.attrs.update({
            'list':'list__%s' % self._name,
            'class':'form-control'
            })
    
    def render(self, name, value, attrs=None, renderer=None):
        text_html = super(ListTextWidget, self).render(name, value, attrs=attrs)
        data_list = '<datalist id="list__%s">' % self._name
        for item in self._list:
            data_list += '<option value="%s">' % item
        data_list += '</datalist>'

        return (text_html + data_list)


class ListingsForm(forms.ModelForm):
    category = forms.CharField()

    class Meta:
        model = Listings
        fields = ['title', 'description', 'bid', 'image_url', 'category']
        widgets = {
            'title': forms.TextInput(attrs={'class':'form-control'}),
            'description': forms.TextInput(attrs={'class':'form-control'}),
            'bid': forms.TextInput(attrs={'class':'form-control'}),
            'image_url': forms.TextInput(attrs={'class':'form-control'}),
            'category': forms.TextInput(attrs={'class':'form-control'})
        }
    def __init__(self, *args, **kwargs):
        _category_list = kwargs.pop('data_list', None)
        super(ListingsForm, self).__init__(*args, **kwargs)
    
        self.fields['category'].widget = ListTextWidget(data_list=_category_list, name='category-list')

views.py

def create_listings(request):
    if request.method == "POST":
        form = ListingsForm(request.POST)
        if form.is_valid():
            #**what to do to save category and user**
            return redirect(reverse('index'))
    else:
        category_list = Category.objects.all().values_list('name')
        form = ListingsForm(data_list=category_list)   
    return render(request, 'auctions/create_listings.html', {
        'form': form
    })

如何在 form.save() 期间将所有数据保存到新的列表中?

我尝试过使用 commit=False,但我得到了ValueError:Field 'id' expected a number but got 'o'. 有没有办法一次保存,还是必须创建一个列表,然后手动添加剩余的数据?

【问题讨论】:

    标签: python django django-models django-forms


    【解决方案1】:

    您可以尝试以下方法,将M2M字段更改为外键,然后在表单中没有太多更改,只需删除类别,最后在视图中保存后添加用户(提交=假) models.py

    from django.contrib.auth.models import AbstractUser
    from django.db import models
    
    
    class User(AbstractUser):
        pass
    
    class Category(models.Model):
        name = models.CharField(max_length=20, blank=True)
        
        
        def __str__(self) -> str:
            return self.name
    
    class Listings(models.Model):
        title = models.CharField(max_length=64, null=False, blank=False)
        description = models.CharField(max_length=64, blank=True)
        bid = models.IntegerField(null=False, blank=False)
        timestamp = models.DateField(db_index=True, auto_now_add=True)
        image_url = models.TextField(blank=True)
        category = models.ForeignKey(Category, null=True, blank=True, on_delete=models.SET_NULL)
        owner = models.ForeignKey(User, verbose_name="owner", on_delete=models.CASCADE, related_name='owner')
    
        class Meta:
            ordering=['-timestamp', 'title']
        
        def __str__(self) -> str:
            return self.title
    

    forms.py

    from auctions.models import Biddings, Comments, Listings
    from django import forms
    
    class ListTextWidget(forms.TextInput):
        def __init__(self, data_list, name, *args, **kwargs):
            super(ListTextWidget,self).__init__(*args, **kwargs)
            self._name = name
            self._list = data_list
            self.attrs.update({
                'list':'list__%s' % self._name,
                'class':'form-control'
                })
        
        def render(self, name, value, attrs=None, renderer=None):
            text_html = super(ListTextWidget, self).render(name, value, attrs=attrs)
            data_list = '<datalist id="list__%s">' % self._name
            for item in self._list:
                data_list += '<option value="%s">' % item
            data_list += '</datalist>'
    
            return (text_html + data_list)
    
    
    class ListingsForm(forms.ModelForm):
        category = forms.CharField()
    
        class Meta:
            model = Listings
            fields = ['title', 'description', 'bid', 'image_url']
            widgets = {
                'title': forms.TextInput(attrs={'class':'form-control'}),
                'description': forms.TextInput(attrs={'class':'form-control'}),
                'bid': forms.TextInput(attrs={'class':'form-control'}),
                'image_url': forms.TextInput(attrs={'class':'form-control'}),
                'category': forms.TextInput(attrs={'class':'form-control'})
            }
        def __init__(self, *args, **kwargs):
            _category_list = kwargs.pop('data_list', None)
            super(ListingsForm, self).__init__(*args, **kwargs)
        
            self.fields['category'].widget = ListTextWidget(data_list=_category_list, name='category-list')
    
    

    views.py 在这里,我手动渲染了字段以进行澄清

    def create_listings(request):
        if request.method == "POST":
            form = ListingsForm(request.POST)
            if form.is_valid():
                title = form.cleaned_data["title"]
                description = form.cleaned_data["description"]
                bid = form.cleaned_data["bid"]
                image_url = form.cleaned_data["image_url"]
                category, created = Category.objects.get_or_create(name = form.cleaned_data["category"])
                owner = request.user
                listing = Listings(
                    title=title,
                    description=description,
                    bid=bid,
                    image_url=image_url,
                    owner=owner,  
                    category=Category.objects.get(name = form.cleaned_data["category"])             
                    )
                listing.save()
                messages.success(request, "Listing created succesfully")
                return redirect(reverse('index'))
        else:
            category_list = Category.objects.all().values_list('name')
            form = ListingsForm(data_list=category_list)   
        return render(request, 'auctions/create_listings.html', {
            'form': form
        })
    
    

    我真的希望这有助于解决您的问题 :)。干杯

    【讨论】:

    • 有点晚了,但我以类似的方式解决了。我真正需要做的就是get_or_create 类别
    猜你喜欢
    • 1970-01-01
    • 2019-02-15
    • 1970-01-01
    • 1970-01-01
    • 2011-09-02
    • 2019-06-01
    • 2012-02-04
    • 1970-01-01
    • 2011-10-05
    相关资源
    最近更新 更多