django many-to-many relation not saved - django

here's my model:
class MediumCategory(models.Model):
name = models.CharField(max_length=100, verbose_name=u"Nazwa")
slug = models.SlugField(blank=True)
parent = models.ForeignKey('self', blank=True, null=True, verbose_name=u"Rodzic")
parameters = models.ManyToManyField(AdvertisementDescriptonParameter, blank=True)
count_mediums = models.PositiveIntegerField(default=0)
count_ads = models.PositiveIntegerField(default=0)
descendants = models.ManyToManyField('self', blank=True, null=True)
def save(self, *args, **kwargs):
self.slug = slugify("%s_%s" % (self.id, self.name))
super(MediumCategory, self).save(*args, **kwargs)
def __unicode__(self):
return unicode(self.name)
here's my admin:
class MediumCategoryAdmin(admin.ModelAdmin):
list_display = ['name', 'parent', 'count_mediums', 'count_ads']
def save_model(self, request, obj, form, change):
admin.ModelAdmin.save_model(self, request, obj, form, change)
update_category_descendants()
and here's the function:
def update_category_descendants(sender=None, **kwargs):
data = dict()
def children_for(category):
return MediumCategory.objects.filter(parent=category)
def do_update_descendants(category):
children = children_for(category)
descendants = list() + list(children)
l = list([do_update_descendants(child) for child in children])
for descendants_part in l:
descendants += descendants_part
if category:
data[category] = []
for descendant in descendants:
data[category].append(descendant)
return list(descendants)
# call it for update
do_update_descendants(None)
for k, v in data.iteritems():
k.descendants = v
print k, k.descendants.all()
what update_category_descendants does, is taking all descendands of node in the tree and saves it into descendants list of this node. Useful for browsing categorized products in store.
While print k, k.descendants.all() works as expected, in fact data is not saved in db.
when I do:
def category(request, category_slug, page=None):
cats = MediumCategory.objects.all()
category = MediumCategory.objects.get(slug=category_slug)
descendants = category.descendants.all()
print "category, descendants", category, descendants
descendants variable is always [].
What am I missing here?

In your final loop in the update_category_descendants function, I believe you need to make it:
for k, v in data.iteritems():
k.descendants.add(*v)
See also Django's related objects reference.

Related

pass data from models.py to views.py and show it to user

I want to give users ten point each time they fill out one Survey , so i have this code above and now how to add the 10 point to self user after he fill out one
models.py :
class User(AbstractUser):
user_pic = models.ImageField(upload_to='img/',default="",null=True, blank=True)
coins = models.IntegerField(default=10)
def get_image(self):
if self.user_pic and hasattr(self.user_pic, 'url'):
return self.user_pic.url
else:
return '/path/to/default/image'
def give_coins(user, count):
user.coins = F('coins') + count
user.save(update_fields=('coins',))
user.refresh_from_db(fields=('coins',))
class Survey(models.Model):
name = models.CharField(max_length=200)
published_on = models.DateTimeField('Published DateTime')
def __str__(self):
return self.name
def was_published_recently(self):
now = timezone.now()
return now - datetime.timedelta(days=1) <= self.published_on <= now
was_published_recently.admin_order_field = 'published_on'
was_published_recently.boolean = True
was_published_recently.short_description = 'Published recently?'
class Participant(models.Model):
survey = models.ForeignKey(Survey, on_delete=models.CASCADE)
participation_datetime = models.DateTimeField('Participation DateTime')
def __str__(self):
return "Participant "+str(self.participation_datetime)
class Question(models.Model):
survey = models.ForeignKey(Survey, on_delete=models.CASCADE)
question_text = models.CharField(max_length=200)
created_on = models.DateTimeField('Creation DateTime')
def __str__(self):
return self.question_text
views.py :
#register.inclusion_tag('survey/survey_details.html', takes_context=True)
def survey_details(context, survey_id):
survey = Survey.objects.get(id=survey_id)
return {'survey': survey}
#require_http_methods(["POST"])
def submit_survey(request):
form_data = request.POST.copy()
form_items = list(form_data.items())
print("form_items", form_items)
form_items.pop(0) # the first element is the csrf token. Therefore omit it.
survey = None
for item in form_items:
# Here in 'choice/3', '3' is '<choice_id>'.
choice_str, choice_id = item
choice_id = int(choice_id.split('/')[1])
choice = Choice.objects.get(id=choice_id)
if survey is None:
survey = choice.question.survey
choice.votes = choice.votes + 1
choice.save()
if survey is not None:
participant = Participant(survey=survey, participation_datetime=timezone.now())
participant.save()
return redirect('/submit_success/')
so what i must to do if i want to add 10 point to user after he complete one survey
If submit_survey is a call that requires authentication the user will be present on the request request.user.
Add the coins by adding request.user.give_coins(count=10) to the submit_query method.
you have 2 way
work with event driven tools(maybe hard but principled)
set give_coin befor participant.save() on submit_survey
anyway I din't notice, coin is on your absUser model but your Participant has nothing to do with it or relations

