我一直在研究为Django Autocomplete Light提供的以下教程:
https://django-autocomplete-light.readthedocs.io/en/master/tutorial.html
我已经为表单中的一个字段成功实现了自动补全功能,但是我无法完成以下部分:
文档指出,我应该能够添加一项功能,该功能允许用户在无法使用所需选项的情况下在表单中创建新选项。但是,本教程在解释如何执行此操作时并不清楚。
我正在尝试实现一种表单,用户可以在其中通过以下方式创建新的反馈:
我已经部分实现了该功能,但是它似乎无法正常工作,就好像没有选择类别,“消息”下拉列表中会显示“类别”列表。但是,如果选择了类别,则会根据需要显示正确的消息。
models.py
class Feedback(models.Model):
feedback_id = models.IntegerField(primary_key=True,default=0)
pre_defined_message = models.ForeignKey('Message',on_delete=models.CASCADE,null=True,blank=True) # Selected from a pre defined list depending on selected category
points = models.IntegerField(default=0)
lecturer = models.ForeignKey('LecturerProfile', on_delete=models.CASCADE, null=True, blank=True)
student = models.ForeignKey('StudentProfile', on_delete=models.CASCADE, null=True, blank=True)
which_course = models.ForeignKey('Course', on_delete=models.CASCADE, null=True, blank=True)
datetime_given = models.DateTimeField(default=timezone.now, blank=False)
optional_message = models.CharField(max_length=200,default="")
category = models.ForeignKey('Category', on_delete=models.CASCADE, null=True, blank=True)
class Category(models.Model):
name = models.CharField(max_length=20, default="Empty",primary_key=True)
def __str__(self):
return self.name
class Message(models.Model):
category = models.ForeignKey('Category',on_delete=models.CASCADE,null=True,blank=True)
text = models.CharField(max_length=200,default="No message",primary_key=True)
def __str__(self):
return self.text
forms.py
class FeedbackForm(autocomplete.FutureModelForm):
optional_message = forms.CharField(max_length=200, required=False)
class Meta:
model = Feedback
fields = ('category', 'pre_defined_message','optional_message','points')
widgets = {
'pre_defined_message': autocomplete.ModelSelect2(url='category_autocomplete',forward=['category']),
'category': autocomplete.ModelSelect2(url='category_autocomplete')
}
help_texts = {
'pre_defined_message': "Select a Message",
'category': 'Category',
'optional_message': "Optional Message",
'points': "Points"
}
views.py
class CategoryAutocomplete(autocomplete.Select2QuerySetView):
def get_queryset(self):
if not self.request.user.is_authenticated or not self.request.user.is_lecturer:
return Category.objects.none()
query_set = Category.objects.all()
category = self.forwarded.get('category', None)
if self.q:
query_set = query_set.filter(name__istartswith=self.q)
return query_set
if category:
query_set = Message.objects.filter(category=category)
return query_set
urls.py
re_path(r'^category-autocomplete/$', CategoryAutocomplete.as_view(create_field='name'), name='category_autocomplete'),
我一直在寻找答案,但一直在努力寻找解决方案。
我也知道,特别是我的forms.py可能没有最有效/最干净的代码,并欢迎提出改进建议。我尝试定义 init 方法,但是无法成功完成此操作。
预先感谢
答案 0 :(得分:2)
在搜索完Django Autocomplete Light的所有开源文档之后:
https://github.com/yourlabs/django-autocomplete-light
我相信我已经找到了解决方案,并认为应该与提供的教程混淆的其他人共享它。
达到我上面的阶段(即自动完成工作)之后,您必须包括一个get_create_option方法,以使视图了解在检索create_field时该怎么做。
因此,在urls.py的urlpatterns列表中,确保存在以下行:
re_path(r'^category-autocomplete/$', CategoryAutocomplete.as_view(model=Category,create_field='name'), name='category_autocomplete')
(注意:必须将create_field变量设置为相关模型的主键。在我的情况下,类别模型的主键是名称 )
下一步是本教程中未明确说明的内容。在查看以下文件后:
https://github.com/yourlabs/django-autocomplete-light/blob/master/src/dal_select2/views.py
我找到了处理新选项创建的方法get_create_option。
def get_create_option(self, context, q):
"""Form the correct create_option to append to results."""
create_option = []
display_create_option = False
if self.create_field and q:
page_obj = context.get('page_obj', None)
if page_obj is None or page_obj.number == 1:
display_create_option = True
# Don't offer to create a new option if a
# case-insensitive) identical one already exists
existing_options = (self.get_result_label(result).lower()
for result in context['object_list'])
if q.lower() in existing_options:
display_create_option = False
if display_create_option and self.has_add_permission(self.request):
create_option = [{
'id': q,
'text': _('Create "%(new_value)s"') % {'new_value': q},
'create_id': True,
}]
return create_option
在我的views.py的CategoryAutocomplete类中包含此方法后,终于可以在搜索中创建新类别了!
我现在很难用先前选择的类别作为外键来创建Message对象,因为该文档也没有得到很好的记录。如果找到解决方案,我将更新此答案。
希望这对某人有帮助!
更新
尽管有点麻烦,但我设法设置了消息模型的外键。我只是访问创建的Message并在表单验证本身中设置其category字段:
if request.method == 'POST':
form = FeedbackForm(request.POST)
if form.is_valid():
new_fb = form.save(commit=False)
# When a new message is made, the category it is associated with is not saved
# To fix this, set the category field within this form and save the message object.
new_fb.pre_defined_message.category = Category.objects.get(name=new_fb.category)
new_fb.pre_defined_message.save()
答案 1 :(得分:1)
也许问题在于用户没有add permission的get_create_option checks吗?
如果将其添加到视图中,是否可行?
def has_add_permission(self, request):
return True
答案 2 :(得分:0)
我有一个模特
class sites(models.Model): #Site Owner for standard sites will be system_1
site = models.CharField(max_length=100)
site_owner = models.ForeignKey(User, on_delete=models.CASCADE, blank = True, null=True)
def __str__(self):
return self.site
我希望用户能够通过自动完成功能添加新网站,并且还可以记录哪个用户创建了网站
dal \ views.py中的-类BaseQuerySetView(ViewMixin,BaseListView): 有以下
def create_object(self, text):
"""Create an object given a text."""
return self.get_queryset().get_or_create(
**{self.create_field: text,})[0]
所以我用
在我的自动完成课程中覆盖了这一点def create_object(self, text):
"""Create an object given a text."""
return self.get_queryset().get_or_create(site_owner=self.request.user,
site=text)[0]
如果需要,可以将其进一步扩展为更新模型中的多行,并且在您的情况下,您应该能够将先前选择的类别传递到此定义中。