Django CustomUser Function

I created a CustomUser as follows, however, I am not able to use the CustomUser functions in Views as I get the error message "get_first_name() missing 1 required positional argument: 'self'" when I call CustomUser.get_first_name().
I checked my settings.py and do import CustomUser, models as well as settings in the view file.
If you could help me here that would be awesome.
models.py
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(verbose_name='email', unique=True)
first_name = models.CharField(verbose_name='first_name', max_length = 15)
last_name = models.CharField(verbose_name='last_name', max_length = 15)
organization = models.CharField(verbose_name="organization", max_length = 15, choices=ORGANIZATIONS)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True) # check this for login email purposes
date_joined = models.DateTimeField(default=timezone.now)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name', 'last_name', 'organization']
objects = CustomUserManager()
def get_full_name(self):
'''
Returns the first_name plus the last_name, with a space in between.
'''
full_name = '%s %s' % (self.first_name, self.last_name)
return full_name.strip()
def get_short_name(self):
'''
Returns the short name for the user.
'''
return self.first_name
def __str__(self):
return self.email
def get_organization(self):
return self.organization
def get_first_name(self):
return self.first_name
def get_email(self):
return self.email
views.py
class Dashboard(LoginRequiredMixin, TemplateView):
template_name = "plot.html"
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super(Dashboard, self).get_context_data(**kwargs)
context['plot'] = plots.plotsurvey()
return context
plots.py
def plotsurvey():
c = CustomUser()
name = c.get_first_name()
df = pd.read_csv(str(name) +'.csv') #
trace = go.Bar(
x = df['Y'],
y = df['Z'], name = 'N'
)
data = [trace]
layout = go.Layout(title="X", margin = dict(b = 150))
fig = go.Figure(data=data, layout=layout)
plot_div = plot(fig, output_type='div', include_plotlyjs=False)
#logger.info("Plotting number of points {}.".format(3))
return plot_div
You are using an instance method, as if it were a class method.
You need to change, this
def plotsurvey():
c = CustomUser()
name = CustomUser.get_first_name()
...
To this (use the instance)
def plotsurvey():
c = CustomUser()
name = c.get_first_name()
...
Note that you have another problem here. You are not actually getting any real user with c = CustomUser(). To get a user, you would need to do something like
CustomUser.objects.get(pk=user_id)
In that case, you finally get:
def plotsurvey(user_id):
c = CustomUser.objects.get(pk=user_id)
name = c.get_first_name()
...
EDIT
We can be more practical, using the view.
class Dashboard(LoginRequiredMixin, TemplateView):
template_name = "plot.html"
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super(Dashboard, self).get_context_data(**kwargs)
user = self.request.user
context['plot'] = plots.plotsurvey(user.pk)
return context
You can use request object
request.user.get_first_name()

Use sessions to count pageviews django detailview

I am trying to count the visits to a view. I would like for the counter to increment by 1 every time someone calls up the view. Then, I want the "visits" field on the model to automatically update with the latest count. However, I am not sure how to implement this. Using some code I've found, I am trying this:
models.py
class Statute(models.Model):
address = models.ForeignKey(Address,
null = True)
statute_name = models.CharField(max_length=25,
default='')
category = models.CharField(max_length=55,
default='')
section_number = models.CharField(max_length=55,
default='')
section_title = models.CharField(max_length=255,
default='')
timestamp = models.DateTimeField(editable=False)
visits = models.IntegerField(default=0)
content = models.TextField(default='')
slug = models.SlugField()
views.py
def get_context_data(self, **kwargs):
context = super(LibraryInStateView, self).get_context_data(**kwargs)
state = State.objects.get(slug=self.kwargs.get('state'))
statute = Statute.objects.all()
context['latest_statutes'] = statute.filter(
address__zipcode__city__county__state=state).order_by(
'-timestamp')
context['statute_count'] = Statute.objects.filter(
address__zipcode__city__county__state=state).count()
context['view_count'] = self.request.session['visits']+1
return context
You can include it in .get_object() method in LibraryInStateView
def get_object(self):
statute = super().get_object()
statute.visits += 1
statute.save()
self.view_count = statute.visits
return statute
Or get method:
def get(self, request, *args, **kwargs):
statute = # ... code to retrieve Statute for this view
statute.visits += 1
statute.save()
self.view_count = statute.visits
return super().get(request, *args, **kwargs)
Then once you attached view_count to class instance, you can add it to context:
def get_context_data(self, **kwargs):
...
context['view_count'] = self.view_count
return context
In your view update:
statute = Statute.objects.filter(address__zipcode__city__county__state=state)
statute.visits += 1
statute.save()
context['statute_count'] = statute

not enough values to unpack (expected 2, got 1)

I have a problem with a queryset in one view. My idea is show all users who are not registered in a program, I put here the models:
models.py
class UCAUser(AbstractUser):
dni_cif=models.CharField(
max_length=9,
blank=True,
verbose_name="DNI/CIF"
)
class InscripcionRealizada(models.Model):
formulario = models.ForeignKey(Formulario)
inscrito = models.ForeignKey(UCAUser,related_name="inscripciones_realizadas")
fecha_registro = models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name = "Inscripción realizada"
verbose_name_plural = "Inscripciones realizadas"
def __str__(self):
return "{} - {} - {}".format(self.formulario.programa, self.formulario.edicion, self.inscrito)
You can see UCAUser and InscripcionRealizada are connected by InscripcionRealizada.inscrito field.
view.py
class InscribirUsuariosListView(ListView):
template_name = "inscripciones/InscribirUsuariolist.html"
model = UCAUser
group_required = ['Administrador']
login_url = "auth-login"
def get_queryset(self):
qs = super(InscribirUsuariosListView, self).get_queryset()
return qs.filter(UCAUser.objects.filter(inscripciones_realizadas__formulario!=self.kwargs['formulario_id']))
def get_context_data(self, **kwargs):
context = super(InscribirUsuariosListView, self).get_context_data(**kwargs)
context['formulario_id'] = self.kwargs['formulario_id']
return context
When I try this, I get an error:
not enough values to unpack (expected 2, got 1)
Any idea?

form.is_valid method keeps failing

I'm trying to make an editing page for the users to update an object data. However, form.is_valid() keeps failing, I have no idea why.
My model:
class Thread(models.Model):
title = models.CharField(max_length=200)
created = models.DateTimeField(auto_now_add=True)
creator = models.ForeignKey(User, blank=True, null=True)
body = models.TextField(max_length=10000)
USER_TYPES = (
('INI','Iniciante'),
('INT','Intermediário'),
('AVA','Avançado')
)
user_type = models.CharField(max_length=20, choices = USER_TYPES, default='INI')
category = models.ForeignKey(Category)
orcamento = models.IntegerField(default=0)
slug = models.SlugField(max_length=40, unique=True)
def get_absolute_url(self):
return "/%s/" % self.slug
def __str__(self):
return self.title
def save(self, **kwargs):
slug_str = "%s %s" % (self.category, self.title)
unique_slugify(self, slug_str)
super(Thread, self).save(**kwargs)
My view:
def edit_thread(request, thread_slug):
thread = Thread.objects.get(slug=thread_slug)
if request.method == 'POST':
form = EditThread(request.POST)
if form.is_valid():
thread.title = form.cleaned_data['title']
thread.orcamento = form.cleaned_data['orcamento']
thread.user_type = form.cleaned_data['experiencia']
thread.body = form.cleaned_data['pergunta']
thread.save()
return HttpResponseRedirect('/thread' + thread.get_absolute_url())
else:
data = {'title' : thread.title, 'experiencia':thread.user_type, 'orcamento' : thread.orcamento, 'pergunta': thread.body}
form = EditThread(initial=data)
return render(request, 'edit_thread.html', {
'form': form })
My form:
class EditThread(forms.ModelForm):
title = forms.CharField(label='Título', max_length=200, error_messages=my_default_errors)
orcamento = forms.IntegerField(label='Preço máximo', error_messages=my_default_errors)
experiencia = forms.ChoiceField(label='Você é um usuário...', choices=Thread.USER_TYPES, error_messages=my_default_errors)
pergunta = forms.CharField(label='Pergunta', widget=forms.Textarea, error_messages=my_default_errors)
class Meta:
model = Thread
def __init__(self, *args, **kwargs):
super(EditThread, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.layout = Layout(
Div('title',
'experiencia',
PrependedAppendedText('orcamento', 'R$', ',00', active=True),
'pergunta',
FormActions(
Submit('save', 'Salvar alterações'),
)))
When accessing the page, the form gets pre-populated with the object's data as it should.
Your form should be inherited from the simple forms.Form instead of the forms.ModelForm:
class EditThread(forms.Form):
...
I would suggest you look at django's class based UpdateView. It can generate an update form for you or you could give it a custom ModelForm by overriding the form_class attribute on your view. When using a ModelForm, you also have to specify which model the form is for eg:
class EditThread(forms.ModelForm):
"field definitions ..."
class Meta:
model = Thread
fields = ['my_field_1', 'my_field_2']